/* The scroll landing: a pinned cephalogram, beats scrolling over it.
 *
 * The mechanism is three rules and nothing else: the stage is sticky and one
 * viewport tall, the beats are pulled up over it by exactly that height, and
 * each beat is a viewport tall so one scroll gesture advances one step. No
 * scroll listener positions anything -- the browser does the pinning, and JS
 * only ever says which beat is current.
 *
 * Colours are tokens.css. The ground is --oa-stage, the same dark the
 * workspace views radiographs on: a bright surround constricts the pupil and
 * washes out the bone edges somebody is trying to read.
 */

/* The measure highlight, taken from the app rather than invented.
   canvas-draw.js paints a hovered measure's plane and its landmarks in
   #ff00ff, so that is what a highlighted measurement looks like in this
   product -- and it is far more visible on a radiograph than the brand
   indigo, which was the complaint. Indigo stays the page's accent; magenta
   means "this is the measurement being pointed at", here and in the app. */
:root {
  --oa-measure-hot: #ff00ff;
  --oa-measure-hot-soft: rgba(255, 0, 255, 0.22);
}


/* --- the two themes ------------------------------------------------------ */

/* Every colour on this page resolves through one of these, which is what
   makes the night/light switch a class on <body> rather than a second
   stylesheet. Light is the default set; .page-dark redefines the same names.
   Nothing below this block names a literal colour, so neither theme can
   gain a rule the other quietly lacks. */

.reel,
.after,
.packs,
.reel-faq {
  --ld-ground: var(--oa-surface);
  --ld-ground-deep: var(--oa-surface-sunken);
  --ld-ink-strong: var(--oa-ink);
  --ld-ink: var(--oa-ink-soft);
  --ld-muted: var(--oa-muted);
  --ld-faint: var(--oa-faint);
  --ld-card: var(--oa-surface);
  --ld-card-deep: var(--oa-surface);
  --ld-line: var(--oa-line);
  --ld-border: var(--oa-line);
  --ld-border-strong: var(--oa-accent-border);
  --ld-accent-ink: var(--oa-accent);
  /* The radiograph is dark in both themes -- it is a photograph, not a
     surface -- so the label halo and the landmark fill stay dark always. */
  --ld-halo: rgba(10, 13, 18, 0.85);
  --ld-pt-fill: rgba(10, 13, 18, 0.55);
}

.page-dark .reel,
.page-dark .after,
.page-dark .packs,
.page-dark .reel-faq {
  --ld-ground: var(--oa-stage);
  --ld-ground-deep: #0b0e13;
  --ld-ink-strong: #f3f5f9;
  --ld-ink: #e8ecf3;
  --ld-muted: #9aa4b5;
  --ld-faint: #7b8698;
  --ld-card: #161a23;
  --ld-card-deep: #10141c;
  --ld-line: #222836;
  --ld-border: #2b3240;
  --ld-border-strong: #3d4658;
  --ld-accent-ink: #a9a3ff;
}

.reel {
  position: relative;
  background: var(--ld-ground);
  color: var(--ld-ink);
  /* The header is fixed, so the stage pins BELOW it and is only as tall as
     what is left. Pinned to 0 it sat under the header and the copy scrolled
     beneath it. */
  --reel-header: 74px;
  /* Breathing room under the fixed header, and the line the copy aligns to. */
  --reel-gap: 3.2vh;
}

/* index.css puts `overflow-x: hidden` on <body>, which makes the body a
   scroll container -- and a sticky element inside a scroll container sticks
   to THAT, not the viewport, so the radiograph stopped pinning the moment
   this page started loading index.css for its ported components.
   `clip` clips exactly the same overflow without creating the container. */
body:has(.reel) {
  overflow-x: clip;
  overflow-y: visible;
}

/* --- the pinned stage ---------------------------------------------------- */

