/* ============================================================================
   The Tactics Academy, upgrade page (OTO).

   Grammar: board briefing. One navy tactical board is the constant; the page
   places things on it and clears them off.

   Tokens are NOT restated here. They come from shared/brand.css, which is the
   live site's own stylesheet, vendored. This file maps them onto scrollcraft's
   six roles and then styles this page's own classes.

   Two documented deviations from the taste floor, both the brand's own and
   both explained in BRIEF.md:
     1. Three type families (Instrument Serif, Lora, Inter). The brand's system.
     2. A second hue. Blue is the page accent. RED IS AN ALARM ROLE, used at one
        size in one place above the fold and nowhere else. It never appears in a
        control, a link, a rule or a label below the fold.
   ========================================================================== */

:root {
  /* --- scrollcraft's six roles, mapped onto the brand ------------------- */
  /* BOARD NIGHT. The board is no longer a thing the page places on paper: the
     board IS the page. So the roles invert. Navy becomes the canvas and cream
     becomes the ink. Not one brand token has changed value; only which token
     plays which part has moved, which is why the page still reads as the same
     site rather than a dark-mode skin of it. */
  --sc-canvas:     var(--navy);
  --sc-surface:    var(--navy-raise);
  --sc-ink:        var(--cream);
  --sc-ink-soft:   rgba(250, 247, 240, 0.66);   /* 8.9:1 on the navy ground */
  --sc-accent:     #6FB2E0;      /* brand --blue is 3.4:1 on navy and misses the
                                    body floor. One step lighter, same hue, 7.6:1.
                                    --blue is kept for fills, where it is a
                                    background rather than a foreground. */
  --sc-accent-ink: #FFFFFF;

  --sc-hairline:        rgba(255, 255, 255, 0.12);
  --sc-hairline-strong: rgba(255, 255, 255, 0.28);

  --sc-font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
  --tta-font-work:   "Lora", Georgia, serif;
  --sc-font-text:    "Inter", system-ui, -apple-system, sans-serif;

  /* The alarm. One place only. Cream on this red is 5.51:1, so the plate
     clears the body floor. --tta-alarm-lift is the same hue raised for the
     rim light, where the red has to read AGAINST the navy rather than carry
     text on top of it. */
  --tta-alarm: #C8102E;
  --tta-alarm-lift: #E83C58;

  /* The cream board. Section 4 is the one place the page inverts back: on a
     navy ground the seven-day board has to be the bright object or it is just
     another dark panel on a dark page, and the whole peak goes quiet. */
  --tta-board:      #F4F1E9;
  --tta-board-ink:  #1D2730;
  --tta-board-soft: #5A636D;
  --tta-board-line: rgba(29, 39, 48, 0.20);

  --sc-measure: 66ch;
  --sc-maxw:    1140px;

  /* Ink-tinted shadow is invisible on navy. Depth on a dark ground comes from
     black plus a light top lip, not from a darker version of the ground. */
  --sc-shadow-color: 0 0 0;
  --sc-e1: 0 1px 2px rgba(0, 0, 0, 0.28);
  --sc-e2: 0 2px 4px rgba(0, 0, 0, 0.26), 0 8px 20px rgba(0, 0, 0, 0.34);
  --sc-e3: 0 4px 8px rgba(0, 0, 0, 0.30), 0 22px 50px rgba(0, 0, 0, 0.42);

  --sc-edge: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* brand.css sets a blanket 88px block padding on every <section>. The acts on
   this page own their own rhythm, and a pinned stage must not carry padding at
   all, so it is cleared here and reinstated per act. */
section { padding: 0; }

body {
  font-family: var(--sc-font-text);
  color: var(--sc-ink);
  /* brand.css paints cream and a 54px gold paper dot. Both belong to a printed
     ground, and this page no longer has one, so the ground is repainted here:
     navy, carrying the board's own 26px dot instead of the paper one. That dot
     is the same grid the .board-panel device already draws, so the page ground
     and the panels placed on it are made of the same material. */
  background: var(--sc-canvas);
  background-image: radial-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 26px 26px;
}

/* brand.css hard-codes the ink colour on every heading for a cream page. */
h1, h2, h3, .serif { color: var(--sc-ink); }

/* ---- the board ground ---------------------------------------------------
   One pitch, viewport-sized, held still while the page travels over it. Alpha
   is deliberately near the floor: this should be felt as structure underneath
   the page rather than seen as a picture on it. */
.ground {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  z-index: 0; pointer-events: none;
}
.ground__g {
  fill: none;
  stroke: #FFFFFF;
  stroke-width: 1.25;
  /* Near the floor on cream, because there it was structure felt through
     paper. On the navy ground the board is the ground, so it is allowed to be
     seen rather than only sensed. Still well under the panels placed on it. */
  opacity: 0.15;
  vector-effect: non-scaling-stroke;
}
.ground__spot { fill: #FFFFFF; stroke: none; }

/* The page rides above the board. */
.site-receipt, main, .rail { position: relative; z-index: 1; }


/* Browser surfaces. The parts not drawn still carry the design. */
::selection { background: rgba(111, 178, 224, 0.30); color: var(--cream); }
:focus-visible { outline: 2px solid #6FB2E0; outline-offset: 3px; border-radius: 3px; }

.wrap { max-width: var(--sc-maxw); margin-inline: auto; padding-inline: var(--sc-gutter); }
.act  { position: relative; }

/* Available to any element whose visible label has been taken over by the
   design but whose accessible name still has to exist somewhere. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ============================================================ 0. RECEIPT ==
   Small, calm, and first. The loud part is directly under it, so this has to
   stay quiet or the fold has two things competing. */
.receipt {
  border-block-end: 1px solid var(--sc-hairline);
  background: rgba(255, 255, 255, 0.04);
}
.receipt__in {
  max-width: var(--sc-maxw);
  margin-inline: auto;
  padding: var(--sc-3) var(--sc-gutter);
  display: flex; align-items: center; gap: var(--sc-3);
}
.receipt__mark { width: 34px; height: 34px; border-radius: 8px; flex-shrink: 0; }
.receipt__txt {
  font-size: 0.9rem; line-height: 1.5; color: var(--sc-ink-soft);
  text-wrap: pretty;
}
.receipt__txt strong { color: var(--sc-ink); font-weight: 600; }


/* ============================================================ 1. INTERRUPT ==
   The fold. Board absent. Bare cream, one alarm line, one statement. */
/* The trailing padding is deliberately small. The board below is a PINNED
   stage, so it already carries a viewport of its own air above the board once
   it centres; stacking a full section padding on top of that read as a hole
   between the fold and the video. The fold's own rhythm is unchanged. */
.act--interrupt {
  padding-block: clamp(1.5rem, 3.4vw, 2.75rem) clamp(0.75rem, 1.6vw, 1.25rem);
}

/* The alarm is now a plate rather than a ruled line: a solid red object placed
   ON the board, which is the grammar the rest of the page already speaks.

   The earlier note here said a halo would be wrong and bled ink into paper
   instead. That was right for a printed cream ground and it is wrong for this
   one. Light on a dark surface is exactly how the eye expects a bright object
   to behave, so the plate genuinely glows: a tight rim and near-glow carried on
   the plate itself, then a wide soft bloom behind it, so the falloff reads as
   light rather than as one flat CSS halo.

   The wrapper hugs the plate, so the bloom is centred on the object and not on
   the column. */
.alarm {
  position: relative;
  isolation: isolate;
  width: fit-content;
  max-width: 100%;
  margin-block-end: clamp(1.5rem, 3.4vw, 2.5rem);
}
.alarm::before {
  content: ""; position: absolute; z-index: -1;
  inset: -2.4em -3.2em;
  background: radial-gradient(54% 118% at 50% 50%,
              rgba(200, 16, 46, 0.62),
              rgba(200, 16, 46, 0.26) 44%,
              transparent 72%);
  filter: blur(28px);
  animation: alarm-bloom 4.6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes alarm-bloom { 0%, 100% { opacity: 0.72; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .alarm::before { animation: none; opacity: 0.88; }
}

.alarm__plate {
  /* Lora 600, the brand's working headline face, so the alarm belongs to the
     page's typography rather than arriving in a different voice. Red is still
     the only non-brand hue on the page and it still appears exactly here and
     nowhere else. Cream on this red is 5.51:1. */
  display: block;
  font-family: var(--tta-font-work);
  font-weight: 600;
  font-size: clamp(1.05rem, 2vw, 1.6rem);
  line-height: 1.35;
  letter-spacing: -0.006em;
  color: var(--cream);
  background: var(--tta-alarm);
  padding: clamp(0.6rem, 1.2vw, 0.85rem) clamp(1rem, 1.8vw, 1.6rem);
  border-radius: 6px;
  text-wrap: pretty;
  box-shadow:
    0 0 0 1px rgba(232, 60, 88, 0.50),
    0 0 22px rgba(200, 16, 46, 0.62),
    0 0 62px rgba(200, 16, 46, 0.42),
    0 4px 8px rgba(0, 0, 0, 0.30),
    0 22px 50px rgba(0, 0, 0, 0.40);
}

.interrupt__h {
  font-family: var(--sc-font-display);
  font-weight: 400;
  font-size: clamp(2.5rem, 6.2vw, 4.7rem);
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--sc-ink);
  text-wrap: balance;
  margin-block-end: var(--sc-4);
}
/* The second line is the same face as the first, upright, separating on colour
   alone. Instrument Serif's italic is a calligraphic one, very unlike its
   roman, and at this size on a dark ground it read as a different typeface
   rather than as emphasis. <em> is kept because the emphasis is real; only the
   slant is dropped. */
.interrupt__h em { font-style: normal; color: var(--sc-accent); }

/* The credit is now the fold's only lede: the "you keep the workbook and add
   the course" line that used to sit above it has gone, since it and this said
   the same thing twice. So it takes that line's type size and carries the fold
   on its own. The rule down its side stays, because it still reads as a note
   pinned to the offer rather than as body copy, and because it is the one thing
   marking the arithmetic out from the headline above it.

   Still deliberately plain: no struck-through price, no badge, no percentage.
   The three figures are lifted to full cream so the sum is scannable without
   the line raising its voice. The struck price belongs on the closing card,
   where the visitor is deciding, and only there. */
.credit {
  padding-inline-start: var(--sc-4);
  border-inline-start: 2px solid rgba(111, 178, 224, 0.45);
  font-size: clamp(1.05rem, 1.6vw, 1.24rem);
  line-height: 1.6;
  color: var(--sc-ink-soft);
  max-width: 52ch;
  text-wrap: pretty;
}
.credit b { color: var(--sc-ink); font-weight: 500; }


/* ============================================================ 2. THE VSL ====
   The board's first placement, and the one moment on the page where the board
   is something you OPEN rather than something you look at.

   The act is pinned now. A full board covers the video, then parts on the
   HALFWAY LINE and slides off both edges, so the seam is the pitch's own centre
   line rather than an arbitrary cut down the middle of a rectangle.

   The earlier notes here are worth keeping, because they are why this shape was
   chosen. A clip-path wipe sliced the video with a hard travelling edge. An
   entrance settle finished before it could be seen, since a flow act this high
   on the page is already at p = 0.72 on a 1280x860 screen before the visitor
   scrolls at all. Pinning removes that whole class of problem: the act owns its
   own travel, so the open always happens in front of the visitor, at any
   viewport height, and never behind them.

   All of it is driven from --sc-p in CSS. page.js is untouched and the engine
   is untouched. --open is the door's own clock, remapped off act progress: a
   beat closed at the top so the board is read as a board, the open across the
   middle half, then a hold with the video clear. The fallback is 1, so with no
   JS at all the doors are simply open and the video is there. */
.act--vsl { --open: clamp(0, calc((var(--sc-p, 1) - 0.12) / 0.5), 1); }

/* The stage does NOT centre its content. Centring a board inside a full
   viewport is what put a hole between the fold and the video, and padding the
   bottom to fake a lift only ever half-fixed it. Aligning to the start pins the
   board a fixed distance from the top of the viewport instead, so it sits high
   and, more usefully, sits in the SAME place at every viewport height rather
   than drifting down as the screen gets taller. The space left under it is the
   board ground, which is the point of the page. */
.vsl-stage { display: flex; align-items: flex-start; }
.vsl__wrap {
  width: 100%;
  padding-block: clamp(2rem, 6vh, 4.5rem) 0;
  max-height: 100vh;
}
.vsl { max-width: 940px; margin-inline: auto; }

/* The action sits in the ground the un-centred stage leaves under the board,
   which is what that space is now for. Centred on the board rather than on the
   page column, so it reads as belonging to the video above it. */
.vsl__act {
  display: flex;
  justify-content: center;
  margin-block-start: clamp(1.5rem, 4.5vh, 2.75rem);
}

.vsl__board { padding: clamp(0.7rem, 1.6vw, 1.1rem); box-shadow: var(--sc-e3); }
.vsl__frame {
  position: relative; z-index: 1;
  border-radius: 10px; overflow: hidden;
  background: #000;
  aspect-ratio: 16 / 9;
}
.vsl__video { width: 100%; height: 100%; display: block; object-fit: cover; }

/* --- the doors ---------------------------------------------------------- */
/* They live inside the frame, so the frame's own overflow clips them: the
   halves slide out and vanish at the edge like doors going into a wall,
   instead of travelling across the rest of the page. Never interactive, so
   the video underneath is always reachable. */
.vsl__doors { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.vsl__door {
  position: absolute; top: 0; bottom: 0;
  width: 50%;
  overflow: hidden;
  background: var(--navy-raise);
  background-image: radial-gradient(rgba(255, 255, 255, 0.06) 1px, transparent 1px);
  background-size: 26px 26px;
  will-change: transform;
}
.vsl__door--l {
  left: 0;
  transform: translateX(calc(var(--open) * -100%));
  box-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.22);
}
.vsl__door--r {
  right: 0;
  transform: translateX(calc(var(--open) * 100%));
  box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.22);
}
/* One pitch drawn twice, each half clipped to its own door, so the two halves
   line up into a single continuous board while they are shut. Each SVG is
   deliberately twice its door's width, which means it has to opt out of
   scrollcraft.css's `img, video, canvas, svg { max-width: 100% }` reset. Left
   in, that reset silently squeezes a whole pitch into each half and the two
   doors read as two separate boards rather than one. */
.vsl__doorsvg { position: absolute; top: 0; width: 200%; max-width: none; height: 100%; }
.vsl__door--l .vsl__doorsvg { left: 0; }
.vsl__door--r .vsl__doorsvg { right: 0; }

.vsl__pitch { fill: none; stroke: rgba(255, 255, 255, 0.30); stroke-width: 1.5; }
.vsl__spot  { fill: rgba(255, 255, 255, 0.30); }

/* The shape on the board keeps playing while the board opens: the back line
   steps up, the midfield shifts across and up, the forward makes the run in
   behind, and the press adjusts to it. One value drives the doors AND the
   shape, so it reads as one gesture rather than two animations that happen to
   line up. */
.vsl__unit--back  { transform: translate(calc(var(--open) * 36px), 0); }
.vsl__unit--mid   { transform: translate(calc(var(--open) * 47px), calc(var(--open) * -21px)); }
.vsl__unit--front { transform: translate(calc(var(--open) * 72px), calc(var(--open) * -40px)); }
.vsl__unit--press { transform: translate(calc(var(--open) * 31px), calc(var(--open) * 25px)); }

.vsl__mark { fill: var(--blue); stroke: var(--cream); stroke-width: 1.6; }
.vsl__opp  { fill: none; stroke: var(--cream); stroke-width: 2.4; stroke-linecap: round; opacity: 0.72; }

/* pathLength normalises every run to 200, so one dash length covers all three
   whatever their real geometry. */
.vsl__run {
  fill: none;
  stroke: #6FB2E0;
  stroke-width: 2.4;
  stroke-linecap: round;
  opacity: 0.85;
  stroke-dasharray: 200px;
  stroke-dashoffset: calc(200px - var(--open) * 200px);
}

/* The instruction is written ON the board rather than captioned under it, so
   the board asks for the scroll that opens it. Centred at x = 500, which is the
   halfway line, so the seam splits the words and each half leaves with its own
   door. That is the whole point of putting it here and not above. */
.vsl__cue {
  font-family: var(--sc-font-display);
  font-size: 42px;
  fill: var(--cream);
  letter-spacing: 0.01em;
  opacity: 0.92;
}


/* ============================================================ 3. PLAINLY ====
   The authored silence in front of the peak. One paragraph, wide margins,
   nothing else. Keep it that way. */
/* Trailing padding stays generous: this is the authored silence in front
   of the peak. The leading padding is cut, because the VSL has already
   given the eye a rest and stacking both full paddings read as a gap. */
.act--plain { padding-block: clamp(1.75rem, 3.6vw, 3rem) clamp(3rem, 7vw, 6.5rem); }
.plain { max-width: 700px; margin-inline: auto; }
.plain__h {
  font-family: var(--tta-font-work);
  font-weight: 600;
  font-size: clamp(1.45rem, 2.8vw, 2.1rem);
  line-height: 1.22;
  letter-spacing: -0.012em;
  text-wrap: balance;
  margin-block-end: var(--sc-5);
}
.plain__p {
  /* Light type on a dark ground renders optically thinner than the same size
     in ink on paper, so the body gains a touch of leading and tracking here
     rather than being left at the cream-page value. */
  font-size: 1.06rem; line-height: 1.78; letter-spacing: 0.004em;
  color: rgba(250, 247, 240, 0.78);
  text-wrap: pretty;
}


/* ============================================================ 4. THE MOVE ===
   THE PEAK. The board is the ground, present from p = 0, so the pinned stage
   is never empty. Everything that moves is driven from --sc-p by page.js. */
.move { display: flex; align-items: center; }
.move__wrap {
  width: 100%;
  display: flex; flex-direction: column;
  gap: clamp(0.9rem, 2vw, 1.6rem);
  padding-block: clamp(1.25rem, 3vw, 2.5rem);
  max-height: 100vh;
}

.move__head { flex-shrink: 0; }
.move__h {
  font-family: var(--tta-font-work);
  font-weight: 600;
  font-size: clamp(1.35rem, 2.7vw, 2rem);
  line-height: 1.2;
  letter-spacing: -0.012em;
  text-wrap: balance;
}
.move__note { font-size: 0.92rem; color: var(--sc-ink-soft); margin-block-start: var(--sc-2); }

/* THE ONE INVERSION ON THE PAGE. Everywhere else the board is dark and the
   page carries it. Here the page is dark and the board is cream, because this
   is the peak: on a navy ground a navy panel is not an object, it is just a
   slightly different patch of the same surface, and the whole seven-day reveal
   would go quiet inside it. Cream makes the board the brightest thing on the
   page at exactly the moment it holds the most content.

   It is the brand's own board device turned inside out, not a new one: same
   26px dot grid, same geometry, same node and chip anatomy. Only the polarity
   moves, and every mark on it moves with it. */
.move__board {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  padding: clamp(0.75rem, 1.8vw, 1.4rem);
  background: var(--tta-board);
  box-shadow: var(--sc-e3), 0 0 0 1px rgba(255, 255, 255, 0.10);
}
.move__board::before {
  background-image: radial-gradient(rgba(29, 39, 48, 0.14) 1px, transparent 1px);
}
.move__svg { width: 100%; height: 100%; display: block; }

/* --- the pitch. Present from the first frame, and it never changes. ------ */
.move__pitch line,
.move__pitch path,
.move__pitch rect,
.move__pitch circle {
  fill: none;
  stroke: var(--tta-board-line);
  stroke-width: 1.5;
}
.move__pitch .goal { stroke: rgba(29, 39, 48, 0.58); stroke-width: 3.5; }
.move__pitch .net  { stroke: rgba(29, 39, 48, 0.20); stroke-width: 1; }

/* --- the move itself ---------------------------------------------------- */
/* The whole route, faint, so the visitor can see where this is going. */
.move__trail {
  fill: none;
  stroke: rgba(29, 39, 48, 0.16);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 3 9;
}
/* The passes, drawn behind the ball as it travels. */
.move__drawn {
  fill: none;
  stroke: var(--blue);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The shot. Heavier and brighter, and page.js draws it at a faster rate than
   the passes. The change of pace is the whole drama: nothing flashes. */
/* On the navy board the shot was lighter than the passes. On cream the same
   move has to run the other way: the shot is the DARKEST, heaviest line on the
   board, because that is what "more" looks like on paper. */
.move__shot {
  fill: none;
  stroke: var(--navy);
  stroke-width: 5;
  stroke-linecap: round;
}
.move__ball {
  fill: var(--navy);
  stroke: var(--tta-board);
  stroke-width: 1.5;
}

/* --- nodes. Muted until reached, per the client brief. ------------------- */
.move__nodes .node circle {
  fill: #FFFFFF;
  stroke: rgba(29, 39, 48, 0.26);
  stroke-width: 1.5;
  transition: fill var(--sc-d-base) var(--sc-ease-out),
              stroke var(--sc-d-base) var(--sc-ease-out);
}
.move__nodes .node text {
  font-family: "Inter", sans-serif;
  font-size: 13px; font-weight: 600;
  fill: rgba(29, 39, 48, 0.45);
  text-anchor: middle; dominant-baseline: central;
  transition: fill var(--sc-d-base) var(--sc-ease-out);
}
.move__nodes .node.is-on circle { fill: var(--blue); stroke: #FFFFFF; }
.move__nodes .node.is-on text   { fill: #FFFFFF; }
/* The bonus is the one node that finishes the sequence, so on cream it takes
   the darkest fill rather than the lightest: the board ends on ink. */
.move__nodes .node.is-bonus.is-on circle { fill: var(--navy); stroke: #FFFFFF; }
.move__nodes .node.is-bonus.is-on text   { fill: var(--cream); }

/* --- chips. Positioned in JS off the live node geometry. ---------------- */
.move__chips { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
/* The chips invert with the board. White cards on a cream board would be two
   shades of the same paper; navy chips read as pieces PLACED on it, which is
   the same relationship the white chips had to the dark board before. */
.move__chip {
  position: absolute;
  width: min(20rem, 62%);
  background: var(--navy);
  color: var(--cream);
  border-radius: 12px;
  padding: 0.6rem 0.85rem;
  box-shadow: 0 6px 20px rgba(10, 16, 21, 0.34), 0 0 0 1px rgba(255, 255, 255, 0.10);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 260ms var(--sc-ease-out), transform 260ms var(--sc-ease-out);
}
.move__chip.is-on { opacity: 1; transform: translateY(0); }
.move__chip.is-bonus { background: var(--blue); color: #FFFFFF; }

.move__chip .k {
  display: block;
  font-size: 0.62rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: #7FC0EE;
  margin-block-end: 3px;
}
.move__chip.is-bonus .k { color: rgba(255, 255, 255, 0.92); }
.move__chip .t { display: block; font-family: var(--tta-font-work); font-weight: 600; font-size: 0.98rem; line-height: 1.2; }
.move__chip .d { display: block; font-size: 0.78rem; line-height: 1.45; margin-block-start: 4px; color: rgba(250, 247, 240, 0.76); }
.move__chip.is-bonus .d { color: rgba(255, 255, 255, 0.92); }

/* --- the semantic content. Hidden while the board does the work, and the
       whole section under reduced motion. ------------------------------- */
.move__list {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ============================================================ 5. PROOF =====
   Two video slots, both placeholders. Then the written quotes, separate and
   below, never substituted into the video slot. */
.act--proof { padding-block: clamp(1rem, 2vw, 1.75rem) clamp(3.5rem, 8vw, 7rem); }

.proof__head {
  display: flex; align-items: end; justify-content: space-between;
  gap: var(--sc-5); flex-wrap: wrap;
  margin-block-end: clamp(1.75rem, 4vw, 3rem);
}
.proof__h {
  font-family: var(--tta-font-work); font-weight: 600;
  font-size: clamp(1.5rem, 3vw, 2.2rem);
  line-height: 1.18; letter-spacing: -0.012em;
  text-wrap: balance;
}
.proof__count { display: flex; align-items: baseline; gap: var(--sc-3); }
.proof__n {
  font-family: var(--sc-font-display);
  font-size: clamp(2.4rem, 5vw, 3.4rem);
  line-height: 1;
  color: var(--sc-accent);
  font-variant-numeric: tabular-nums;
}
.proof__lab { font-size: 0.86rem; color: var(--sc-ink-soft); max-width: 22ch; line-height: 1.45; }

/* Asymmetric on purpose. A wide clip and a phone clip are not two equal
   columns, so they are not laid out as two equal columns. */
.films {
  display: grid;
  grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr);
  gap: clamp(1.25rem, 3vw, 2.25rem);
  align-items: start;
}
.film { min-width: 0; }
.film__frame {
  position: relative;
  overflow: hidden;
  border-radius: 14px;
  background: #000;
  /* A dark video frame on a dark ground needs an edge, or the poster bleeds
     into the page and the clip stops reading as a placed object. */
  box-shadow: var(--sc-e2), 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.film__frame--wide { aspect-ratio: 16 / 9; }
.film__frame--tall {
  aspect-ratio: 9 / 16;
  height: min(27rem, 56vh); width: auto; margin-inline: auto;
}
.film__video { width: 100%; height: 100%; display: block; object-fit: cover; }

.film__slot {
  position: relative;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: var(--sc-2);
  border-radius: 14px;
  background:
    repeating-linear-gradient(135deg,
      rgba(29, 39, 48, 0.035) 0 12px,
      rgba(29, 39, 48, 0.065) 12px 24px);
  border: 1px dashed var(--border-hover);
  color: var(--muted);
}
.film__slot--wide { aspect-ratio: 16 / 9; }
.film__slot--tall { aspect-ratio: 9 / 16; height: min(27rem, 56vh); width: auto; margin-inline: auto; }
.film__badge {
  font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: #FFFFFF; background: var(--navy);
  padding: 5px 11px; border-radius: 999px;
}
.film__meta { font-size: 0.82rem; }
.film__cap { margin-block-start: var(--sc-3); font-size: 0.88rem; color: var(--sc-ink-soft); text-wrap: pretty; }

.quotes { margin-block-start: clamp(2.5rem, 6vw, 4.5rem); }
.quotes__lead {
  font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--sc-accent);
  padding-block-end: var(--sc-3);
  border-block-end: 1px solid var(--sc-hairline);
  margin-block-end: clamp(1.25rem, 3vw, 2rem);
}
.quotes__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.25rem, 3vw, 2.5rem);
}
/* Not cards. Type on space, separated by a rule. */
.quote { min-width: 0; }
.quote p {
  font-family: var(--tta-font-work); font-size: 1rem;
  line-height: 1.6; letter-spacing: 0.004em;
  color: rgba(250, 247, 240, 0.86);
  text-wrap: pretty;
}
.quote footer { margin-block-start: var(--sc-3); display: flex; flex-direction: column; gap: 1px; }
.quote cite { font-style: normal; font-weight: 600; font-size: 0.88rem; color: var(--sc-ink); }
.quote footer span { font-size: 0.8rem; color: var(--sc-ink-soft); }


/* ============================================================ 6. DECIDE ====
   The board, cleared to one price and one action. Last act on the page, so
   every cue here takes a single value and holds. */
/* No cues here, which is where this act started and where it has ended up. The
   sum was briefly animated on scroll and the animation has been removed: the
   composition it produced is kept as the resting state, struck price and all.
   A close resolves; it does not make an entrance. */
.decide { display: flex; align-items: center; }
.decide__wrap {
  width: 100%;
  display: flex; flex-direction: column;
  gap: clamp(1rem, 2.4vw, 1.75rem);
  padding-block: clamp(1.5rem, 3.5vw, 3rem);
}

/* The close stays dark rather than inverting with the seven-day board. Two
   cream boards would make the page read as light-with-dark-gaps, and the peak
   would stop being the one place the polarity flips. So this one lifts off the
   ground instead: one step up in value, a hairline, and a deeper shadow, which
   is enough to make it an object without spending the inversion twice. */
.decide__board {
  padding: clamp(1.5rem, 3.5vw, 2.75rem);
  background: var(--navy-raise);
  box-shadow: var(--sc-e3), 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.decide__grid {
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
}

.decide__h {
  font-family: var(--sc-font-display);
  font-weight: 400;
  font-size: clamp(1.9rem, 4vw, 3rem);
  line-height: 1.05;
  letter-spacing: -0.018em;
  color: #FFFFFF;
  text-wrap: balance;
}
.decide__gets {
  list-style: none;
  margin-block-start: var(--sc-5);
  display: flex; flex-direction: column; gap: var(--sc-3);
}
.decide__gets li {
  position: relative;
  padding-inline-start: 1.6rem;
  /* Light type on a dark ground: a touch more leading and tracking, and one
     step more weight, or it renders thin. */
  font-size: 0.95rem; line-height: 1.6; letter-spacing: 0.004em;
  color: #DCE3E9;
  text-wrap: pretty;
}
.decide__gets li::before {
  content: ""; position: absolute;
  inset-inline-start: 0; inset-block-start: 0.55em;
  width: 8px; height: 8px; border-radius: 50%;
  background: #7FC0EE;
}

/* The price panel goes cream. This is the only other place on the page that
   inverts, and it is a smaller move than the peak's: there the whole board
   flips, here one panel INSIDE a dark board does, so the two do not compete.
   It buys two things. The close gets the brightest object on the page, which is
   what the client asked for, and the red marker below lands on paper, where a
   correction written in marker actually belongs. */
.decide__act {
  background: var(--tta-board);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 14px;
  padding: clamp(1.25rem, 2.6vw, 1.9rem);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.34), 0 26px 60px rgba(0, 0, 0, 0.48);
}

/* --- the sum ------------------------------------------------------------ */
.ladder { margin-block-end: var(--sc-4); }
.ladder__was { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.ladder__lab {
  font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--tta-board-soft);
}
.ladder__num {
  position: relative;
  font-family: var(--sc-font-display);
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  line-height: 1;
  color: var(--tta-board-soft);
  font-variant-numeric: tabular-nums;
}
/* A drawn stroke, not a text-decoration: it has to arrive over the number on
   scroll, and it has to look written. preserveAspectRatio is none so the path
   stretches to whatever the number's box is, and non-scaling-stroke stops that
   stretch from also thickening the line. The max-width opt-out is the same
   scrollcraft.css reset the doors have to escape. */
.ladder__strike {
  position: absolute;
  left: -9%; top: 50%;
  width: 118%; max-width: none; height: 0.86em;
  transform: translateY(-54%);
  overflow: visible;
  pointer-events: none;
}
.ladder__strike path {
  fill: none;
  stroke: var(--tta-alarm);
  stroke-width: 4.5;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.ladder__credit {
  margin-block-start: var(--sc-2);
  font-size: 0.86rem; line-height: 1.5;
  color: var(--tta-board-soft);
  text-wrap: pretty;
}
.ladder__credit b { color: var(--tta-board-ink); font-weight: 600; }

.decide__price {
  font-family: var(--sc-font-display);
  font-size: clamp(3rem, 7vw, 4.6rem);
  line-height: 0.95;
  color: var(--tta-board-ink);
  font-variant-numeric: tabular-nums;
}
.decide__cur { font-size: 0.55em; vertical-align: 0.28em; margin-inline-end: 0.04em; color: var(--tta-board-soft); }
.decide__once { font-size: 0.85rem; color: var(--tta-board-soft); margin-block: var(--sc-2) var(--sc-5); }
.decide__grt {
  font-size: 0.82rem; line-height: 1.55; color: var(--tta-board-soft);
  margin-block-start: var(--sc-4);
  text-wrap: pretty;
}

/* --- the one button. One style, one destination, one label. ------------- */
.cta {
  display: block; width: 100%;
  font-family: var(--sc-font-text);
  font-weight: 600; font-size: 1.02rem;
  text-align: center; text-decoration: none;
  padding: 16px 28px;
  border-radius: 10px;
  background: var(--blue);
  color: #FFFFFF;
  box-shadow: 0 1px 2px rgba(29, 39, 48, 0.10), 0 2px 6px rgba(29, 39, 48, 0.07);
  transition: background var(--sc-d-fast) var(--sc-ease-out),
              box-shadow var(--sc-d-fast) var(--sc-ease-out),
              transform var(--sc-d-fast) var(--sc-ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .cta:hover {
    background: var(--deep-blue);
    box-shadow: 0 0 0 1px rgba(50, 129, 188, 0.38),
                0 0 0 7px rgba(50, 129, 188, 0.13),
                0 5px 12px rgba(24, 68, 102, 0.26),
                0 14px 32px rgba(24, 68, 102, 0.20);
    transform: translateY(-2px);
  }
}
.cta:active { transform: translateY(1px); box-shadow: 0 1px 3px rgba(29, 39, 48, 0.18); }
.cta--sm { width: auto; font-size: 0.94rem; padding: 11px 20px; white-space: nowrap; }
/* Sized to its own words rather than to a column. The full-width .cta is right
   inside the closing card, where it is the last thing on a panel; out on the
   open ground it would read as a bar rather than as a button. */
.cta--inline { display: inline-block; width: auto; padding: 15px 32px; }

/* --- the decline path. Running text, quiet, never a second button. ------ */
.decline {
  font-size: 0.88rem; line-height: 1.6; color: var(--sc-ink-soft);
  text-align: center; max-width: 62ch; margin-inline: auto;
  text-wrap: pretty;
}
.decline a { color: var(--sc-ink-soft); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
@media (hover: hover) and (pointer: fine) { .decline a:hover { color: var(--sc-ink); } }

/* --- footer, inside the closing stage so there is no dead tail ---------- */
.foot { border-block-start: 1px solid var(--sc-hairline); padding-block-start: var(--sc-4); }
.foot__row { display: flex; align-items: center; gap: var(--sc-3); margin-block-end: var(--sc-3); }
.foot__mark { width: 30px; height: 30px; border-radius: 7px; }
.foot__mission { font-family: var(--tta-font-work); font-size: 0.92rem; color: var(--sc-ink); }
.foot__legal { font-size: 0.74rem; line-height: 1.55; color: rgba(250, 247, 240, 0.52); max-width: 90ch; }
.foot__legal--fine { margin-block-start: var(--sc-2); font-size: 0.68rem; opacity: 0.85; }


/* ============================================================ CHROME =======
   The board rail. Stop, price, one action. No wordmark. */
/* The rail was a dark bar docked over a cream page, so it separated on value
   alone. Over the navy ground it no longer can, so it lifts one step and takes
   a brighter top edge: the rail is chrome sitting ON the board, not part of it. */
.rail {
  position: fixed;
  inset-inline: 0; inset-block-end: 0;
  z-index: var(--sc-z-chrome);
  background: rgba(26, 37, 46, 0.97);
  backdrop-filter: blur(8px);
  border-block-start: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 -10px 34px rgba(0, 0, 0, 0.45);
  transform: translateY(101%);
  transition: transform 320ms var(--sc-ease-drawer);
}
.rail.is-up { transform: translateY(0); }
.rail[hidden] { display: none; }
.rail__in {
  max-width: var(--sc-maxw); margin-inline: auto;
  padding: 0.7rem var(--sc-gutter);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sc-4);
}
.rail__where {
  display: flex; align-items: center; gap: 0.55rem;
  font-size: 0.82rem; font-weight: 500;
  color: #C3CFD9;
  min-width: 0;
}
.rail__where span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail__dot { width: 7px; height: 7px; border-radius: 50%; background: #7FC0EE; flex-shrink: 0; }
.rail__act { display: flex; align-items: center; gap: var(--sc-4); flex-shrink: 0; }
.rail__price {
  font-family: var(--sc-font-display);
  font-size: 1.5rem; color: #FFFFFF; line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* The rail sits over the page, so the closing act needs room under it. */
.act--decide .decide__wrap { padding-block-end: clamp(4.5rem, 8vw, 6rem); }


/* ============================================================ RESPONSIVE ===
   Phone first audience, so these are real layouts rather than a squeeze. */
@media (max-width: 900px) {
  .films { grid-template-columns: minmax(0, 1fr); }
  .film--tall .film__slot--tall,
.film--tall .film__frame--tall { height: min(24rem, 62vh); }
  .quotes__grid { grid-template-columns: minmax(0, 1fr); gap: var(--sc-5); }
  .quote + .quote { border-block-start: 1px solid var(--border); padding-block-start: var(--sc-5); }
  .decide__grid { grid-template-columns: minmax(0, 1fr); gap: var(--sc-5); }
  .proof__head { align-items: start; }
}

@media (max-width: 700px) {
  /* Step the fold down a rung. The clamp floors above are desktop floors and
     they wrap a headline to six lines at 390px. */
  .alarm__plate { font-size: clamp(0.95rem, 3.8vw, 1.15rem); }
  .alarm::before { inset: -1.6em -1.8em; filter: blur(20px); }
  .credit { font-size: 0.92rem; }
  .interrupt__h { font-size: clamp(2.1rem, 8.6vw, 2.7rem); }
  .interrupt__sub { font-size: 1rem; }
  .receipt__txt { font-size: 0.82rem; }
  .receipt__txt strong { display: block; }

  .move__wrap { gap: var(--sc-3); }
  .move__note { display: none; }
  .move__chip { width: min(17rem, 80%); padding: 0.55rem 0.75rem; }
  .move__chip .d { font-size: 0.72rem; line-height: 1.4; }

  .rail__where { display: none; }
  .rail__in { justify-content: space-between; }
  .rail__act { flex: 1; justify-content: space-between; }
}


/* ============================================================ REDUCED MOTION
   Fewer and gentler, not zero. The completed scene is the static state, per
   the brand rule, so the move is drawn whole and every day is legible. */
@media (prefers-reduced-motion: reduce) {
  .rail { transition: none; }
  .cta { transition: none; }
  .move__chip { transition: none; }

  /* The doors are the whole reason that act is pinned, so with them held open
     there is nothing left for the pin to do: the act becomes an ordinary
     section holding a video, which is what it was before. The board is not
     shown half-open or faded out, it is simply already open, because the
     completed scene is the static state. */
  .act--vsl { --open: 1; height: auto !important; }
  .act--vsl .vsl-stage { display: block; height: auto !important; position: static !important; }
  .act--vsl .vsl__wrap { max-height: none; padding-block: clamp(1.5rem, 4vw, 3rem); }
  .vsl__doors { display: none; }


  /* The board keeps its finished state, and the eight days are read from the
     list rather than from chips that would need scroll to arrive. */
  .move__chips { display: none; }
  .move__list {
    position: static;
    width: auto; height: auto;
    margin: 0; overflow: visible; clip-path: none; white-space: normal;

    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--sc-4) var(--sc-5);
    margin-block-start: var(--sc-5);
  }
  .move__list li { border-block-start: 1px solid var(--sc-hairline); padding-block-start: var(--sc-3); }
  .move__list li::before {
    content: "Lesson " attr(data-day);
    display: block;
    font-size: 0.64rem; font-weight: 700;
    letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--sc-accent);
    margin-block-end: 4px;
  }
  .move__list li.is-bonus::before { content: "Bonus"; }
  .move__list h3 { font-family: var(--tta-font-work); font-size: 1rem; font-weight: 600; color: var(--sc-ink); }
  .move__list p { font-size: 0.85rem; line-height: 1.5; color: var(--sc-ink-soft); margin-block-start: 3px; }

  /* The pinned stage cannot hold a board and eight open rows at once, so the
     act stops pinning and becomes an ordinary section. */
  .act--move { height: auto !important; }
  .act--move .move { display: block; height: auto !important; position: static !important; }
  .act--move .move__wrap { max-height: none; padding-block: var(--sc-8); }
  .act--move .move__board { min-height: 42vh; }
}