.reel__stage {
  position: sticky;
  top: var(--reel-header);
  height: calc(100vh - var(--reel-header));
  height: calc(100svh - var(--reel-header));
  /* A real two-column grid. This was a centred flex box with a large
     margin-inline-start pushing the frame rightwards, which on any viewport
     narrower than the guess ran the radiograph off the right edge -- the
     image was cropped mid-face at 1440px. The grid gives the copy one column
     and the radiograph the other, and neither can overflow the other. */
  display: grid;
  /* The copy column is the narrower of the two: it is capped at a reading
     measure anyway, and an even split left a corridor of empty page between
     the sentence and the radiograph it describes. */
  /* The radiograph is portrait (1855:2130), so in a half-width column it can
     never fill the width and the remainder reads as dead space. The second
     column is sized close to what the image actually occupies and the copy
     takes the rest. */
  /* 1440px of stage has to hold ~620px of reading measure and a ~410px
     portrait image. Something has to give; the question is only where. A
     wide second column put it all to the right of the radiograph; a narrow
     one puts it all in the gutter. Splitting it -- a column sized close to
     the image, with the remainder shared -- is the least visible place for
     it to go. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 440px);
  /* Two rows in the second column: the radiograph, then the readout beneath
     it. align-content centres the pair as a block rather than centring each
     row in half the stage. */
  grid-template-rows: auto auto;
  /* Top-aligned, not centred. Centring made the frame's top depend on how
     tall the readout happened to be, so there was no fixed line for the copy
     to be aligned WITH -- and it left the radiograph flush against the
     header. --reel-gap is that line, and the sticky cards use the same
     value, so the two cannot drift apart. */
  align-content: start;
  padding-block-start: var(--reel-gap);
  justify-items: start;
  overflow: hidden;
  /* The content is ~500px of reading measure plus a ~410px portrait image.
     On a 1440px screen that leaves about 530px of slack, and letting the
     grid absorb it put the lot in the gutter between the sentence and the
     radiograph. Capping the pair and centring it puts the slack in the outer
     margins, where nobody reads it as a gap. */
  padding-inline: max(clamp(20px, 5vw, 64px), calc((100% - 1120px) / 2));
  /* The stage runs from under the header to the bottom of the screen, so its
     centre sits half a header-height BELOW the viewport's -- and the beats
     are centred on the viewport (the observer's -50%/-50% band). Centred
     content in each therefore disagreed by ~37px, which is exactly the
     offset that made the image look unaligned with the copy. Reserving the
     same height at the bottom puts both centres in the same place. */
}

.reel__frame {
  position: relative;
  grid-column: 2;
  grid-row: 1;
  /* Centred now that the column is close to the image's own width: any
     remainder splits evenly instead of piling up on one side. */
  justify-self: center;
  /* An absolute height, not a percentage: the grid row is auto-sized now that
     the readout sits beneath, so a percentage resolved against the frame's
     own content and collapsed it to a couple of hundred pixels. */
  height: 52vh;
  max-width: 100%;
  aspect-ratio: 1855 / 2130;
}

.reel__svg {
  display: block;
  width: 100%;
  height: 100%;
  filter: contrast(1.05) brightness(0.92);
}

/* --- the camera ---------------------------------------------------------- */

/* The radiograph and its marks move as one group, so each beat can push in on
   the region it is talking about instead of the reader hunting for it on a
   full-size skull. Three variables drive it, set per beat below:
   --cam-x/--cam-y are where to put the centre of the frame, in the image's
   own coordinates, and --cam-s is how far to push in.
 *
 * The maths: to bring a point (x, y) to the centre of an 1855x2130 viewBox at
 * scale s, translate by (927.5 - s*x, 1065 - s*y). transform-origin is 0 0 so
 * the two compose predictably; with any other origin the scale would move the
 * point again after the translate had placed it.
 */
.reel__cam {
  --cam-x: 927.5;
  --cam-y: 1065;
  --cam-s: 1;
  transform-origin: 0 0;
  transform:
    translate(
      calc(927.5px - var(--cam-s) * var(--cam-x) * 1px),
      calc(1065px - var(--cam-s) * var(--cam-y) * 1px)
    )
    scale(var(--cam-s));
  /* Slow and eased: a fast camera move on a medical image reads as a glitch.
     The cubic settles rather than bouncing -- anatomy should not spring. */
  transition: transform 1.15s cubic-bezier(0.22, 0.61, 0.24, 1);
}

/* The push-ins, one per landmark group. Each centre is the point that beat
   adds -- or, for the cranial base, the midpoint of the S-N line. */
.reel__stage[data-focus="1"] .reel__cam { --cam-x: 722;  --cam-y: 678;  --cam-s: 1.85; }
.reel__stage[data-focus="2"] .reel__cam { --cam-x: 1100; --cam-y: 1120; --cam-s: 1.95; }
.reel__stage[data-focus="3"] .reel__cam { --cam-x: 1105; --cam-y: 1430; --cam-s: 1.85; }
/* Pulled back for the planes and the measurements: S-N-A-B spans most of the
   face, so the last beat is the one that needs the wide shot again. */
.reel__stage[data-focus="4"] .reel__cam { --cam-x: 927.5; --cam-y: 1065; --cam-s: 1; }

/* A slight tilt, so pushing in reads as moving a camera through space rather
   than as a flat zoom. Kept small -- past about 6 degrees the radiograph
   starts to look distorted, which on an anatomical image is the wrong kind of
   interesting. */
.reel__frame {
  perspective: 1400px;
  transform-style: preserve-3d;
}

.reel__svg {
  transition: transform 1.15s cubic-bezier(0.22, 0.61, 0.24, 1);
  will-change: transform;
}

.reel__stage[data-focus="1"] .reel__svg { transform: rotateY(3.5deg) rotateX(-1.5deg); }
.reel__stage[data-focus="2"] .reel__svg { transform: rotateY(-3deg) rotateX(1.5deg); }
.reel__stage[data-focus="3"] .reel__svg { transform: rotateY(-3.5deg) rotateX(-2deg); }
.reel__stage[data-focus="4"] .reel__svg { transform: none; }

/* Labels and markers are drawn in image coordinates, so pushing in scales
   them too and they would swell to twice their size. Counter-scaling keeps
   them the size the reader has already learned to read. */
.lm-label { transition: font-size 1.15s cubic-bezier(0.22, 0.61, 0.24, 1); }

.reel__stage[data-focus="1"] .lm-label,
.reel__stage[data-focus="2"] .lm-label,
.reel__stage[data-focus="3"] .lm-label { font-size: 34px; }

.reel__stage[data-focus="1"] .lm-pt,
.reel__stage[data-focus="2"] .lm-pt,
.reel__stage[data-focus="3"] .lm-pt { stroke-width: 4; r: 9; }

/* --- landmarks ----------------------------------------------------------- */

/* A ring with a dark core and a magenta halo, not a thin white circle.
   Against bone the plain outline washed out at exactly the moment the reader
   is meant to be following it; the halo separates the marker from whatever
   is behind it, and the dark fill keeps the centre readable over highlights. */
.lm-pt {
  fill: rgba(8, 10, 14, 0.72);
  stroke: #ffffff;
  stroke-width: 9;
  filter:
    drop-shadow(0 0 7px rgba(255, 0, 255, 0.9))
    drop-shadow(0 0 16px rgba(255, 0, 255, 0.45));
  transform: scale(0.3);
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.44s cubic-bezier(0.2, 1.35, 0.4, 1);
}

/* --i staggers within the group, so a region lands as a sequence of
   placements rather than all at once -- which is how it is actually done. */
.lm-group.is-shown .lm-pt {
  transform: scale(1);
  transition-delay: calc(var(--i) * 70ms);
}

.lm-label {
  fill: #ffffff;
  paint-order: stroke;
  /* viewBox units on an 1855-wide image: at 40 these rendered around 12px on
     screen and were unreadable. */
  font-size: 58px;
  font-weight: 600;
  letter-spacing: 0.01em;
  /* A dark halo, because the label sits on a radiograph whose local
     brightness changes under it -- plain white text disappears over bone and
     the outline is what keeps it legible everywhere on the image. */
  paint-order: stroke;
  stroke: rgba(6, 8, 12, 0.92);
  stroke-width: 9;
  stroke-linejoin: round;
}

.lm {
  opacity: 0;
  transition: opacity 0.3s ease;
}

.lm-group.is-shown .lm {
  opacity: 1;
  transition-delay: calc(var(--i) * 70ms);
}

/* One pulse as a point lands, so the eye is told where to look rather than
   having to find a new dot on a busy image. It runs once and stops -- a
   marker that keeps pulsing reads as an alarm. */
.lm-group.is-shown .lm-halo {
  animation: lm-land 1.1s ease-out both;
  animation-delay: calc(var(--i) * 70ms);
}

.lm-halo {
  fill: none;
  stroke: var(--oa-measure-hot);
  stroke-width: 4;
  opacity: 0;
}

@keyframes lm-land {
  0%   { r: 15px;  opacity: 0.95; stroke-width: 6; }
  100% { r: 64px;  opacity: 0;    stroke-width: 1; }
}

.lm-plane {
  fill: none;
  stroke: var(--oa-measure-hot);
  stroke-width: 7;
  stroke-linecap: round;
  filter: drop-shadow(0 0 10px var(--oa-measure-hot-soft));
  stroke-dasharray: 1400;
  stroke-dashoffset: 1400;
  transition: stroke-dashoffset 0.9s ease-out;
}

.lm-planes.is-shown .lm-plane { stroke-dashoffset: 0; }
.lm-planes.is-shown .lm-plane:nth-child(2) { transition-delay: 0.16s; }
.lm-planes.is-shown .lm-plane:nth-child(3) { transition-delay: 0.32s; }
.lm-planes.is-shown .lm-plane:nth-child(4) { transition-delay: 0.48s; }

/* --- readout ------------------------------------------------------------- */

/* Below the frame, in normal flow.

   It has now been in two wrong places. Hung off the frame's left edge it ran
   into the copy column once the radiograph moved left; laid over the image it
   covered A, B and the N-A and N-B lines -- the readout sitting on top of the
   very thing it was describing. There is no free corner on a cephalogram: the
   anatomy runs corner to corner. So it goes underneath, where it cannot
   collide with anything. */
.reel__readout {
  grid-column: 2;
  grid-row: 2;
  /* Matched to the frame, so the cards line up under the radiograph rather
     than running the full width of the column. */
  /* Matched to the frame's rendered width -- the aspect ratio is 1855:2130,
     so the frame is 0.871 of its height. */
  width: calc(52vh * 1855 / 2130);
  max-width: 100%;
  justify-self: center;
  margin: var(--oa-space-3) 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.reel__readout.is-shown { opacity: 1; transform: translateY(0); }

/* Two columns while it is measurements alone; one per row once each carries
   its norm, which is a line of prose and needs the width. */
/* One line per measurement: name, value, then the norm as a trailing note.
   Stacked rows fit the frame's width; three cards side by side did not leave
   room for "norm 82 +/- 2 (Steiner) -- maxillary protrusion". */
.reel__readout--teaching li { grid-template-columns: auto auto 1fr; }

.reel__readout li {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--oa-space-4);
  align-items: baseline;
  padding: 9px 14px;
  border-radius: var(--oa-radius-sm);
  background: var(--ld-card-deep);
  /* Tinted to the highlight rather than the neutral line colour, so the
     readout and the planes it describes read as one thing. */
  border: 1px solid rgba(255, 0, 255, 0.35);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(3px);
}

.reel__readout span {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ld-faint);
}

.reel__readout b {
  font-size: 20px;
  font-weight: 700;
  color: var(--oa-measure-hot);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* The norm is cited, never asserted: it names its source in the markup.
   On its own line under the pair, so a long citation cannot squeeze the
   value into a column of single characters. */
.reel__readout i {
  grid-column: 1 / -1;
  font-style: normal;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--ld-faint);
}

/* --- the beats ----------------------------------------------------------- */

.reel__beats {
  position: relative;
  /* Pulled up over the sticky stage by exactly its height -- which is now the
     viewport minus the header, so this has to match or the two drift apart. */
  margin-top: calc(-100vh + var(--reel-header));
  margin-top: calc(-100svh + var(--reel-header));
}

/* Sized so two or three beats share the screen. They used to be a viewport
   each, which meant only one was ever readable and the rest were faded to
   nothing -- a reader had to scroll four times to find out what the page
   said. Copy is not a reward for scrolling: all of it is legible, and the
   scroll only decides which landmarks are on the radiograph. */
.beat {
  /* Matched to the stage's own inset, so the copy lines up with the
     radiograph's column rather than with the viewport edge. */
  margin-inline-start: max(clamp(20px, 5vw, 64px), calc((100vw - 1120px) / 2));
  /* Taller than the card, so the sticky card spends most of the beat pinned
     level with the radiograph rather than sliding past it. */
  min-height: 62vh;
  display: flex;
  flex-direction: column;
  /* flex-start, not center: centring parked the card halfway down its beat,
     which is BELOW the sticky line, so sticky only engaged for the last part
     of each beat's travel and the tops were adrift the rest of the time. */
  justify-content: flex-start;
  padding: clamp(20px, 4vh, 40px) 0;
  /* The COLUMN is as wide as the radiograph leaves; the measure is set on
     the paragraph instead. Constraining the whole column to a reading measure
     also constrained the button row, so the two calls to action stacked on a
     1440px screen with room to spare beside them. */
  max-width: min(62ch, 47vw);
}

/* Taller than the rest, and positioned so the scroll hint anchors to it. */
.beat--open { min-height: 78vh; position: relative; }

/* The stats beat is a grid of figures, not a paragraph, so it needs room the
   others do not -- at 42vh the last column was clipped mid-label. */
.beat:has(.beat__stats) { min-height: 56vh; }

/* Full strength, always. The current beat is MARKED rather than the others
   being dimmed -- the rail below says where you are without taking the rest
   of the page away to say it. */
/* Sticky within its own beat, pinned to the same line the radiograph starts
   on.
 *
 * The image is pinned and the copy scrolled, so their tops could not stay
 * aligned -- measured across a scroll the gap ran from 121px to 322px, which
 * is the "unaligned" the eye keeps catching. Pinning each card for the length
 * of its own beat holds it level with the image while that beat is being
 * read, then lets the next one push it away.
 *
 * Every beat stays in the document, so all the copy is still there to scroll
 * through; what changes is only where the current one sits while it is
 * current. */
.beat__card {
  position: sticky;
  top: calc(var(--reel-header) + var(--reel-gap));
  padding-left: var(--oa-space-5);
  border-left: 2px solid transparent;
  transition: border-color 0.35s ease;
}

.beat.is-current .beat__card { border-left-color: var(--oa-accent); }

.beat__eyebrow {
  display: inline-block;
  margin-bottom: var(--oa-space-4);
  padding: 6px 14px;
  border-radius: var(--oa-radius-pill);
  background: var(--oa-accent-track);
  color: var(--ld-accent-ink);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.beat__title {
  margin: 0 0 var(--oa-space-4);
  font-size: clamp(24px, 2.5vw, 32px);
  line-height: 1.12;
  letter-spacing: -0.025em;
  font-weight: 600;
  color: var(--ld-ink-strong);
  text-wrap: balance;
}

/* 60px in a half-width column wrapped "Place the landmark." onto five lines.
   The hero is still the biggest thing on the page at 46. */
.beat__title--hero { font-size: clamp(30px, 3.7vw, 46px); line-height: 1.06; }

.beat__body {
  margin: 0;
  /* The reading measure lives here, not on the column. */
  max-width: 46ch;
  font-size: clamp(15px, 1.5vw, 17.5px);
  line-height: 1.62;
  color: var(--ld-muted);
}

.beat__link {
  display: inline-block;
  margin-top: var(--oa-space-4);
  color: var(--ld-accent-ink);
  border-bottom: 1px solid var(--ld-border-strong);
  padding-bottom: 2px;
  text-decoration: none;
}

.beat__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--oa-space-3);
  margin-top: var(--oa-space-6);
}

.beat__reassure {
  margin: var(--oa-space-3) 0 0;
  font-size: 13.5px;
  color: var(--ld-muted);
}

.reel-btn {
  display: inline-flex;
  align-items: center;
  padding: 13px 26px;
  border-radius: var(--oa-radius-md);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
}

.reel-btn--primary {
  background: var(--oa-accent);
  color: #ffffff;
  box-shadow: 0 8px 28px rgba(108, 99, 255, 0.32);
}

.reel-btn--primary:hover { background: var(--oa-accent-hover); color: #fff; }

.reel-btn--ghost { border: 1px solid var(--ld-border); color: var(--ld-ink); }
.reel-btn--ghost:hover { border-color: var(--ld-border-strong); color: #fff; }

/* The scroll hint is gone. Once the copy was top-aligned it landed on the
   hero's own buttons instead of at the foot of the beat, and a page whose
   first screen is a headline over a radiograph does not need telling that it
   scrolls. */

.beat__stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: var(--oa-space-5);
  margin: var(--oa-space-5) 0 0;
}

.beat__stats dt {
  font-size: clamp(26px, 3vw, 36px);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ld-ink-strong);
  font-variant-numeric: tabular-nums;
}

.beat__stats dd {
  margin: 6px 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ld-faint);
}

/* --- after the reel ------------------------------------------------------ */

/* The radiograph is released here and the page changes gear: normal flow,
   each block arriving as it reaches the viewport. One shared reveal rather
   than a bespoke animation per section -- the variety comes from the layouts,
   and a page where every block enters differently reads as restless. */

/* .trial-how is the whitepaper/lead section, included from index.html and
   carrying its own section element rather than an .after wrapper. Given the
   same ground and rhythm here so it does not read as a foreign block dropped
   between two of ours. */
.page-dark .trial-how {
  background: var(--oa-stage) !important;
  padding: clamp(40px, 6vw, 76px) clamp(20px, 5vw, 64px);
  border-top: 1px solid #222836;
}

.after {
  background: var(--ld-ground);
  color: var(--ld-ink);
  /* 112px top AND bottom between every block left the page reading as a
     series of islands with dead space between them. */
  padding: clamp(40px, 6vw, 76px) clamp(20px, 5vw, 64px);
  border-top: 1px solid var(--ld-line);
}

.after__title {
  margin: 0 0 var(--oa-space-6);
  font-size: clamp(24px, 3.2vw, 36px);
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--ld-ink-strong);
  text-wrap: balance;
}

.after__title--close {
  max-width: 20ch;
  font-size: clamp(28px, 4vw, 46px);
  line-height: 1.08;
}

.after__lede {
  margin: 0;
  max-width: 48ch;
  font-size: clamp(15px, 1.5vw, 17px);
  line-height: 1.62;
  color: var(--ld-muted);
}

.after__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--oa-space-5);
  max-width: 1180px;
}

.after__card {
  padding: var(--oa-space-5);
  border: 1px solid var(--ld-line);
  border-radius: var(--oa-radius-lg);
  background: var(--ld-card);
}

.after__card svg { width: 24px; height: 24px; stroke: var(--ld-accent-ink); }

.after__card h3 {
  margin: var(--oa-space-4) 0 var(--oa-space-2);
  font-size: 17px;
  font-weight: 600;
  color: var(--ld-ink-strong);
}

.after__card p { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--ld-muted); }

.after__split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
  max-width: 1180px;
}

@media (max-width: 860px) {
  .after__split { grid-template-columns: minmax(0, 1fr); }
}

.after__quote {
  margin: 0;
  padding: var(--oa-space-5);
  background: var(--ld-card);
  border: 1px solid var(--ld-line);
  border-radius: var(--oa-radius-lg);
}

.after__quote blockquote {
  margin: 0 0 var(--oa-space-4);
  font-size: clamp(15px, 1.5vw, 17px);
  line-height: 1.6;
  color: var(--ld-ink);
}

.after__quote figcaption { display: flex; flex-direction: column; gap: 2px; }
.after__quote strong { font-size: 14px; color: var(--ld-ink-strong); }
.after__quote span { font-size: 13px; color: var(--ld-faint); }

.after__note {
  max-width: 68ch;
  margin: var(--oa-space-5) 0 0;
  font-size: 13.5px;
  color: var(--ld-faint);
}

.after__list { margin: 0; padding: 0; list-style: none; }

.after__list li {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--oa-space-4) 0;
  border-bottom: 1px solid var(--ld-line);
}

.after__list strong { font-size: 15.5px; font-weight: 600; color: var(--ld-ink-strong); }
.after__list span { font-size: 14px; line-height: 1.6; color: var(--ld-muted); }

.after--close { text-align: left; }
.after--close .beat__actions { margin-top: var(--oa-space-6); }

/* --- the shared reveal --------------------------------------------------- */

/* The reveal rules live in css/theme_dark.css now -- reveal.js is site-wide
   and any page can opt a block in, so the landing no longer owns them. */

/* Two columns on a wide screen. One 78ch column left two thirds of the
   viewport empty beside it, which is what made the section look unfinished. */
.reel-faq {
  columns: 2;
  column-gap: clamp(24px, 4vw, 56px);
  max-width: 1180px;
}


@media (max-width: 860px) {
  .reel-faq { columns: 1; }
}

.reel-faq__item {
  border-bottom: 1px solid var(--ld-line);
  /* Or a column break splits a question from its answer. */
  break-inside: avoid;
}

.reel-faq__item summary {
  padding: 18px 0;
  font-size: 15.5px;
  font-weight: 500;
  color: var(--ld-ink);
  cursor: pointer;
  list-style: none;
}

.reel-faq__item summary::-webkit-details-marker { display: none; }
.reel-faq__item summary::after { content: "+"; float: right; color: var(--ld-faint); }
.reel-faq__item[open] summary::after { content: "−"; }

.reel-faq__answer {
  padding: 0 0 20px;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--ld-muted);
}

/* --- narrow -------------------------------------------------------------- */

/* A phone gets the finished tracing once, in flow, with the copy under it.

   It used to pin the radiograph to the top at 44% of the screen and scroll
   the beats beneath it, so the build-up would run on a phone too. In practice
   the image held nearly half the screen for every beat on the page, the copy
   squeezed through what was left with a gap under each paragraph, and at
   390px the landmarks being added were too small to follow. The animation is
   the desktop's; a phone gets the result, which is what it can read. */
@media (max-width: 860px) {
  .reel__stage {
    position: static;
    display: block;
    height: auto;
    padding: var(--oa-space-4) clamp(20px, 5vw, 32px) 0;
    overflow: visible;
  }

  .reel__frame {
    width: min(100%, 420px);
    height: auto;
    max-width: none;
    margin: 0 auto;
    perspective: none;
  }

  /* Wide shot, no tilt: the camera is how the desktop follows the beats. */
  .reel__cam,
  .reel__svg { transform: none !important; }

  .reel .lm { opacity: 1; }
  .reel .lm-halo { opacity: 0; animation: none; }
  .reel .lm-pt { transform: scale(1); }
  .reel .lm-plane { stroke-dashoffset: 0; }
  .lm-label { font-size: 62px; }

  .reel__readout,
  .reel__readout--teaching {
    width: min(100%, 420px);
    margin: var(--oa-space-3) auto 0;
    opacity: 1;
    transform: none;
  }

  .reel__beats { margin-top: 0; }

  /* The hero before the picture. The stage comes first in the markup because
     desktop pins it behind the copy; on a phone that put the headline and
     its button below an image the height of the screen. Flattening the beat
     list into the reel lets the opening beat alone move above the stage,
     while the rest keep their place after it. */
  .reel { display: flex; flex-direction: column; }
  .reel__beats { display: contents; }
  .beat--open { order: -1; }

  .beat,
  .beat--open,
  .beat:has(.beat__stats) {
    min-height: 0;
    max-width: none;
    margin-inline-start: 0;
    padding: var(--oa-space-5) clamp(20px, 5vw, 32px) 0;
  }

  .beat:last-child { padding-bottom: clamp(40px, 8vw, 64px); }

  .beat__card {
    position: static;
    padding-left: 0;
    border-left: 0;
  }

  .beat__body { max-width: none; }

  /* The opening beat puts its buttons straight under the headline, so they
     are on the first screen; the subtitle can wait one flick. */
  .beat--open .beat__card { display: flex; flex-direction: column; align-items: flex-start; }
  .beat--open .beat__actions { order: 1; margin-top: var(--oa-space-4); }
  .beat--open .beat__reassure { order: 2; }
  .beat--open .beat__body { order: 3; margin-top: var(--oa-space-4); }
}

/* index.css paints a gradient strip across the top of <body>, sized to the
   header reserve, as a decoration behind the light header. This page loads
   index.css for its ported components but supplies its own ground, so that
   strip has nothing to sit behind -- it just shows through at the top of the
   page, mint-to-lavender, on the light theme. */
body:has(.reel) { background-image: none; }
