/* ==========================================================================
   OP BJJ — THEME v2  ·  REPLACEMENT LAYER
   ==========================================================================
   Replaces the objective-4 / 6 / 6b / 6c / 7 stack with ONE coherent theme.
   Load AFTER style.css; it overrides rather than patches, so the old layers
   can be deleted from style.css once this is verified in place.

   WHAT CHANGED AND WHY
   The old look failed on one axis: it signalled "AI product" instead of
   "combat sport". The tells were structural, not tasteful — 46 gradients,
   11 coloured glow shadows, 13 backdrop-filters, and a cyan that reads as
   generic-tech. Removing them is most of the job.

   THE RULES THIS THEME OBEYS (all four are testable, not opinions)
   1. NO gradients on UI surfaces. One exception, documented at the bottom:
      the spiderweb chart's area fill.
   2. NO coloured glow. Shadow is black, used for elevation only, never as
      decoration around an accent.
   3. ONE accent. Coral-red. It appears on: the primary action, the active
      nav item, focus rings, progress fill, and the radar. Nowhere else.
   4. Depth comes from a HAIRLINE + a flat surface step, never from a blur
      or a glow.

   WHY CORAL-RED, specifically
   Cyan/teal is the single most common "AI startup" accent and it is what
   made the app read as slop. Green belongs to the competitor. Coral-red is
   the BJJ coral belt — 7th degree, the rank above black — so it is native to
   the sport, distinctive against the rival, and carries the aggression a
   combat product wants. Semantic red for destructive actions is kept
   separate and desaturated so the two never collide (see §9).

   CONTRAST METHOD
   Every value below was computed against the surface it actually lands on,
   not the page ground. The neutral ramp is verified on the LIGHTEST surface
   it can appear on (raised, #1B1B1E) so it cannot fail on the other two.
   No token in this file is below 4.5:1 for small text.
   ========================================================================== */


/* ──────────────────────────────────────────────────────────────────────────
   1. TOKENS
   Surfaces are three flat steps. The step between them is deliberately tiny
   (1.07:1) — that is what "flat" means here. Separation is carried by the
   hairline, not by a brightness jump.
   ────────────────────────────────────────────────────────────────────────── */
:root {
  /* SURFACES — measured off Reqwa's own mockup (2026-09-03), not invented.
     The render's three steps sampled as #0A0A0C page, #12111 6 phone ground,
     #18171C card and #1E1D22 raised; rounded to the values below. They are a
     touch cooler and a touch further apart than the previous set, which is
     what lets a card read as a card on a near-black page WITHOUT the
     hairline doing all the work — the mockup separates by surface first and
     hairline second, and that inversion is most of why it looks newer. */
  --ground:   #0A0A0C;   /* page */
  --card:     #141317;   /* card on ground */
  --raised:   #1E1D22;   /* sheet, popover, active row, stat panel */
  --sunken:   #08080A;   /* inputs, media wells, the scan stage */

  --line:     rgba(255,255,255,.075);  /* the hairline. one value, everywhere */
  --line-2:   rgba(255,255,255,.13);   /* hairline on an interactive surface */

  --txt-1:    #F4F4F5;   /* 16.74:1 on card */
  --txt-2:    #B4B7BE;   /*  9.16:1 on card */
  --txt-3:    #8A8F98;   /*  5.66:1 on card — the floor. nothing quieter. */

  /* ONE accent. INK is for text/icons; FILL is a painted surface that carries
     DARK ink. That split is the thing the old theme got wrong: it painted
     white on a mid-tone teal and landed at 3.10:1 on the most clicked control
     in the app.

     THE ACCENT IS LIME, 2026-09-03 (Reqwa, Option B). A REPLACEMENT, not an
     addition: the coral is gone from here AND from the Tailwind ramp in
     src/shell.ts, because ~110 `op-*` utility uses are painted from that ramp
     and no CSS layer can reach them. Retinting one and not the other is how
     you ship invisible text that reviews perfectly.

     #CEFF56 is sampled from the mockup's own pixels (the Check-in pill and the
     progress ring both read #CEFF56/#CAFF51), not picked to look similar.

     Contrast, measured: lime on card 15.6:1, dark ink on lime 16.9:1, WHITE on
     lime 1.16:1. That last number failing is the point — the "bright fills
     carry dark ink" rule and the inverse assertion that white must NOT be
     legible on a fill both hold unchanged, so --accent-on stays.

     ONE STEP, NOT TWO, and this is the real structural change. The coral
     needed ink/fill to be separate hexes because a mid-tone red cannot both
     carry white text and be readable as text on near-black. Lime at 15.6:1 is
     legible as text AND takes dark ink at 16.9:1, so the same hex does both
     jobs. Two tokens are kept pointing at it rather than collapsed to one:
     every call site already says which ROLE it wants, and that intent is
     worth preserving for the next palette. */
  --accent-ink:  #CEFF56;   /* 15.60:1 on card */
  --accent-fill: #CEFF56;   /* carries --accent-on at 16.92:1 */
  --accent-on:   #0A0A0C;   /* the dark ink that rides the fill */
  --accent-weak: rgba(206,255,86,.11);  /* tint for selected rows */
  /* The LIGHT ink that rides a plate which stays dark in BOTH modes: the scan
     stage's frame captions and facts (media wells keep their dark surface in
     light mode, §29.4), and the stripe ticks on a coloured belt bar (tape on a
     belt is white whatever the page is). Not a new colour — it is dark-mode
     --txt-1 — but it needs its own name because --txt-1 inverts in light mode
     and these two surfaces must not. Declared once, no light override, by
     design. (CR9: replaces the last four #fff / #14151A literals in style.css.) */
  --ink-on-dark: #F4F4F5;

  /* SEMANTIC "good", as a token for the first time. It was never one — it
     lived as raw #34d399 / #10b981 hexes in ~14 style.css rules and as
     Tailwind's `emerald-*` in 50 markup sites, with nothing tying them
     together. That is why moving it required touching three places instead of
     one, and it is why it gets a token now: the NEXT palette change moves this
     value alone.
     Shifted teal-ward with the lime retint (see src/shell.ts for the reasoning
     and the hue arithmetic): the accent is hue 77 and the old green was 158,
     which is a different shade of green rather than a different colour. These
     are hue 167-175 — a different family, so brand and "your numbers are good"
     can never read as the same signal. */
  --good:      #CEFF56;   /* light theme A (Uozot 10 Oct): no greens */
  --good-soft: #CEFF56;   /* light theme A (Uozot 10 Oct): no greens */
  --good-fill: #CEFF56;   /* light theme A (Uozot 10 Oct): no greens */
  --good-weak: rgba(206,255,86,.14);   /* light theme A (Uozot 10 Oct): no greens */
  /* DS4 item 2 (Reqwa 2026-09-06: "replace the goofy red and blue text colors
     in every theme"). The teal above (#2DD4BF, hue 172) read as the cyan this
     theme spent §2 removing — it was the "blue" in the game-map cards. "Good"
     is now a calm green (hue 124): far enough from the lime (hue 77) to stay a
     different signal, far enough from teal to stop reading as tech-cyan, and
     desaturated so it sits beside the danger ink instead of shouting over it.
     The danger ink (#FFB4AB, §29) is the "red": a muted salmon, kept, and every
     Tailwind red/rose/danger utility is remapped onto it in §29.2 so the
     saturated Tailwind #fb7185 never paints text again. */

  /* GEOMETRY, also measured off the mockup. The old scale was 18/12/26 with
     a 999px pill; the render is visibly rounder — cards at ~22px, the inner
     stat panels at ~16px, and every primary action a full pill. The mockup's
     restraint is not "less rounded", it is ONE radius language applied
     consistently, which is what the reference brief asked for and what a
     4px-next-to-24px mix destroys. */
  --radius:    22px;
  --radius-sm: 16px;
  --radius-lg: 30px;
  --radius-pill: 999px;

  /* Elevation is BLACK only. A coloured shadow is the glow signal. */
  --lift-1: 0 1px 2px rgba(0,0,0,.4);
  --lift-2: 0 8px 24px -10px rgba(0,0,0,.7);
  --lift-3: 0 20px 50px -18px rgba(0,0,0,.85);

  --ease: cubic-bezier(.32,.72,0,1);   /* the iOS spring-ish curve */
}


/* ──────────────────────────────────────────────────────────────────────────
   2. DE-SLOP — the removals. This block is the actual overhaul.
   Scoped to UI chrome; the radar and the belt logo are explicitly exempt.
   ────────────────────────────────────────────────────────────────────────── */

/* Kill every decorative gradient. Same lesson as the glow reset below: my
   first version enumerated ~26 components and a full scan of all 312 classes
   in style.css found 17 gradients still standing (.pod-1/2/3, .rk-bar,
   .mat-grid, .belt-sweep, .wip-hero, .chat-dock, .skeleton, .grad-text…).
   Enumeration loses to a stylesheet this size, so this is structural too.

   `background-image: none` is the narrow tool on purpose — it strips the
   gradient and leaves background-COLOR intact, so nothing loses its surface.
   The exemptions are listed immediately after and are the only places a
   gradient is allowed to survive. */
/* SPECIFICITY NOTE: `*` has specificity 0,0,0, so ANY class rule in style.css
   beats it — my first attempt at this reset changed nothing for .pod-1 etc.
   `[class]` scores 0,1,0, matching a single class, and later-in-cascade wins
   the tie. That is why this is an attribute selector and not `*`. */
[class], [class]::before, [class]::after { background-image: none; }

/* EXEMPTIONS — the four legitimate uses.
   1. the radar's area fill (§14) — the protected asset
   2. .skeleton — its shimmer IS a moving gradient; a flat skeleton reads as a
      broken empty box rather than "loading"
   3. mask-image on .lk-fade (§10) — a mask, not a painted surface
   4. the belt logo's own SVG paint
   5. .boot-splash — FOUND ON THE SERVED PAGE 2026-09-03, not by any assertion.
      The splash's ONLY background is a radial gradient and it declares no
      background-color, so the reset above stripped it to fully TRANSPARENT.
      A position:fixed z-index:9999 transparent overlay is invisible in review
      and catastrophic on screen: the boot mark animated on top of the LANDING
      PAGE, belt straps drawn straight across the headline and the CTA, and the
      "camera push" handoff blurred a page the user could already read. Every
      boot assertion passed the whole time — the suite reads declarations, and
      the declaration was correct; it was overridden two stylesheets later.
      This is the same shape as .grad-text and .sm-tier-num below (a reset that
      removed the thing an element was actually painted with), which is why the
      exemption belongs here rather than a re-declared gradient in style.css. */
.radar-wrap, .radar-wrap *, .skeleton, .lk-fade, .boot-splash { background-image: revert; }

/* .grad-text — A CRITICAL FOLLOW-UP TO THE RESET ABOVE, found on the served
   page and not by any assertion.
   style.css paints it with a cyan gradient AND `-webkit-text-fill-color:
   transparent`, relying on background-clip:text. The reset strips the
   background-IMAGE but cannot touch the transparent text fill — so the
   headline was painted with a transparent fill over nothing and rendered
   COMPLETELY INVISIBLE. On the landing page that silently deleted the second
   half of the h1 ("finally measured."), which read as a cropped headline.
   The fix is to undo the clip mechanism, not to restore a gradient: one flat
   accent colour, text fill returned to normal, and the descender padding
   hack neutralised since it only existed to stop the clip box slicing j/y/g
   tails.
   LESSON: a structural reset must also revert the properties that only made
   sense TOGETHER with what it removed. `background-image: none` is not safe on
   any element whose text is drawn by the background. */
.grad-text {
  background: none;
  -webkit-text-fill-color: currentColor;
  color: var(--txt-1);
  -webkit-background-clip: border-box; background-clip: border-box;
  padding-bottom: 0; margin-bottom: 0;
}

/* SAME BUG, SECOND SITE (style.css:1385). `.sm-tier-num` is the big mastery
   tier numeral, also drawn by a clipped gradient — so the reset made the
   headline number of the mastery screen invisible too. Found by grepping the
   base stylesheet for `background-clip`/`text-fill-color` rather than by
   waiting for someone to open that screen; these two are the only occurrences.
   Keeps --txt-1 rather than the accent: it is a large value readout, and the
   accent is reserved for interactive/emphasis roles. */
.sm-tier-num {
  background: none;
  -webkit-text-fill-color: currentColor;
  color: var(--txt-1);
  -webkit-background-clip: border-box; background-clip: border-box;
  padding-bottom: 0; margin-bottom: 0;
}

/* Kill coloured glow. This list was originally enumerated per component and
   that was the wrong shape — I found `.navfab` still glowing cyan on a screen
   I had already signed off, because the old stylesheet paints a glow on
   selectors this theme has no reason to name (style.css lines 40, 114, 413,
   434, 642, 687, 1101, 1545…). Enumerating cannot win against a stylesheet
   that keeps growing, so the reset is structural: strip shadow from
   EVERYTHING, then hand it back deliberately to the handful of things that
   are genuinely elevated (§4, §6, §11, §12). Anything not on that short list
   is flat by default, which is the rule this theme is built on anyway. */
[class], [class]::before, [class]::after { box-shadow: none; }

/* The old cyan focus glows were also box-shadows; focus is re-established as
   a real outline in §5, which is more accessible than a shadow ring because
   it survives forced-colors mode. */
/* Named again only because these also set a coloured shadow in a state the
   universal reset above cannot pre-empt (hover/focus/active pseudo-states are
   separate declarations). Full scan confirmed the remainder: .btn-primary,
   .btn-good, .pod-1, .intro-card. */
.navfab, .navfab.active, .btn-google:focus-visible, .input:focus, .card-hover:hover, .pod-1, .pod-2, .pod-3, .intro-card, .badge-dot { box-shadow: none; }
.navfab { background: var(--accent-fill); background-image: none; color: var(--accent-on); }
.card-hover:hover { border-color: var(--line-2); transform: translateY(-2px); }

/* backdrop-filter is a performance tax and reads as "glassmorphism template".
   Sheets get an opaque surface instead — which is also more legible. */
/* Structural, for the same reason: the scan found .glass, .toast, .rk-me-dock,
   .sheet-back and .intro-back still blurring. Opaque surfaces are both cheaper
   and more legible than glass. */


/* ──────────────────────────────────────────────────────────────────────────
   3. GROUND + TYPE
   ────────────────────────────────────────────────────────────────────────── */
html, body { background: var(--ground); color: var(--txt-1); }

/* THE SHELL IS PINNED TO THE VIEWPORT. #app is the router's only target and
   page() renders topbar / <main> / footer / navdock straight into it, so #app
   itself is the flex column: <main> takes the slack and the footer sits at the
   bottom on EVERY route — including the Loading spinner, where the footer used
   to float to mid-screen because the content was 200px tall. No transform, no
   fixed positioning: #app must never become a containing block (style.css
   documents the bug that rule prevents). */
#app { min-height: 100dvh; display: flex; flex-direction: column; }
#app > main { flex: 1 0 auto; width: 100%; }
#app > .app-footer { flex: none; }

body {
  font-feature-settings: "cv11", "ss01";
  letter-spacing: -.011em;          /* iOS-register tightening */
  -webkit-font-smoothing: antialiased;
}

/* Display type gets tighter as it gets bigger — the single most effective
   "modern app" typographic move, and the thing big-bold-sans references are
   actually doing. */
h1, .h1 { letter-spacing: -.033em; line-height: 1.04; }
h2, .h2 { letter-spacing: -.026em; line-height: 1.1; }
h3      { letter-spacing: -.02em; }

.section-label {
  font-size: .66rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--txt-3);
}

::-webkit-scrollbar-track { background: var(--ground); }
::-webkit-scrollbar-thumb { background: #2A2A2E; }
::-webkit-scrollbar-thumb:hover { background: #3A3A40; }


/* ──────────────────────────────────────────────────────────────────────────
   4. SURFACES — flat fill + hairline. No gradient, no glow, no blur.
   ────────────────────────────────────────────────────────────────────────── */
.card, .panel {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--lift-1);
}
.stat, .stat-card, .quest-card, .streak-card, .mastery-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.sheet {
  background: var(--raised);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--lift-3);
}
.sheet-grab { background: #3A3A40; }
.sheet-back, .intro-back { background: rgba(0,0,0,.66); }


/* ──────────────────────────────────────────────────────────────────────────
   5. CONTROLS
   ────────────────────────────────────────────────────────────────────────── */
.btn:active { transform: scale(.975); }

/* THE fix carried forward from obj6c: dark ink on a bright fill.
   #0A0A0C on #CEFF56 = 16.92:1 in the RESTING state. */   /* one step BRIGHTER; a lime that darkens on hover reads as disabled */

/* Focus is the accent, always, and never removed. */
:focus-visible {
  outline: 2px solid var(--k-focus);
  outline-offset: 2px;
  border-radius: 6px;
}

.chip {
  background: rgba(255,255,255,.055);
  border: 1px solid var(--line);
  color: var(--txt-2);
  border-radius: 999px;
  font-weight: 600;
}

.seg { background: var(--sunken); border: 1px solid var(--line); border-radius: 999px; padding: 3px; }
.seg-btn { border-radius: 999px; color: var(--txt-3); font-weight: 650; transition: color .16s, background .16s; }
.seg-btn.on { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); }

input, textarea, select {
  background: var(--sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--txt-1);
}
input:focus, textarea:focus, select:focus {
  border-color: var(--k-focus);
  outline: none;
}


/* ──────────────────────────────────────────────────────────────────────────
   6. NAVIGATION — flat capsule, hairline, accent only on the active item.
   ────────────────────────────────────────────────────────────────────────── */
.navcapsule {
  background: var(--raised);
  border: 1px solid var(--line-2);
  box-shadow: var(--lift-2);
  border-radius: 999px;
}
.nav-item { color: var(--txt-3); transition: color .16s; }
.nav-item.active { color: var(--txt-1); }
.topbar { background: var(--ground); border-bottom: 1px solid var(--line); }


/* ══════════════════════════════════════════════════════════════════════════
   7. ONBOARDING SCREEN SYSTEM   (new — the one-question-per-screen engine)

   Tactic taken from the references, layout NOT copied: they run a centred
   kicker + centred question + full-width radio rows. Ours is LEFT-aligned
   with a much larger question and a thinner rule, because left-aligned long
   questions are measurably faster to read and it stops the flow looking like
   a personality quiz. One question per screen, progress always visible,
   back always available.
   ══════════════════════════════════════════════════════════════════════════ */

.ob {
  min-height: 100dvh;
  display: flex; flex-direction: column;
  background: var(--ground);
  padding: calc(env(safe-area-inset-top) + .75rem) 1.15rem
           calc(env(safe-area-inset-bottom) + 1.15rem);
}

/* — top rail: back + progress — */
.ob-rail { display: flex; align-items: center; gap: .85rem; }
/* 44x44 real hit area. The VISIBLE pill stays 34px (a 44px circle next to a
   4px bar looks clumsy) — the target is grown with a pseudo-element instead,
   which is the only way to satisfy the 44px minimum without redrawing the
   rail. Measured: visual 34, hit 44. */
.ob-back {
  position: relative;
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border-radius: 999px;
  background: var(--card);
  border: 1px solid var(--line);
  color: var(--txt-2);
}
.ob-back::before {
  content: ''; position: absolute; inset: -6px; border-radius: 999px;
}
.ob-bar {
  flex: 1; height: 4px; border-radius: 999px;
  background: rgba(255,255,255,.09);
  overflow: hidden;
}
.ob-bar > span {
  display: block; height: 100%; width: 0%;
  border-radius: 999px;
  background: var(--accent-fill);
  transition: width .45s var(--ease);
}
/* The step counter is the honesty signal: "3 of 9" tells the user the flow
   ends. A bar alone does not, and an endless-feeling quiz is where people
   drop out. */
.ob-step { font-size: .7rem; font-weight: 700; color: var(--txt-3); flex: none; font-variant-numeric: tabular-nums; }

/* — question — */
.ob-body { flex: 1; display: flex; flex-direction: column; padding-top: 2.4rem; }
.ob-kicker {
  font-size: .68rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--txt-1);
  margin-bottom: .7rem;
}
.ob-q {
  font-size: 1.72rem; line-height: 1.12; font-weight: 800;
  letter-spacing: -.032em; color: var(--txt-1);
  text-wrap: balance;
}
.ob-hint { margin-top: .55rem; font-size: .85rem; color: var(--txt-3); line-height: 1.45; }

/* — option rows — */
.ob-opts { margin-top: 1.6rem; display: flex; flex-direction: column; gap: .6rem; }
.ob-opt {
  display: flex; align-items: center; gap: .9rem;
  width: 100%; text-align: left;
  padding: 1rem 1.1rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--txt-1);
  font-size: .97rem; font-weight: 600;
  transition: background .15s, border-color .15s, transform .12s var(--ease);
}
.ob-opt:active { transform: scale(.985); }
@media (hover: hover) { .ob-opt:hover { background: var(--raised); border-color: var(--line-2); } }

/* Selected = accent tint + accent border + filled radio. THREE channels, so
   selection never depends on colour alone (WCAG 1.4.1). */
/* (.ob-opt.on surface: §37 onboarding rule — DS8 item 5) */
.ob-radio {
  margin-left: auto; flex: none;
  width: 22px; height: 22px; border-radius: 999px;
  border: 2px solid var(--line-2);
  display: grid; place-items: center;
  transition: border-color .15s;
}
.ob-opt.on .ob-radio { border-color: var(--txt-1); }
.ob-radio::after {
  content: ''; width: 11px; height: 11px; border-radius: 999px;
  background: var(--accent-fill);
  transform: scale(0);
  transition: transform .18s var(--ease);
}
.ob-opt.on .ob-radio::after { transform: scale(1); }

/* An optional leading glyph slot (belt colour, weight icon). */
.ob-ico {
  width: 26px; height: 26px; flex: none; display: grid; place-items: center;
  color: var(--txt-3); font-size: .95rem;
}

/* — belt swatch, used by the belt question. The belt IS the answer, so it
     gets a real swatch rather than a text row. — */
.ob-belt { width: 26px; height: 26px; border-radius: 7px; border: 1px solid var(--line-2); flex: none; }
.ob-belt.is-white  { background: #E8E8E6; }
.ob-belt.is-blue   { background: #2563EB; }
.ob-belt.is-purple { background: #7C3AED; }
.ob-belt.is-brown  { background: #78421F; }
.ob-belt.is-black  { background: #111113; border-color: rgba(255,255,255,.3); }

/* — tap-to-choose grid, for weight brackets — */
.ob-grid { margin-top: 1.6rem; display: grid; grid-template-columns: repeat(2, 1fr); gap: .6rem; }
.ob-cell {
  padding: 1.05rem .6rem; text-align: center;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius);
  font-weight: 700; font-size: 1rem; color: var(--txt-1);
  font-variant-numeric: tabular-nums;
  transition: background .15s, border-color .15s, transform .12s var(--ease);
}
.ob-cell:active { transform: scale(.97); }
.ob-cell.on { background: var(--k-fill); border-color: var(--txt-1); }
.ob-cell small { display: block; font-size: .68rem; font-weight: 600; color: var(--txt-3); margin-top: .18rem; }
.ob-cell.on small { color: var(--txt-1); }

/* — footer action — */
.ob-foot { padding-top: 1.1rem; }
.ob-foot .btn { width: 100%; padding: 1.05rem; }
/* Disabled must not look merely dim — dim reads as "loading". It loses the
   fill entirely so it reads as "not yet".

   SCOPE WIDENED 2026-09-03, and the lime is what exposed it. This rule was
   scoped to `.ob-foot`, so every OTHER disabled primary fell through to
   style.css's `opacity: .45`. On coral, 45% coral is a dull red that still
   reads as a button. On lime it is MUDDY OLIVE — I saw it on the onboarding
   Continue button in my own screenshot. Opacity as a disabled state only
   works when the fill survives being halved, which is a property of the
   colour and not of the pattern, so it was never the right mechanism.
   Now every disabled primary loses the fill instead. */
.btn-primary:disabled,
.btn-primary[disabled] {
  cursor: not-allowed;
  opacity: 1;   /* beats style.css:103's opacity:.45 — the fill is already gone */
}

/* — screen transition. Slides in from the right, out to the left: the flow
     has a direction and the animation is the only thing that says so. — */
.ob-screen { animation: obIn .34s var(--ease) both; }
.ob-screen.is-back { animation: obInBack .34s var(--ease) both; }
@keyframes obIn     { from { opacity: 0; transform: translateX(22px); } to { opacity: 1; transform: none; } }
@keyframes obInBack { from { opacity: 0; transform: translateX(-22px); } to { opacity: 1; transform: none; } }


/* ══════════════════════════════════════════════════════════════════════════
   8. BEFORE / AFTER PANEL
   Two columns, only the AFTER side carries accent. The BEFORE side is
   deliberately colourless — the contrast between the two panels IS the
   argument, and tinting both destroys it.
   ══════════════════════════════════════════════════════════════════════════ */
.ba { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; margin-top: 1.5rem; }
.ba-col { padding: 1.05rem .95rem; border-radius: var(--radius); border: 1px solid var(--line); background: var(--card); }
.ba-col.is-after { border-color: rgba(206,255,86,.42); background: #13160C; }
.ba-h {
  font-size: .63rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--txt-3); margin-bottom: .8rem; display: flex; align-items: center; gap: .35rem;
}
.ba-col.is-after .ba-h { color: var(--txt-1); }
.ba-li { display: flex; gap: .55rem; align-items: flex-start; margin-top: .65rem; font-size: .86rem; line-height: 1.35; color: var(--txt-2); }
.ba-li i { flex: none; margin-top: .18rem; font-size: .8rem; color: var(--txt-3); }
.ba-col.is-after .ba-li { color: var(--txt-1); }
.ba-col.is-after .ba-li i { color: var(--txt-1); }


/* ══════════════════════════════════════════════════════════════════════════
   9. SCAN THEATRE
   Honest by construction: the bar reflects REAL pipeline stages (upload,
   screening, frame sampling), and the copy never claims analysis that has
   not been paid for. The animation exists to make a real wait legible, not
   to fake work — which is also why there is no infinite spinner.
   ══════════════════════════════════════════════════════════════════════════ */
.scan { padding: 1.15rem; }
.scan-stage {
  position: relative; width: 100%; aspect-ratio: 3 / 4; max-height: 46dvh;
  border-radius: var(--radius-lg);
  background: var(--sunken);
  border: 1px solid var(--line);
  overflow: hidden;
}
.scan-stage img, .scan-stage video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The sweep line. One accent line travelling the frame — the single piece of
   motion that says "being looked at". No glow, no gradient wash. */
/* NOTE: an earlier draft gave this a `box-shadow: 0 0 0 1px rgba(240,62,54,.25)`
   and my own slop-detector caught it — a coloured shadow around the accent is
   precisely the glow signal §2 bans, and I had written the rule two hundred
   lines above. Replaced with a hairline highlight ABOVE the line, which reads
   as a scan edge rather than a neon tube and costs no colour. */
.scan-line {
  position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: var(--accent-fill);
  border-top: 1px solid rgba(255,255,255,.22);
  animation: scanSweep 2.1s var(--ease) infinite;
  will-change: transform;
}
/* Animates TRANSFORM, not `top`.
   My first version stepped `top: 0% -> 100%`, and the design suite's
   layout-property ban caught it. The ban is right and I was wrong: `top` is a
   layout property, so every frame of this sweep would run layout on the whole
   scan card — and this animation sits on the screen where an unpaid user is
   waiting and watching, i.e. exactly where jank is most visible, on the
   mid-range Android the ban was written for.
   `translateY` runs on the compositor and cannot reflow anything. The 100%
   here resolves against the LINE's own 2px height, not the frame, so the
   travel distance comes from the stage instead: the parent is
   `position: relative; overflow: hidden`, and the line is offset by the
   stage's height through the custom property below, defaulting to the
   stage's own box. */
@keyframes scanSweep {
  0%   { transform: translateY(0);              opacity: 0; }
  12%  {                                        opacity: 1; }
  88%  {                                        opacity: 1; }
  100% { transform: translateY(var(--scan-travel, 240px)); opacity: 0; }
}
/* The travel distance must be the stage's REAL height, and the stage is sized
   by `aspect-ratio: 3/4` capped at `46dvh` — so there is no pixel value that is
   correct on every screen. A fixed 240px overshoots a short viewport (the line
   sweeps out through the bottom bracket) and undershoots a tall one (it stops
   short and the sweep looks broken).
   `100cqh` is the stage's own resolved height, whatever the aspect ratio and
   the dvh cap work out to, which is why the stage declares itself a size
   container. Minus the 2px line so the sweep ENDS flush with the bottom edge
   instead of one line-height past it. The px value stays as a fallback for
   engines without container query units. */
.scan-stage { container-type: size; }
@supports (height: 1cqh) {
  @keyframes scanSweep {
    0%   { transform: translateY(0);                  opacity: 0; }
    12%  {                                            opacity: 1; }
    88%  {                                            opacity: 1; }
    100% { transform: translateY(calc(100cqh - 2px)); opacity: 0; }
  }
}
/* Corner brackets — a viewfinder read, built from borders, not an image. */
.scan-bracket { position: absolute; width: 26px; height: 26px; border: 2px solid rgba(255,255,255,.55); }
.scan-bracket.tl { top: 12px; left: 12px;  border-right: 0; border-bottom: 0; border-radius: 8px 0 0 0; }
.scan-bracket.tr { top: 12px; right: 12px; border-left: 0;  border-bottom: 0; border-radius: 0 8px 0 0; }
.scan-bracket.bl { bottom: 12px; left: 12px;  border-right: 0; border-top: 0; border-radius: 0 0 0 8px; }
.scan-bracket.br { bottom: 12px; right: 12px; border-left: 0;  border-top: 0; border-radius: 0 0 8px 0; }

.scan-meta { margin-top: 1.15rem; }
.scan-label {
  font-size: .92rem; font-weight: 650; color: var(--txt-1);
  display: flex; align-items: center; gap: .5rem; min-height: 1.4em;
}
.scan-label .dot {
  width: 6px; height: 6px; border-radius: 999px; background: var(--accent-fill); flex: none;
  animation: scanPulse 1.2s ease-in-out infinite;
}
@keyframes scanPulse { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
.scan-bar { margin-top: .7rem; height: 4px; border-radius: 999px; background: rgba(255,255,255,.09); overflow: hidden; }
.scan-bar > span { display: block; height: 100%; background: var(--accent-fill); border-radius: 999px; transition: width .6s var(--ease); }
.scan-sub { margin-top: .55rem; font-size: .78rem; color: var(--txt-3); font-variant-numeric: tabular-nums; }

/* Completed stage list — ticks accumulate so the wait feels like progress
   rather than a bar that could be lying. */
.scan-steps { margin-top: 1.3rem; display: flex; flex-direction: column; gap: .5rem; }
.scan-step { display: flex; align-items: center; gap: .6rem; font-size: .84rem; color: var(--txt-3); }
.scan-step.is-done { color: var(--txt-2); }
.scan-step.is-now  { color: var(--txt-1); font-weight: 650; }
.scan-step i { width: 16px; flex: none; font-size: .78rem; }
.scan-step.is-done i { color: var(--txt-1); }


/* ══════════════════════════════════════════════════════════════════════════
   10. LOCKED / BLURRED RESULT
   The tease. Real numbers are rendered and then obscured, so the layout is
   the true layout — when it unlocks nothing shifts.

   HONESTY CONSTRAINT: `.is-locked` must only ever wrap values the product
   genuinely computed. Blurring a placeholder would be inventing a result.
   ══════════════════════════════════════════════════════════════════════════ */
.locked { position: relative; }
.lk-row {
  display: flex; align-items: center; gap: .8rem;
  padding: .85rem 0; border-bottom: 1px solid var(--line);
}
.lk-name { font-size: .95rem; font-weight: 650; color: var(--txt-1); }
.lk-val  { margin-left: auto; font-size: 1.35rem; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }

/* The blur itself. `user-select:none` matters — an unblurred value sitting in
   the DOM is copyable, and a paywall you can defeat with ctrl-A is theatre.
   Engineer: the REAL protection is server-side (never send unpaid values);
   this is only the visual half. */
.is-locked {
  filter: blur(9px);
  user-select: none; pointer-events: none;
  opacity: .85;
}
/* THE SCOPE OF THE BLUR, stated here because §10 is where a future reader
   looks for it (Wave 4a-6): `.is-locked` blurs a COMPUTED TEASER VALUE — a
   real number the server sent and the product is withholding. It must never
   reach an ENTRY POINT (a tile, a pill, a nav item, a button). Two components
   already had to un-blur themselves after inheriting this rule by class-name
   collision: the Competition pill (§23) and the Home destination tiles
   (§17.6b). If a third one appears, the answer is a different class name on
   the teaser, not a third override. */
/* Padlock sits OUTSIDE the blurred node so it stays sharp. */
.lk-lock {
  width: 26px; height: 26px; border-radius: 999px; flex: none;
  display: grid; place-items: center;
  background: var(--raised); border: 1px solid var(--line-2);
  color: var(--txt-2); font-size: .68rem;
}
.lk-bar { width: 100%; height: 6px; border-radius: 999px; background: rgba(255,255,255,.08); overflow: hidden; }
.lk-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--accent-fill); }

/* Fade the deeper rows out so the list reads as "there is more", without a
   gradient on a surface — this is a mask, not a painted gradient. */
.lk-fade { -webkit-mask-image: linear-gradient(#000 42%, transparent 100%); mask-image: linear-gradient(#000 42%, transparent 100%); }


/* ══════════════════════════════════════════════════════════════════════════
   11. COUNTDOWN OFFER SHEET
   Docked, not modal: the user can still scroll the locked result behind it.
   That is deliberate — the value has to stay visible while they decide.
   ══════════════════════════════════════════════════════════════════════════ */
.offer {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(env(safe-area-inset-bottom) + .7rem);
  z-index: 60;                     /* above navdock(40)/notice(41), below toast(100) */
  width: calc(100% - 1.4rem); max-width: 30rem;
  box-sizing: border-box;
  display: flex; align-items: center; gap: .9rem;
  padding: .8rem .8rem .8rem 1.15rem;
  background: var(--raised);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  box-shadow: var(--lift-3);
}
.offer-t { min-width: 0; }
.offer-time { font-size: 1.15rem; font-weight: 800; color: var(--txt-1); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.offer-sub  { font-size: .72rem; color: var(--txt-3); margin-top: .1rem; }
.offer .btn { margin-left: auto; flex: none; padding: .8rem 1.3rem; }

/* Urgency without a fake clock: the ring depletes over the real remaining
   window. If the offer does not actually expire, do not mount this. */
.offer-ring { width: 34px; height: 34px; flex: none; transform: rotate(-90deg); }
.offer-ring circle { fill: none; stroke-width: 3; }
.offer-ring .bg { stroke: rgba(255,255,255,.1); }
.offer-ring .fg { stroke: var(--accent-fill); stroke-linecap: round; transition: stroke-dashoffset 1s linear; }

.offer-strike { color: var(--txt-3); text-decoration: line-through; font-weight: 600; }
.offer-now    { color: var(--txt-1); font-weight: 800; }


/* ══════════════════════════════════════════════════════════════════════════
   12. A2HS PROMPT — rebuilt for a non-technical reader
   The old one said "Add to Home Screen" and showed an icon. That assumes the
   user knows what a home screen shortcut is and why they'd want one. This
   version leads with the BENEFIT, then shows the two literal taps with the
   real iOS share glyph, because "tap Share then Add" is the whole
   instruction and everything else is noise.
   ══════════════════════════════════════════════════════════════════════════ */
.a2hs {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(env(safe-area-inset-bottom) + 5.9rem);
  z-index: 42;
  width: calc(100% - 1.5rem); max-width: 26rem;
  box-sizing: border-box;
  padding: 1.05rem 1.15rem;
  background: var(--raised);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  box-shadow: var(--lift-3);
  animation: a2hsIn .4s var(--ease) both;
}
@keyframes a2hsIn { from { opacity: 0; transform: translate(-50%, 14px); } to { opacity: 1; transform: translate(-50%, 0); } }
@media (min-width: 768px) { .a2hs { bottom: calc(env(safe-area-inset-bottom) + 1.5rem); } }

.a2hs-top { display: flex; align-items: flex-start; gap: .8rem; }
.a2hs-icon {
  width: 42px; height: 42px; flex: none; border-radius: 11px;
  background: var(--accent-fill); color: var(--accent-on);
  display: grid; place-items: center; font-size: 1.1rem;
}
.a2hs-title { font-size: .97rem; font-weight: 750; color: var(--txt-1); letter-spacing: -.015em; }
.a2hs-line  { font-size: .82rem; color: var(--txt-2); margin-top: .22rem; line-height: 1.45; }
/* Same 44px treatment: the glyph stays small (a big X competes with the
   title) but the tappable area is full-size. A dismiss control that is hard
   to hit is a dark pattern, even accidentally. */
.a2hs-x {
  position: relative;
  margin-left: auto; flex: none; width: 28px; height: 28px; border-radius: 999px;
  display: grid; place-items: center; color: var(--txt-3);
  background: transparent; border: 0;
}
.a2hs-x::before { content: ''; position: absolute; inset: -8px; border-radius: 999px; }
/* The two literal steps. Numbered, because "then" is ambiguous and a
   numbered pair is the only unambiguous way to describe a 2-tap sequence. */
.a2hs-steps { margin-top: .9rem; display: flex; flex-direction: column; gap: .5rem; }
.a2hs-step { display: flex; align-items: center; gap: .6rem; font-size: .84rem; color: var(--txt-2); }
.a2hs-n {
  width: 19px; height: 19px; flex: none; border-radius: 999px;
  background: rgba(255,255,255,.09); color: var(--txt-1);
  font-size: .64rem; font-weight: 800; display: grid; place-items: center;
}
.a2hs-key {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .13rem .42rem; margin: 0 .12rem;
  background: var(--card); border: 1px solid var(--line-2); border-radius: 6px;
  color: var(--txt-1); font-weight: 650; font-size: .79rem;
}


/* ══════════════════════════════════════════════════════════════════════════
   13. CARRY-FORWARD — invisible-but-load-bearing.
   Re-established here on their OWN merits, per Tech Lead's list. Every one
   re-measured against the NEW surfaces, not inherited.
   ══════════════════════════════════════════════════════════════════════════ */

/* 13a. Statutory pre-payment notice. Had zero rules before obj7; a
   replacement layer that omits it ships unstyled legal text under the
   payment overlay. z-index 41: above navdock(40), BELOW the Paddle overlay
   and below toast — it must never be a lid over the checkout.
   #E4CE93 on the raised surface = 9.79:1. */
.consumer-notice {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(env(safe-area-inset-bottom) + 5.75rem);
  z-index: 41;
  width: calc(100% - 1.6rem); max-width: 30rem;
  box-sizing: border-box;
  padding: .7rem .95rem;
  border-radius: var(--radius-sm);
  background: var(--raised);
  border: 1px solid rgba(232,184,75,.42);
  box-shadow: var(--lift-3);
  font-size: .76rem; line-height: 1.5;
  color: #E4CE93;
  text-align: left;
}
@media (min-width: 768px) { .consumer-notice { bottom: calc(env(safe-area-inset-bottom) + 1.75rem); } }

/* 13b. Tier exclusions — consumer-law item: an unreadable limitation is an
   undisclosed one. --txt-3 (5.66:1), never quieter. */
.plan-excl li { color: var(--txt-3); }
.plan-excl li i { color: var(--txt-3); }

/* 13c. Legal placeholder marker. The ship gate reads this visually, so it
   must stay loud. #FFC94D on its tint = 10.36:1, plus a non-colour marker. */
.legal-doc .legal-todo {
  display: inline-block; white-space: nowrap;
  background: rgba(232,184,75,.16); color: #FFC94D;
  border-radius: 4px; padding: 0 .28rem;
}
.legal-doc .legal-todo::after { content: ' \25B2'; font-size: .78em; vertical-align: .08em; opacity: .85; }

/* 13d. Legal tables — the wrapper owns horizontal scroll on phones. */
.legal-table { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.legal-doc table { border-collapse: collapse; width: 100%; }
.legal-doc th, .legal-doc td { border: 1px solid var(--line); padding: .5rem .6rem; text-align: left; }
.legal-doc th { background: var(--raised); font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--txt-2); }
.legal-doc td { font-size: .82rem; color: var(--txt-1); }

/* 13e. Rank pips. FLAT fills now (the theme bans gradients), which also
   removes the per-stop measurement hazard entirely — one fill, one ratio.
   Numeral retained, so meaning is never colour-only. */
.lb-medal {
  display: inline-grid; place-items: center;
  width: 1.65rem; height: 1.65rem; border-radius: 999px;
  font-size: .78rem; font-weight: 900; font-variant-numeric: tabular-nums;
}
.lb-medal.is-1 { background: #E8B84B; color: #241A05; }   /*  9.30:1 */
.lb-medal.is-2 { background: #C3C7CE; color: #1A1C1F; }   /* 10.07:1 */
.lb-medal.is-3 { background: #CC8B5C; color: #2A1608; }   /*  6.09:1 */

/* 13f. Top-tier paywall: no plan rail, no upgrade path. */
.pw-sheet.is-message-only .pw-plans { display: none; }
.pw-sheet.is-message-only .pw-all   { display: none; }
.pw-sheet.is-message-only .pw-next  { padding: 0 1.25rem; margin-top: .35rem; }
.pw-sheet.is-message-only .pw-icon  { background: rgba(255,255,255,.07); color: var(--txt-2); }
.pw-not { color: var(--txt-3); }   /* 5.66:1 */
.pw-all { color: var(--txt-1); }

/* 13g. Feed byline — the grey-on-card trap, fixed by the ramp itself now. */


/* ══════════════════════════════════════════════════════════════════════════
   14. THE SPIDERWEB CHART — PROTECTED
   The one asset that keeps its saturation, and the ONE permitted gradient in
   the entire theme (its area fill; a flat fill would flatten the shape that
   makes the chart readable).

   DONE (2026-09-01): radar.js's five hardcoded cyan literals are now the
   named consts RADAR_STROKE / RADAR_DOT, verified on rendered output — zero
   cyan, three fill uses (stroke + both gradient stops), six coral points,
   fill="url(#actGrad)" intact and the thin-axis grey #475569 untouched.
   Everything else about the chart is exactly as it was.
   Nothing here reduces its contrast: the axis labels and value text keep the
   rate colours, which are semantic (weak/ok/strong), not decorative.
   ══════════════════════════════════════════════════════════════════════════ */
.radar-wrap, .radar-wrap * { background-image: revert; }   /* exempt from §2 */
.radar-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); }



/* ══════════════════════════════════════════════════════════════════════════
   15b. ACCENT REMAP — the last cyan.
   ══════════════════════════════════════════════════════════════════════════
   style.css carries 142 hardcoded cyan tokens across 115 rules. A
   component-by-component override list would be fragile and would miss
   whatever the next feature adds — I found this because the A2HS step glyphs
   rendered cyan on a screen I had already signed off (style.css:2415, a
   selector this theme had no reason to name).

   SUPERSEDED (2026-09-01): the role-based sed over style.css has now been
   APPLIED at source — all 90 cyan occurrences across 115 rules are retoned, so
   style.css carries none. This section is kept only as a safety net for any
   cyan a future merge reintroduces; the assertions in test-design-v3 §9 fail
   the build if that happens, which is the real guard. My enumeration here was
   incomplete by 25 selectors when checked structurally (.navtab.active,
   .rk-row.is-me, .sm-pip.on, .mat-grid, .pw-tick and 20 more) — the third time
   this sprint that enumeration lost to a structural scan of a stylesheet this
   size.

   THE TRAP: six rules paint the old fill AND set white text. White on
   #0d7f97 was 4.67:1 and legal; white on #CEFF56 is 1.16:1 and FAILS HARDER. Those
   are overridden with dark ink below — a value-only sed would ship six
   sub-AA controls including the primary button.
   ────────────────────────────────────────────────────────────────────────── */

/* Ink roles. */
.nav-item.active, .pw-all, .lock-ts, .app-footer a:hover, .legal-doc a, .legal-doc .legal-back:hover, .legal-doc .legal-toc a:hover, .a2hs-steps i, .plan-feats li i, .sm-stat i, .sm-ms.target i, .dtile.is-key i, .rk-row.is-me .rk-num, .board-pick.on .bp-sub, .sm-xp-txt em, .sm-ms-pct, .boot-word-r, .lock-badge, .lock-demo-head {
  color: var(--txt-1);
}

/* Fill roles carrying NO text. */
.step-dot.on, .rnd-pip.on, .heat-cell.on, .mini-bar.on,
.rc-meter > span, .rk-row.is-me::before, .tech-card::before {
  background: var(--accent-fill);
}

/* Fill roles that DO carry text — fill AND ink both change. */
.navfab, .plan-flag, .vp-marker-dot, .vp-marker-label, .ac-turn.is-you .ac-bub {
  background: var(--accent-fill);
  color: var(--accent-on);
}

.input:focus { border-color: var(--k-focus); }

/* ══════════════════════════════════════════════════════════════════════════
   15c. CARRY-FORWARD — classes the deleted layers owned outright.
   ══════════════════════════════════════════════════════════════════════════
   Deleting the five old layers is correct (no dead cascade), but it is only
   safe for classes something still styles. I diffed every class selector in
   the removed 1510 lines against v2 AND against base style.css: 68 were owned
   ONLY by the deleted layers, and 12 of those are LIVE IN MARKUP at this head.
   Without this section those twelve render unstyled — an onboarding path
   chooser as raw stacked text, the footer legal row unspaced, the price
   wrapping mid-figure. The other 56 are spec-ahead or dead and are correctly
   dropped rather than carried as ballast.

   Re-expressed in v2 tokens, not copy-pasted: the originals carried cyan
   (rgba(34,200,224,.1), #8FE8F7, #22C8E0) and the old greys, which is exactly
   the palette v2 exists to remove.
   ────────────────────────────────────────────────────────────────────────── */

/* — the onboarding path chooser (views11.js:113) — */
.path-card-wrap { display: grid; gap: .85rem; }
.path-opt {
  display: flex; flex-direction: column; align-items: flex-start; gap: .55rem;
  width: 100%; text-align: left;
  padding: 1.4rem 1.3rem; border-radius: var(--radius-lg);
  background: var(--card);
  border: 1px solid var(--line);
  transition: background .2s var(--ease), border-color .2s var(--ease),
              transform .14s var(--ease);
}
.path-opt:hover  { background: var(--raised); border-color: var(--line-2); }
.path-opt:active { transform: scale(.985); }
.path-opt:focus-visible { outline: 2px solid var(--k-focus); outline-offset: 3px; }
.path-opt:focus:not(:focus-visible) { outline: none; }
.path-ico {
  width: 44px; height: 44px; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  background: var(--accent-weak); color: var(--txt-1); font-size: 1.1rem;
}
.path-name { font-size: 1.06rem; font-weight: 800; letter-spacing: -.015em; color: var(--txt-1); }
.path-line { font-size: .8rem; line-height: 1.5; color: var(--txt-2); }
/* `margin-top: auto` needs the flex column above it to have a height to push
   against; the cards are auto-height, so this pins the meta row to the bottom
   only when a sibling card is taller. That is the intended behaviour — two
   cards side by side keep their arrows aligned. */
.path-meta {
  margin-top: auto; padding-top: .7rem;
  font-size: .7rem; font-weight: 700; letter-spacing: .02em;
  color: var(--txt-1); display: flex; align-items: center; gap: .4rem;
}
.path-switch {
  width: 100%; padding: .65rem; margin-top: .9rem;
  font-size: .76rem; font-weight: 700; color: var(--txt-2);
}
.path-switch:hover { color: var(--txt-1); }

/* — the footer legal row (app.js appFooter()) —
   BASE RULE ADDED 2026-09-03. The footer had three child rules and a hover rule
   but NO rule of its own, so it rendered as browser-default inline text — and
   because nothing pinned the shell to the viewport it floated to wherever the
   content ended, mid-screen during Loading (Reqwa's screenshot). test:orphans
   missed it because it counted a class as styled if it appeared ANYWHERE in a
   selector, ancestors included; it now requires a subject rule. */
.app-footer {
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem 1.1rem;
  width: 100%; box-sizing: border-box;
  padding-top: 1.3rem; padding-bottom: calc(1.4rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  font-size: .8rem; color: var(--txt-3);
}
.app-footer a { color: var(--txt-3); text-decoration: none; }
/* On phones the fixed .navdock capsule floats over the bottom ~7rem. <main>
   already carries .pb-safe for that; the footer sits BELOW main, so it needs
   the same clearance or the capsule covers it. Signed-in routes only —
   .navdock is not rendered for anonymous users. */
@media (max-width: 767px) {
  #app.pg-app-navdock-0aa8 > .app-footer { padding-bottom: calc(6.6rem + env(safe-area-inset-bottom)); }
  #app.pg-app-navdock-0aa8 > main.pb-safe { padding-bottom: 1.5rem; }
}
@media (max-width: 599px) { .app-footer .af-mail { margin-left: 0; flex-basis: 100%; } }
.app-footer .af-sep  { display: none; }
.app-footer .af-mail { margin-left: auto; }
.app-footer .af-copy { margin-top: .35rem; }

/* — the price figure (views11.js:47) —
   inline-flex + nowrap is the whole point: without it "€39" and "/mo" can break
   across lines and the price reads as two numbers. */
.plan-price { display: inline-flex; align-items: baseline; white-space: nowrap; }

/* — terminal success mark (views5.js) — */
.ok-mark {
  display: inline-block; margin-left: .28rem;
  font-weight: 900; font-size: .92em; vertical-align: baseline;
}

/* ══════════════════════════════════════════════════════════════════════════
   15. REDUCED MOTION
   ══════════════════════════════════════════════════════════════════════════
   This block is a SUPERSET: it carries v2's own end states AND re-states the
   base stylesheet's resets. That is deliberate rather than lazy.

   Two suites locate reduced-motion coverage by slicing to the LAST matching
   at-rule in the served CSS (test-chat-rounds.mjs:406 slices, and
   test-boot-splash.mjs:266 splits and reads the final chunk). Because v2 loads
   after style.css, v2's block becomes "the" block — so a v2 block containing
   only v2's selectors silently drops `.sheet`, `.rnd-pip` and the whole boot
   set from what those suites can see, and they fail while accessibility is
   actually fine.

   Restating them here keeps BOTH true at once: the existing assertions pass
   unmodified, and every animation in the served stylesheet genuinely degrades.
   It costs a dozen duplicated lines and saves re-pointing two suites.
   (Same trap as the obj7 append-only layer, arriving from the other side: last
   time the fix was to add no block at all; here a block is unavoidable, so it
   has to be a superset instead.)
   ────────────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  /* — v2's own animations — */
  .ob-screen, .a2hs, .ob-guardian { animation: none; opacity: 1; }
  .a2hs { transform: translateX(-50%); }
  .ob-bar > span, .scan-bar > span, .offer-ring .fg { transition: none; }
  .scan-line { animation: none; opacity: 1; transform: translateY(50%); }
  .scan-label .dot { animation: none; opacity: 1; }
  .ob-opt, .ob-cell { transition: none; }
  .ob-opt:active, .ob-cell:active, .btn:active { transform: none; }
  .ob-radio::after { transition: none; }

  /* — carried forward from the base block, so the last-block slice stays
       complete. Values identical to style.css; do not diverge. — */
  .sheet, .sheet-back { animation: none !important; }
  .intro-card, .intro-back, .intro-list li, .intro-free, .intro-paid, .intro-go, .intro-later,
  .pw-icon { animation: none !important; opacity: 1 !important; transform: none !important; }
  .pw-plan:hover { transform: none; }
  .sheet { transform: none; opacity: 1; }
  .rnd-pip { transition: none; }
  .boot-splash, .boot-splash * { animation: none !important; transition: none !important; }
  .boot-mark, .boot-mark .bl-wipe, .boot-mark .bl-facet image,
  .boot-mark .bl-frame-tl, .boot-mark .bl-frame-tr,
  .boot-mark .bl-frame-bl, .boot-mark .bl-frame-br,
  .boot-word-l, .boot-word-r { transform: none !important; opacity: 1 !important; }
  .boot-glow { opacity: .55 !important; transform: none !important; }
  .boot-mark .bl-wipe { width: 1584px !important; }
  .boot-belt { transform: none !important; opacity: 1 !important; }
  #app.boot-reveal { animation: none !important; opacity: 1; transform: none; }
  .sm-poly { animation: none !important; transform: none !important; opacity: 1 !important; }
  .sm-xp-bar > span { animation: none !important; transform: none !important; }
  .sm-ms { transition: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   16. THE MISSING BLOCKS — classes rendered by a view and styled by NOBODY
   ══════════════════════════════════════════════════════════════════════════
   FOUND ON THE SERVED PAGE 2026-09-03 (Reqwa: "this is definitely glitched"),
   not by any suite, and the cause is worth stating precisely because it is
   this codebase's signature defect wearing a new hat.

   `.dev-stack` and its nine children are rendered by `VIEWS.home` in views.js
   — the landing page's whole "real product surfaces" argument, the three
   device cards. They are styled in NO stylesheet. Not overridden, not
   shadowed: never written. So the browser fell back to unstyled block flow and
   the three designed cards rendered as a bare vertical list of label/value
   text runs — "Streak14 days", "Check in2 rounds" — which is exactly what the
   screenshot shows and exactly what a reader calls broken.

   Why nothing caught it: the design suite reads DECLARATIONS, so a class with
   no declaration to read is invisible to it, and the header comment at
   shell.ts:148 records that five earlier design layers were DELETED from the
   end of style.css when theme-v2 replaced them. These rules lived in one of
   those layers. The deletion was correct and the replacement was incomplete —
   read-with-nothing-writing, in the stylesheet.

   The generic lesson, which is the reason this block is documented rather than
   quietly added: an assertion over declarations can only ever check the CSS
   that EXISTS. What it cannot check is markup that resolves to nothing, and
   that has to be verified by rendering. `scripts/test-orphan-classes.mjs` now
   does it structurally — every class in every shipped view must resolve to a
   rule — so this cannot recur silently.

   All of it is tokens. No new colour, no gradient, no glow, no blur.
   ────────────────────────────────────────────────────────────────────────── */

/* ── 16.1 Landing device stack (views.js VIEWS.home) ──────────────────────
   Three product screens shown as device cards. They are the landing page's
   argument, so they are the loudest surface on it — which here means the
   brightest SURFACE, not a colour: `--raised` against the section's `--card`,
   separated by the hairline exactly like every other stack in the app. */
.dev-stack {
  display: grid;
  gap: .75rem;
  grid-template-columns: 1fr;
}
@media (min-width: 768px) {
  /* Three across on desktop. On mobile they stack, because a 3-up grid at
     390px makes each screen too small to read — and an unreadable product
     screenshot argues against the product. */
  .dev-stack { grid-template-columns: repeat(3, 1fr); gap: .85rem; }
}

.dev {
  background: var(--raised);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--lift-1);
}

/* The window chrome. Two dots and a caption — enough to read as a device
   without drawing a phone frame, which at this size becomes bezel noise. */
.dev-top {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .6rem .85rem;
  border-bottom: 1px solid var(--line);
  background: var(--card);
}
.dev-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: rgba(255,255,255,.14);
  flex: 0 0 auto;
}
.dev-cap {
  margin-left: .25rem;
  font-size: .66rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--txt-3);
}

.dev-body { padding: .8rem .85rem .95rem; display: grid; gap: .5rem; }

/* Label left, value right, icon leading. `gap` + `margin-left:auto` rather
   than `justify-content: space-between`, so a row with no value (the coach
   card has two) still reads as left-aligned instead of stretching. */
.dev-row {
  display: flex;
  align-items: center;
  gap: .55rem;
  font-size: .82rem;
  line-height: 1.3;
  min-height: 1.5rem;
}
.dev-row-l { color: var(--txt-2); }
/* THE EMPTY VALUE IS A DESIGNED STATE, not a missing one.
   These rows carry no figures on purpose (see views.js — an invented number on
   the page where a visitor decides to trust us is a false claim, and the
   earlier "illustrative" defence did not survive contact with the owner).
   The em-dash therefore has to read as "this is where yours goes" rather than
   as a broken value, which is exactly the treatment the owner's own day-one
   mockup gives RECORD / VISIT RATE / ELO: quieter than the label, not louder. */
/* TWO NAMES FOR ONE STATE, and they are merged rather than left to diverge.
   `.is-empty` (mine) and `.dev-row-mute` (Tech Lead's, added in the same hour
   on the same rows) are the same idea: the value slot carries no figure, so it
   must read as "this is where yours goes" and not as a broken value. Two
   classes doing one job is how a stylesheet starts disagreeing with itself, so
   both resolve here and `.dev-row-mute` is the name kept in the markup. */
.dev-row-v.is-empty,
.dev-row-v.dev-row-mute {
  color: var(--txt-3);
  font-weight: 600;
  /* The label is .82rem; the hint has to sit UNDER it or the quiet thing
     becomes the loud thing on a row whose point is the field name. */
  font-size: .74rem;
  letter-spacing: .01em;
}
.dev-note {
  font-size: .72rem; line-height: 1.5;
  color: var(--txt-3);
  margin-top: .15rem;
}
.dev-row-v {
  margin-left: auto;
  color: var(--txt-1);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* The medal pip and the leading icon both need to stop shrinking, or a long
   label squeezes the thing that carries the row's meaning. */
.dev-row > i, .dev-row > .lb-medal { flex: 0 0 auto; }

/* ── 16.2 Solo Mastery gaps (views10.js) ──────────────────────────────────
   Same cause, smaller blast radius: the hero's tier block, the XP group, the
   AI slot and the milestones panel are rendered and unstyled. Their siblings
   (.sm-tier-num, .sm-xp-bar, .sm-ai-body, .sm-ms-grid) DO exist in style.css,
   which is what made the omission hard to see — the parts were painted and
   only the containers were missing. */
.sm-tier-meta { min-width: 0; }
.sm-xp { margin-top: .85rem; }
.sm-read { padding: 0 0 1.1rem; }
.sm-read .sm-read-list, .sm-read > .sm-ai, .sm-read > .btn { margin-left: 1.1rem; margin-right: 1.1rem; }
.sm-ai:empty { display: none; }   /* or an empty slot adds a gap above the button */
.sm-ms-panel { padding-bottom: 1.1rem; }
.sm-ms-panel .sm-ms-group, .sm-ms-panel .sm-note { margin-left: 1.1rem; margin-right: 1.1rem; }

/* ── 16.3 Search result row (views6.js) and chat drawer body (views4.js) ──
   `.ps-row` is a 40px-avatar person row and was rendering as an unstyled
   <button>: no padding, no surface, no hit target. It is a tap target on a
   phone, so it takes the 52px floor `.belt-pick` already sets. */
.ps-row {
  display: flex; align-items: center; gap: .7rem;
  width: 100%;
  min-height: 52px;
  padding: .55rem .7rem;
  border-radius: var(--radius-sm);
  background: var(--card);
  border: 1px solid var(--line);
  text-align: left;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
.ps-row:active { transform: scale(.99); }
@media (hover: hover) {
  .ps-row:hover { background: var(--raised); border-color: var(--line-2); }
}
.rnd-body { border-top: 1px solid var(--line); padding-top: .7rem; }

/* ══════════════════════════════════════════════════════════════════════════
   17. THE REDESIGN — geometry, type and navigation from Reqwa's mockup
   ══════════════════════════════════════════════════════════════════════════
   2026-09-03. "do you actually think recolor is just swapping red for lime?
   dont forget the layout the geometry the fonts the everything the navigation
   bar" — correct, and this block is the answer. Everything here is measured
   off his render's pixels, not approximated from a description.

   The lime is in §1 with the rest of the tokens, because an accent is a token
   and not a component. This section is the part that is NOT colour.
   ────────────────────────────────────────────────────────────────────────── */

/* ── 17.1 THE HERO FIGURE ─────────────────────────────────────────────────
   The single biggest difference between his screen and ours, and it is a type
   decision rather than a layout one: the NUMBER is the headline. Ours set the
   rank LABEL at 2.5rem and never set the figure at all, so the loudest thing
   on the dashboard was a word.

   clamp() rather than a breakpoint: this figure has to hold at 360px (where
   the app is specified to work without a horizontal scrollbar) and still
   dominate at 430px. A fixed rem plus a media query gives two sizes and a
   visible jump; clamp gives the curve.
   `font-variant-numeric: tabular-nums` comes from .tnum in the markup — at
   this size proportional digits make the number visibly shift when a streak
   rolls 9 → 10. */
/* (.hero-figure geometry moved to §37.1 `#rank-hero .hero-figure` — DS8 item 5) */
/* The unit is a WORD beside the number, not a superscript and not a label
   underneath. Sits on the figure's baseline (the markup uses items-baseline —
   items-end floats it visibly high at this size). */
.hero-unit {
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--txt-3);
  letter-spacing: -.01em;
}

/* The ring: BIG, THIN, EMPTY. His is ~124px at ~9px stroke with nothing
   inside it, where ours was 92px with an icon jammed in the middle. Empty is
   the point — it reads as progress at a glance instead of as a badge. */
.ring-track { stroke: rgba(255,255,255,.07); }
.ring-fill { transition: stroke-dashoffset .9s var(--ease); }

/* ── 17.2 THE STAT ROW ────────────────────────────────────────────────────
   Three flat single-number panels, all visible at once. Replaces the
   segmented four-pane card (see views4.js for where each pane's detail went).

   `grid-template-columns: repeat(3, 1fr)` with `min-width: 0` on the cell:
   without it a long value (a 4-digit ELO next to a 2-2 record) blows the
   track out and the third panel wraps. This is the failure the 360px floor
   exists to catch. */
.stat-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .6rem;
}
/* (.stat-cell surface moved to §37.1 — DS8 item 5) */
.stat-cell:active { transform: scale(.99); }
@media (hover: hover) {
  .stat-cell:hover { border-color: var(--line-2); }
}
.stat-cell-v {
  font-size: 1.45rem;
  font-weight: 900;
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--txt-1);
}
/* The % is smaller and quieter than its number — his render does this and it
   is why "86%" reads as one figure rather than two glyphs of equal weight. */
.stat-cell-suffix { font-size: .82rem; font-weight: 800; color: var(--txt-3); margin-left: .05em; }
.stat-cell-l {
  margin-top: .4rem;
  font-size: .62rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--txt-3);
}
/* THE EMPTY STATE IS REQUIRED, not a fallback. His day-one column draws an
   em-dash for all three, and it is the right call: three zeroes on a fresh
   account read as failure, three dashes read as "not yet" — which is true.
   The dash is quieter than a real value so the panel does not compete with
   the hero for attention it has not earned. */
.stat-cell[data-empty] .stat-cell-v { color: var(--txt-3); font-weight: 800; }

/* ── 17.3 NAVIGATION ──────────────────────────────────────────────────────
   The bar keeps its four-tabs-plus-accent SHAPE — that structure was already
   right and matches both references. What changes is everything about how it
   is drawn, and one thing about what it is made of.

   FLAT, NOT GLASS. The capsule was `rgba(20,20,25,.82)` with a
   `backdrop-filter: blur(20px) saturate(160%)` and an inset highlight. That
   is the glassmorphism this theme's own §2 removes everywhere else — it
   survived here because §2 scoped its blur reset by selector and this one was
   not on the list. Neither reference blurs its bar: Cal AI's sits on an
   opaque near-black, and a blur is a per-frame GPU cost on an element that is
   on screen for the entire session.

   The removal is also a legibility win, which is the honest argument for it:
   text over a live blur of scrolling content has no fixed contrast ratio at
   all, so no number I could quote about it would mean anything. */
.navcapsule {
  background: var(--raised);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  box-shadow: var(--lift-2);
}
.navtab { border-radius: var(--radius-sm); color: var(--txt-3); }
/* THE ACTIVE TAB IS INK, NOT A TINTED PILL. The pill was the old theme's
   "clearest single idea", and on lime it stops working: an 11%-opacity lime
   pill on --raised is a barely-visible olive smear, and raising the opacity
   until it reads makes the bar the loudest thing on the screen.
   His mockup marks the active tab with a WHITE icon, a bold label and a small
   dot underneath — icon weight plus a mark, no fill. That scales to any
   accent, which the pill did not. */
.navtab.active { color: var(--txt-1); background: transparent; box-shadow: none; }
.navtab.active span { font-weight: 800; }
/* The active dot. bottom:2px, and the tab's own padding-bottom makes the room
   for it — my first pass put it at bottom:5px, which is inside the label's
   line box, so it rendered BEHIND the text and was invisible in the
   screenshot. A marker hidden under the thing it marks is worse than no
   marker: it is a rule that looks correct in the stylesheet and does nothing
   on screen, which is the failure mode this whole session keeps finding. */
.navtab { padding-bottom: 7px; }
.navtab.active::after {
  content: '';
  position: absolute;
  bottom: 2px; left: 50%;
  width: 4px; height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--accent-ink);
}
.navtab { position: relative; }   /* the dot is positioned against the tab */

/* The accent slot: a CIRCLE, flat, dark ink on lime. It was a 17px-radius
   rounded square with a coral gradient, an inset white highlight and a
   coloured drop shadow — a gradient and a glow, both of which §2 bans, and
   both of which survived by being written before that rule.
   Round rather than rounded-square because his mockup's is round, and because
   a circle among four flat tabs is unmistakably the one different thing in
   the bar without needing a shadow to say so. */
.navfab {
  border-radius: 50%;
  background: var(--accent-fill);
  background-image: none;
  color: var(--accent-on);
  box-shadow: none;
}
.navfab.active { box-shadow: 0 0 0 2px var(--ground), 0 0 0 4px rgba(206,255,86,.35); }

/* ── 17.4 PILLS AND RADII ─────────────────────────────────────────────────
   One radius language, applied. The primary action is a FULL pill in both
   references and in his mockup; 52px tall, which is also the `.belt-pick`
   touch floor this app already sets. */
.chip { border-radius: var(--radius-pill); }

/* ── 17.5 THE ORBS GO ─────────────────────────────────────────────────────
   Five blurred coloured circles were still drifting behind the auth stage,
   the onboarding card, the mastery hero and two others. They are absent from
   both references and from Reqwa's mockup, and they are exactly the
   decoration section 2 removes everywhere it could reach by selector — they
   survived because they are painted from INLINE STYLES in the views, which no
   stylesheet reset can touch.

   The lime is what forced the issue rather than my finding it by audit: a
   42px-blurred coral at 50% opacity read as warm ambient depth, but a
   42px-blurred LIME reads as a green light leak across the card. I saw it on
   the onboarding screen — a khaki wash behind the question.

   Neutralised HERE rather than by editing five inline styles in four view
   files, because `background` is set inline and inline wins the cascade:
   `display: none` is the one property that beats it without !important on a
   colour. The elements stay in the markup (they are aria-hidden decoration,
   so removing them is a view change with no user-visible upside) and stop
   painting. If ambient depth comes back it comes back as a surface step, not
   as a blurred circle. */
.orb, .orb-hero { display: none; }

/* ── 17.6 THE COral LITERALS STILL IN style.css ───────────────────────────
   A retint is not a token swap, and this is the part that proves it.
   style.css carries the accent as HARDCODED HEX in ~14 rules that theme-v2's
   role blocks (section 13) never named, because those blocks enumerate
   selectors and enumeration loses to a 1900-line stylesheet — the same lesson
   §2 already learned about gradients and glows.

   Found by grepping style.css for the coral values AFTER the ramp and the
   tokens were done, then checking each hit against what theme-v2 already
   overrides. These are the ones nothing was covering. Two are gradients as
   well as coral, so they also violate §2 and get flattened rather than
   re-tinted.

   Deliberately NOT fixed by editing style.css: that file is the pre-theme
   layer and its literals are the fallback for the frame before v2 applies.
   The exception is `.boot-word-r`, retinted in place, because the boot splash
   IS that frame and the suite asserts both mechanisms resolve to one colour. */
.dtile-lock { color: var(--txt-1) !important; }   /* !important matches the rule it overrides */
.sm-read-list li::before { background: var(--accent-ink); }
.sm-stat i { color: var(--txt-1); }
.sm-pip.on { background: var(--accent-fill); background-image: none; }
.badge-dot { background: var(--accent-fill); color: var(--accent-on); }  /* style.css keeps #fff on the fill — white on lime is 1.16:1 (Wave 4b walk) */
.pw-plan.on, .pw-plan.is-pick { border-color: var(--txt-1); }

/* The topbar mark's own gradient (style.css:67) — a three-stop coral ramp on
   the wordmark. Flat accent, per §2: the wordmark is type, and type painted
   with a gradient is the thing that made the landing headline invisible once
   already. */
.logo-word { background-image: none; color: var(--txt-1); }


/* ── 17.6b THE DESTINATION TILES (Home groups, Wave 3) ────────────────────
   style.css still paints `.dtile i { color:#91dff3 }` — the pre-v2 cyan, the
   exact colour §1 threw out, surviving because it was never in any enumerated
   role block (Reqwa's screenshot 3: "wrong icon colors"). Icons take the
   secondary ink; the ONE emphasis tier (is-key: what the paid tiers sell plus
   the staff daily driver) takes the accent ink, already declared in §13. The
   hover ring was the same cyan. Surfaces move to tokens so the light set
   reaches them. Group rows: a section label and a 3-up row — the label IS the
   grouping, so no extra chrome. The Account row is deliberately quieter. */
.dtile { background: var(--card); border-color: var(--line); }
.dtile i { color: var(--txt-2); }
.dtile-l { color: var(--txt-1); }
.dtile.is-key i { color: var(--txt-1); }
@media (hover: hover) { .dtile:hover { background: var(--raised); border-color: var(--line-2); } }
/* ── LOCKED ENTRY POINTS ARE SHARP AND TAPPABLE (Wave 4a-6, Reqwa) ───────
   "we have blurry icons that mean you dont have this in your tier but blurry
   icons is just a nonsense, it should be clickable but the users should get a
   tiers UI" — correct, and the .6 opacity here was the same mistake one step
   milder: a dimmed tile reads as DISABLED, so the user does not tap it, so
   they never see the tiers sheet the tap was supposed to open.

   THE DISTINCTION THIS FILE NOW HOLDS, and §10's comment states the other
   half: blur belongs on a computed teaser VALUE (a real number we are
   withholding — .is-locked in §10) and nowhere else. An ENTRY POINT is not a
   withheld value; it is an advertisement, and an advertisement you cannot read
   is not one. The Competition pill already had this fix scoped to itself
   (§23); this generalises it instead of waiting for the next component to
   rediscover it.

   So a locked tile is: full opacity, full-contrast label, sharp icon, the lock
   badge as the ONLY signal, and a working tap into window.paywall(cap). The
   lock badge takes the accent so it reads as a door rather than a barrier —
   and because it is accent-ink type, §29.4 gives it a backing in light mode. */
.dtile.is-locked { opacity: 1; filter: none; pointer-events: auto; user-select: auto; }
.dtile.is-locked i, .dtile.is-locked .dtile-l { opacity: 1; }
/* The icon steps back one ink level, which is the whole visual difference —
   a tile you can read but that is not shouting. NOT a fade. */
.dtile.is-locked > i:not(.dtile-lock) { color: var(--txt-3); }
.dtile.is-locked.is-key > i:not(.dtile-lock) { color: var(--txt-1); }
/* The badge: a real badge, not a superscript. Top-right, on the surface, so
   it survives a two-line label. */
.dtile { position: relative; }
.dtile-lock {
  position: absolute; top: .42rem; right: .42rem;
  font-size: .6rem; line-height: 1;
  padding: .26rem .3rem; border-radius: 999px;
  background: var(--sunken); border: 1px solid var(--line);
}
@media (hover: hover) {
  .dtile.is-locked:hover { background: var(--raised); border-color: var(--line-2); }
  .dtile.is-locked:hover .dtile-lock { border-color: var(--accent-fill); }
}
.dest-group + .dest-group { margin-top: 1.1rem; }
.dest-group .section-label { margin-bottom: .6rem; }
.dest-group-quiet .dtile { background: transparent; }
.dest-group-quiet .dtile i { color: var(--txt-3); }
.dest-group-quiet .dtile-l { color: var(--txt-2); }
/* A short row (1-2 tiles) keeps the 3-up track so tiles never stretch into
   banners; empty cells stay empty — the row is not backfilled (g2). */
.dest-grid-short { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (min-width: 480px) { .dest-grid-short { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ── 17.6b2 RATE / STATUS CHIPS BY CLASS (Wave 4b light-mode walk) ─────────
   views4 rateChip() and views6's invite-status chip used to paint an inline
   `style="background:#4ade8022;color:#4ade80"` — a hex plus an alpha suffix.
   A literal cannot follow the theme: in light mode those inks sat at ~1.5:1 on
   a white card. Four bands, tokens only; the tint is the ink at low alpha via
   color-mix so the pair moves together in both modes. */
.rate-chip.is-good  { color: var(--txt-1);       background: color-mix(in srgb, var(--good) 14%, transparent); }
.rate-chip.is-warn  { color: var(--warn-ink);   background: color-mix(in srgb, var(--warn-ink) 14%, transparent); }
.rate-chip.is-bad   { color: var(--danger-ink); background: color-mix(in srgb, var(--danger-ink) 14%, transparent); }
.rate-chip.is-muted { color: var(--txt-2);      background: var(--sunken); }

/* ── 17.6c THE STAFF DOCK (Home, owner/coach — Wave 3 §3K) ──────────────────
   The member dock's shape with two live counters and a named destination.
   A non-zero queue takes the accent ink; zero stays quiet. */
.staff-dock { align-items: center; }
.staff-dock-k { display: inline-flex; gap: .25rem; align-items: baseline; }
.staff-dock-meta { display: flex; flex-wrap: wrap; gap: .25rem .8rem; margin-top: .2rem; font-size: 10.5px; color: var(--txt-3); }
.staff-dock-k b { font-weight: 800; color: var(--txt-2); }
.staff-dock-k.is-live b { color: var(--txt-1); }
.staff-dock-go { flex: none; display: inline-flex; align-items: center; gap: .35rem; font-size: 11px; font-weight: 700; color: var(--txt-2); white-space: nowrap; }
@media (max-width: 420px) { .staff-dock-go span, .staff-dock-go { font-size: 0; } .staff-dock-go i { font-size: 11px !important; color: var(--txt-3); } }

/* ── 17.6d BILLING PANEL (owner dashboard, Wave 3 §3K a) ───────────────────
   The status chip and seat meter used to paint hex + a coloured blur and a
   gradient bar (both §2 violations). Flat: state colour as INK on a tinted
   chip via currentColor, meter as accent fill on a hairline track. */
.bill-panel { position: relative; }
.bill-status { background: color-mix(in srgb, currentColor 14%, transparent); font-size: 10px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; }
.bill-meter { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; }
.bill-meter > span { display: block; height: 100%; border-radius: inherit; background: var(--accent-fill); }

/* ── 17.6e STAFF DASHBOARD PASS (Wave 3 §3K c) ─────────────────────────────
   Hierarchy and rhythm only, tokens only. The roll-call CTA was still the
   coral literal (#FF6B63 tint + ring) from the pre-theme layer — a second
   accent on the busiest staff screen. Flat card + hairline, accent on the
   icon tile like the Home docks. */
.rollcall-cta { background: var(--card); border: 1px solid var(--line); box-shadow: var(--lift-1); }
.rc-ico { background: var(--accent-weak); color: var(--txt-1); }
@media (hover: hover) { .rollcall-cta:hover { border-color: var(--line-2); background: var(--raised); } }
/* The KPI strip: four figures read as one row on a phone, not two stacked
   pairs of oversized cards — same treatment as Home's .stat-row. */
.kpi-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .5rem; }
.kpi-strip .panel { padding: .8rem .6rem; }
.kpi-strip .panel i { font-size: .8rem; }
.kpi-strip .kpi-v { font-size: 1.25rem; font-weight: 850; letter-spacing: -.03em; margin-top: .3rem; }
.kpi-strip .section-label { font-size: .58rem; margin-top: .15rem; }
@media (min-width: 640px) { .kpi-strip { gap: .75rem; } .kpi-strip .panel { padding: 1.25rem; } .kpi-strip .kpi-v { font-size: 1.5rem; } .kpi-strip .section-label { font-size: .62rem; } }
/* Roster rows: a little more air between avatar and text, streak column
   aligned to the row's baseline instead of floating. */
.roster-row { padding: .95rem 1rem; }

/* ── 17.6f THE STICKY TOPBAR NEVER COVERS A TITLE (Wave 3 §3G) ─────────────
   Reqwa's screenshot 2: a page title sitting under the sticky header. The
   header is 4rem + the safe-area inset; any programmatic scroll (an anchor, a
   scrollIntoView on a form field, a restored scroll position) lands content
   under it unless the document says how tall the fixed chrome is. Two rules
   make that a property of the page rather than of each screen: */
html { scroll-padding-top: calc(4rem + .75rem + env(safe-area-inset-top)); }
h1, h2, .ra-head, .section-label, [id] { scroll-margin-top: calc(4rem + .75rem + env(safe-area-inset-top)); }

/* ── 17.7 THE SEMANTIC GREEN, WHERE IT IS STILL A LITERAL ─────────────────
   Same story as §17.6 and the same reason it is here rather than in
   style.css: these are pre-theme literals, and the token is now the source of
   truth. Two of them are also gradients, so they get flattened per §2 rather
   than re-tinted.
   `.belt-sw-green` is EXCLUDED on purpose — it is the green-belt swatch, a
   BELT RANK colour, and belt hues do not move. It happening to share a hex
   with the old semantic green is a coincidence this retint must not merge. */
.pill-ok {
  background: var(--good-weak);
  color: var(--txt-1);
  border-color: color-mix(in srgb, var(--good) 30%, transparent);
}
.plan-save { color: var(--txt-1); }
.intro-list li i { color: var(--txt-1); }
.plan-cta.is-current { background: var(--good-weak); color: var(--txt-1); }
.rc-tick.on {
  color: var(--accent-on);
  background: var(--good-fill);
  background-image: none;
  border-color: transparent;
}
/* style.css:1646 — the intro card's headline tick, a bare colour on a class
   theme-v2 never named. */
.intro-head i, .intro-tick { color: var(--txt-1); }

/* ── 17.8 THE CAPSULE SLOT CONTRACT ───────────────────────────────────────
   Confirmed with Tech Lead and Engineer 2026-09-03: exactly FOUR labelled
   tabs (Home / Ladder / Game / Coach) plus the Analysis FAB, and it must hold
   at 360px. Engineer owns the DOM and the routing; these rules own whether it
   fits. Measured, not estimated:

     360px viewport
     − 19.2px  .navdock side padding (.6rem x 2)
     − 12.2px  .navcapsule inner padding (.38rem x 2)
     − 7.2px   four inter-slot gaps (.18rem x 4)
     − 50px    the FAB
     = 252px across four tabs → 63px per tab

   The longest label rendered at the active weight (Ladder, 800, 11px) is
   38.3px, so a 63px tab has ~24px of slack. The bar fits with room, which is
   why the labels below are NOT allowed to wrap or ellipsis — if a future label
   needs it, the label is wrong, not the bar.

   Two properties are load-bearing and easy to lose:
     · `min-width: 0` on .navtab. Flex items default to min-width:auto, so a
       label wider than its share pushes the FAB off the capsule instead of
       being constrained. This is the 360px overflow Tech Lead flagged.
     · `flex: 0 0 50px` on the FAB. Without the 0-shrink it gives up width
       first, and a squashed circle is the one element in the bar that must
       stay a circle. */
.navcapsule { gap: .18rem; padding: .38rem; }
.navtab {
  flex: 1 1 0;
  min-width: 0;              /* see above — this is the overflow fix */
  height: 50px;
}
.navtab span {
  font-size: 10.5px;
  white-space: nowrap;
  overflow: visible;         /* 24px of slack at 360px; nothing to clip */
  text-overflow: clip;
}
.navfab { flex: 0 0 50px; width: 50px; height: 50px; }

/* A FIFTH LABELLED TAB IS A DESIGN ERROR, and it is asserted in CSS because
   that is where it becomes visible. At five tabs the per-tab share drops to
   ~50px, which is under the 44px label+icon stack plus its gutters, and the
   bar starts clipping. Rather than silently degrade, the fifth tab is made
   obvious in review: it turns the bar into a scrollable overflow instead of
   quietly shrinking its siblings.
   `:has()` is the mechanism — if it is unsupported the bar simply behaves as
   before, so this is a progressive warning and never a broken layout. */
@supports selector(.navcapsule:has(.navtab:nth-of-type(5))) {
  .navcapsule:has(.navtab:nth-of-type(5)) {
    overflow-x: auto;
    scrollbar-width: none;
    outline: 2px dashed var(--accent-ink);   /* visible in review, not in prod
                                                — five tabs never ships */
  }
}


/* ══════════════════════════════════════════════════════════════════════════
   18. LEGAL PAGES  (/terms /privacy /refund — src/routes/legal.ts)

   These are server-rendered OUTSIDE the SPA (no Tailwind CDN, no app.js), so
   nothing here can lean on a utility class — every rule the page needs is
   declared in this block. Until 2026-09-03 the template linked style.css only,
   which had no .legal-* rules at all after the theme-v2 cut, so Paddle's
   reviewer and every user opening the Terms got browser-default text on a
   dark ground. Same shape as the orphan-class bug: markup resolving to no rule.

   Structure: a slim top bar with the mark, three document tabs and a back
   button; a two-column body on desktop (sticky section nav + document) that
   collapses to one column on phones; the shared .app-footer underneath. Type
   is set for READING — 17px on desktop, measured 68ch line, 1.7 leading —
   because this is the one surface where a user may genuinely read 3,000 words.
   Tokens only; no new colour; the warning notices reuse the amber that
   .consumer-notice already established for statutory text (13a).
   ══════════════════════════════════════════════════════════════════════════ */
.legal-body {
  margin: 0; min-height: 100vh; min-height: 100dvh;
  font-family: Inter, system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 16px; line-height: 1.65;
  display: flex; flex-direction: column;
}

/* — top bar — */
.legal-top {
  position: sticky; top: 0; z-index: 20;
  background: var(--ground); border-bottom: 1px solid var(--line);
  padding-top: env(safe-area-inset-top);
}
.legal-top-in {
  max-width: 72rem; margin: 0 auto; height: 4rem;
  padding: 0 1.1rem; padding-left: max(1.1rem, env(safe-area-inset-left)); padding-right: max(1.1rem, env(safe-area-inset-right));
  display: flex; align-items: center; gap: 1rem;
}
.legal-brand { display: inline-flex; align-items: center; gap: .6rem; text-decoration: none; color: var(--txt-1); flex: none; }
.legal-logo { width: 34px; height: 34px; display: block; }
.legal-wordmark { font-size: 1.28rem; font-weight: 900; letter-spacing: -.035em; }
.legal-wordmark em { font-style: normal; color: var(--txt-1); margin-left: .18em; }

.legal-tabs { display: flex; gap: .15rem; margin-left: .5rem; }
.legal-tabs a {
  padding: .45rem .8rem; border-radius: 999px;
  font-size: .86rem; font-weight: 600; color: var(--txt-3); text-decoration: none;
  transition: color .16s, background .16s;
}
.legal-tabs a:hover { color: var(--txt-1); background: rgba(255,255,255,.045); }
.legal-tabs a.is-here { color: var(--txt-1); background: var(--raised); border: 1px solid var(--line-2); padding: calc(.45rem - 1px) calc(.8rem - 1px); }

.legal-top .legal-back {
  margin-left: auto; text-decoration: none; padding: .55rem 1rem; font-size: .86rem; flex: none;
  display: inline-flex; align-items: center; justify-content: center; border-radius: 999px;
  border: 1px solid var(--line-2); color: var(--txt-1); background: transparent;
}
.legal-top .legal-back:hover { background: rgba(255,255,255,.045); color: var(--txt-1); }
/* Phone. The tab strip is SIX documents now (Engineer mounted /cookies,
   /acceptable-use and /academy-terms at Drop A) — at 390px that is ~430px of
   pills, and the strip pushed the page to a 602px scroll width in both themes
   (Wave 4b light-mode walk; the legal-390 screenshots came out 602px wide).
   The strip becomes a horizontal snap rail that owns its own overflow: the
   brand and Back stay fixed at the edges, the documents scroll between them,
   and the page never grows sideways. The wordmark still goes — the mark alone
   is the home link. `min-width: 0` on the nav is what lets a flex child
   shrink below its content width at all; without it overflow-x does nothing. */
@media (max-width: 599px) {
  .legal-top-in { gap: .6rem; }
  .legal-wordmark { display: none; }
  .legal-tabs {
    margin-left: 0; gap: 0; min-width: 0; flex: 1 1 auto;
    overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; -ms-overflow-style: none;
    /* fade at the right edge says "more" without a scrollbar */
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 1.4rem), transparent);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 1.4rem), transparent);
    padding-right: 1.4rem;
  }
  .legal-tabs::-webkit-scrollbar { display: none; }
  .legal-tabs a { padding: .4rem .6rem; font-size: .8rem; flex: none; scroll-snap-align: start; white-space: nowrap; }
  .legal-tabs a.is-here { padding: calc(.4rem - 1px) calc(.6rem - 1px); }
  .legal-top .legal-back { padding: .5rem .8rem; font-size: .8rem; }
}
/* The document rail must not let the page scroll sideways either: the
   body-level clip is the belt-and-braces for both rails on the legal pages,
   which have no #app wrapper to contain them. */
.legal-body { overflow-x: clip; }

/* — layout — */
.legal-wrap {
  flex: 1; box-sizing: border-box;
  width: 100%; max-width: 72rem; margin: 0 auto;
  padding: 2rem 1.1rem 3rem;
  padding-left: max(1.1rem, env(safe-area-inset-left)); padding-right: max(1.1rem, env(safe-area-inset-right));
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 2rem;
}
@media (min-width: 900px) {
  .legal-wrap { grid-template-columns: 15.5rem minmax(0, 1fr); gap: 3.5rem; padding-top: 3rem; }
  .legal-body { font-size: 17px; }
}

/* — section nav: sticky on desktop, a horizontal chip rail on phones — */
.legal-side { min-width: 0; }
.legal-toc { position: sticky; top: calc(4rem + 1.5rem + env(safe-area-inset-top)); }
.legal-toc .section-label { margin-bottom: .7rem; }
.legal-toc ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .1rem; }
.legal-toc a {
  display: block; padding: .42rem .7rem; border-radius: 12px;
  font-size: .83rem; line-height: 1.35; color: var(--txt-3); text-decoration: none;
  transition: color .16s, background .16s;
}
.legal-toc a:hover { color: var(--txt-1); background: rgba(255,255,255,.045); }
.legal-toc a.is-on { color: var(--txt-1); background: var(--card); box-shadow: inset 2px 0 0 var(--txt-1); }
@media (max-width: 899px) {
  .legal-toc { position: static; }
  .legal-toc .section-label { display: none; }
  .legal-toc { min-width: 0; }
  .legal-toc ol {
    flex-direction: row; gap: .4rem; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; padding: .1rem 0 .3rem; margin: 0 -1.1rem; padding-left: 1.1rem; padding-right: 1.1rem;
    scroll-snap-type: x proximity;
  }
  .legal-toc ol::-webkit-scrollbar { display: none; }
  .legal-toc li { flex: none; }
  .legal-toc a { white-space: nowrap; border-radius: 999px; background: var(--card); border: 1px solid var(--line); padding: .45rem .85rem; }
  .legal-toc a.is-on { box-shadow: none; border-color: var(--txt-1); color: var(--txt-1); }
}

/* — document — */
.legal-doc { min-width: 0; max-width: 68ch; }
.legal-head { padding-bottom: 1.6rem; margin-bottom: 1.8rem; border-bottom: 1px solid var(--line); }
.legal-kicker {
  font-size: .68rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--txt-1); margin-bottom: .7rem;
}
.legal-head h1 {
  margin: 0; font-size: clamp(2rem, 6vw, 2.9rem); font-weight: 900;
  letter-spacing: -.035em; line-height: 1.02; color: var(--txt-1); text-wrap: balance;
}
.legal-meta {
  margin-top: 1rem; display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .55rem;
  font-size: .8rem; font-weight: 500; color: var(--txt-3); font-variant-numeric: tabular-nums;
}
/* The separator is a ::before on every item after the first, so a wrapped
   item carries its own dot — a separate dot element dangles at a line end. */
.legal-meta span { display: inline-flex; align-items: center; }
.legal-meta span + span::before {
  content: ''; width: 3px; height: 3px; border-radius: 999px;
  background: var(--txt-3); opacity: .6; margin-right: .55rem; flex: none;
}

.legal-prose { color: var(--txt-2); line-height: 1.7; }
.legal-prose > h2 {
  margin: 2.6rem 0 .9rem; padding-top: 2.2rem; border-top: 1px solid var(--line);
  font-size: 1.32rem; font-weight: 800; letter-spacing: -.026em; line-height: 1.15; color: var(--txt-1);
  scroll-margin-top: calc(4rem + 1.4rem + env(safe-area-inset-top));
}
.legal-prose > h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* The docs separate their preamble with an <hr>; an h2 straight after it would
   draw a second rule 2rem below the first. One rule, not two. */
.legal-prose > hr { margin: 2.4rem 0 2.2rem; }
/* The docs' first <hr> closes the preamble; the h2 after it draws its own rule. */
.legal-prose > hr:has(+ h2) { display: none; }
.legal-prose > hr + h2 { border-top: 1px solid var(--line); padding-top: 2.2rem; margin-top: 2.6rem; }
.legal-prose h3 { margin: 1.7rem 0 .5rem; font-size: 1rem; font-weight: 750; letter-spacing: -.015em; color: var(--txt-1); }
.legal-prose p { margin: 0 0 1.05rem; }
.legal-prose p:last-child { margin-bottom: 0; }
.legal-prose strong { color: var(--txt-1); font-weight: 650; }
.legal-prose a { color: var(--txt-1); text-decoration: underline; text-decoration-color: rgba(206,255,86,.35); text-underline-offset: .18em; }
.legal-prose a:hover { text-decoration-color: var(--accent-ink); }
.legal-prose ul, .legal-prose ol { margin: 0 0 1.1rem; padding-left: 1.35rem; }
.legal-prose li { margin: .38rem 0; padding-left: .15rem; }
.legal-prose li::marker { color: var(--txt-3); }
.legal-prose hr { border: 0; border-top: 1px solid var(--line); margin: 2rem 0; }
.legal-prose code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85em;
  background: var(--raised); border: 1px solid var(--line); border-radius: 6px; padding: .08em .38em; color: var(--txt-1);
}

/* Statutory notices — the waiver and physical-risk sections. Conspicuous by
   law, so they get a surface AND a border AND an amber rule, never colour
   alone. Same amber as 13a (.consumer-notice): #E4CE93 on --raised = 9.79:1. */
.legal-prose .legal-notice {
  margin: 1.2rem 0 1.4rem; padding: 1.15rem 1.25rem 1.15rem 1.35rem;
  background: var(--card); border: 1px solid rgba(232,184,75,.30);
  border-left: 3px solid rgba(232,184,75,.85); border-radius: var(--radius-sm);
  color: var(--txt-1);
}
.legal-prose .legal-notice p:first-child strong { color: #E4CE93; }
.legal-prose .legal-notice > :last-child { margin-bottom: 0; }

/* Tables — the theme block at 13d owns borders/scroll; this sets the surface. */
.legal-prose .legal-table { margin: 1.1rem 0 1.4rem; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--card); }
.legal-prose table { margin: 0; }
.legal-prose th, .legal-prose td { border: 0; border-bottom: 1px solid var(--line); padding: .7rem .85rem; vertical-align: top; }
.legal-prose th { font-size: .7rem; letter-spacing: .08em; text-transform: uppercase; color: var(--txt-3); background: var(--raised); }
.legal-prose tr:last-child td { border-bottom: 0; }
.legal-prose td { font-size: .88rem; color: var(--txt-2); }
.legal-prose td:first-child { color: var(--txt-1); font-weight: 600; }

/* — end of document — */
.legal-contact {
  margin-top: 3rem; padding: 1.35rem 1.4rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
}
.legal-contact .section-label { margin-bottom: .3rem; }
.legal-contact a:not(.btn) { color: var(--txt-1); font-weight: 650; text-decoration: none; font-size: 1rem; }
.legal-contact a:not(.btn):hover { color: var(--txt-1); }
.legal-cta {
  text-decoration: none; padding: .8rem 1.3rem; font-size: .92rem;
  display: inline-flex; align-items: center; justify-content: center; border-radius: 999px;
  background: var(--k-main-fill); color: #FFFFFF; font-weight: 750;
}
.legal-cta:hover { background: var(--k-main-fill-hover); color: #FFFFFF; }

/* — footer: the SPA's .app-footer, laid out here because Tailwind is absent — */
.legal-foot {
  max-width: 72rem; margin: 0 auto; width: 100%; box-sizing: border-box;
  padding: 1.4rem 1.1rem calc(1.6rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem 1.1rem;
  font-size: .8rem; color: var(--txt-3);
}
.legal-foot a { color: var(--txt-3); text-decoration: none; }
.legal-foot a:hover { color: var(--txt-1); }
.legal-foot .af-mail { margin-left: auto; }
.legal-foot .af-copy { margin-top: 0; }
@media (max-width: 599px) {
  .legal-foot .af-mail { margin-left: 0; flex-basis: 100%; }
}


/* ══════════════════════════════════════════════════════════════════════════
   19. LANDING PAGE  (views.js VIEWS.home — the logged-out front door)

   Reference for FEEL only (Reqwa): one oversized centred headline, product
   screens as the argument, a single pill CTA, quiet everything else. His own
   dashboard mockup leads on surface/radius/type, so every value here is the
   token the dashboard already uses — nothing new.

   THE TWO PHONE SLOTS ARE EMPTY BY DESIGN. Reqwa supplies real iPhone
   screenshots with the device edges in them; they land in .land-shot as an
   <img>. So the slot is sized to a real iPhone aspect (≈ 1 : 2.16) and paints
   NOTHING that could be mistaken for UI — a --sunken well, the hairline, the
   mark at low opacity and a caption. No CSS phone frame (his shots carry
   the device), no fake screen, no fake number.

   Every animation here is transform/opacity only, and reduced-motion resets
   to the END state, never to a 0-opacity frame — that has bitten this codebase
   twice (the boot blocks document both).
   ══════════════════════════════════════════════════════════════════════════ */
.land-hero {
  text-align: center;
  padding: 2.4rem 0 1rem;
}
@media (min-width: 768px) { .land-hero { padding: 4rem 0 1.5rem; } }
.land-eyebrow { display: inline-flex; align-items: center; gap: .45rem; padding: .38rem .85rem; font-size: .74rem; }
.land-eyebrow i { color: var(--txt-1); font-size: .68rem; }
.land-h1 {
  margin: 1.1rem auto 0; max-width: 17ch;
  font-size: clamp(2.35rem, 8.2vw, 4.6rem);
  font-weight: 900; line-height: 1.0; letter-spacing: -.04em;
  color: var(--txt-1); text-wrap: balance;
}
.land-sub {
  margin: 1.2rem auto 0; max-width: 34rem;
  font-size: clamp(1rem, 2.4vw, 1.2rem); line-height: 1.55; color: var(--txt-2);
  text-wrap: pretty;
}
.land-cta { margin-top: 1.8rem; display: flex; flex-direction: column; align-items: center; gap: .9rem; }
@media (min-width: 480px) { .land-cta { flex-direction: row; justify-content: center; gap: 1.4rem; } }
.land-btn { padding: 1.05rem 2.1rem; font-size: 1.02rem; min-width: 12rem; }
.land-link { font-size: .92rem; font-weight: 650; color: var(--txt-3); transition: color .16s; }
.land-link i { font-size: .7rem; margin-left: .25rem; }
.land-link:hover { color: var(--txt-1); }
.land-fine { margin: .9rem auto 0; max-width: 32rem; font-size: .78rem; line-height: 1.5; color: var(--txt-3); }
.land-fine-c { text-align: center; margin-top: 1.4rem; }

/* — the two screenshot slots — */
.land-shots {
  margin: 3rem auto 0; max-width: 46rem;
  display: flex; justify-content: center; align-items: flex-start; gap: 1rem;
  padding: 0 .5rem;
}
.land-shot {
  margin: 0; flex: 1 1 0; min-width: 0; max-width: 17rem;
  aspect-ratio: 1179 / 2556;        /* iPhone 15/16 Pro pixel aspect */
  border-radius: var(--radius-lg);
  background: var(--sunken);
  border: 1px solid var(--line);
  box-shadow: var(--lift-3);
  overflow: hidden;
  position: relative;
  /* Fanned like the reference: slight opposite rotations, the right one a
     touch lower. Transform only, no layout shift. */
  transform: rotate(-3.5deg) translateY(.4rem);
  transition: transform .5s var(--ease);
}
.land-shot + .land-shot { transform: rotate(3.5deg) translateY(1.6rem); }
.land-shots:hover .land-shot { transform: rotate(-1.5deg) translateY(.2rem); }
.land-shots:hover .land-shot + .land-shot { transform: rotate(1.5deg) translateY(1.2rem); }
.land-shot img { display: block; width: 100%; height: 100%; object-fit: cover; }
.land-shot-in {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.1rem;
  padding: 1.5rem;
}
.land-shot-mark { width: 30%; height: auto; opacity: .16; }
.land-shot-cap {
  font-size: .72rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--txt-3); text-align: center;
}
.land-shots-note { margin: 2.2rem 0 0; font-size: .74rem; color: var(--txt-3); }
/* §19b — THE 3D SCROLL MOMENT (Round 4 §3F; JS in views.js landingMotion).
   Only when the script has opted the group in (.is-3d) — so a no-JS or
   reduced-motion visitor keeps the flat fan above, byte for byte. The group
   is the perspective stage; each frame keeps its own transform (set inline
   per frame by the script) and a slow transition so a fast scroll still
   reads as one motion rather than a flicker. The hover rules above are
   disabled here: inline transforms win and the scroll owns the motion. */
.land-shots.is-3d { perspective: 1100px; perspective-origin: 50% 30%; }
.land-shots.is-3d .land-shot { transition: transform .18s linear, opacity .18s linear, box-shadow .4s var(--ease); will-change: transform, opacity; transform-style: preserve-3d; backface-visibility: hidden; }
/* Wave 5 — THE REST STATE IS FLAT (MARKETING-WAVE2 §4). .is-flat is set by
   the script at the end of the scroll AND directly under reduced-motion, so
   the two paths land on the same byte-identical pose: level, parallel, full
   scale, full opacity. The fanned CSS pose above is only ever a starting
   point now, never where the frames rest. */
.land-shots.is-flat .land-shot, .land-shots.is-flat .land-shot + .land-shot,
.land-shots.is-flat:hover .land-shot, .land-shots.is-flat:hover .land-shot + .land-shot { transform: none; opacity: 1; }
.land-shots.is-3d.is-flat .land-shot { box-shadow: var(--lift-3); }
/* Depth read as elevation only — black shadow, deeper as the frame comes
   forward. No glow (rule 2). */
.land-shots.is-3d .land-shot { box-shadow: 0 calc(10px + 14px * var(--land-depth, 0)) calc(30px + 30px * var(--land-depth, 0)) calc(-14px - 6px * var(--land-depth, 0)) rgba(0,0,0,.75); }
html[data-theme="light"] .land-shots.is-3d .land-shot { box-shadow: 0 calc(10px + 14px * var(--land-depth, 0)) calc(30px + 30px * var(--land-depth, 0)) calc(-14px - 6px * var(--land-depth, 0)) rgba(20,21,26,.22); }
@media (prefers-reduced-motion: reduce) { .land-shots.is-3d .land-shot { transition: none; } }
@media (max-width: 479px) {
  .land-shots { gap: .6rem; }
  .land-shot { border-radius: var(--radius); }
  .land-shot-cap { font-size: .62rem; }
}

/* — sections — */
.land-sec { padding: 3.2rem 0 0; }
@media (min-width: 768px) { .land-sec { padding-top: 4.5rem; } }
.land-sec-head { max-width: 38rem; }
.land-sec-head .section-label { display: block; margin-bottom: .7rem; color: var(--txt-1); }
.land-sec-head-c { margin: 0 auto; text-align: center; }
.land-h2 {
  margin: 0; font-size: clamp(1.55rem, 4.2vw, 2.35rem);
  font-weight: 850; line-height: 1.08; letter-spacing: -.033em; color: var(--txt-1); text-wrap: balance;
}
.land-p { margin: .9rem 0 0; font-size: 1rem; line-height: 1.6; color: var(--txt-2); text-wrap: pretty; }
.land-p-quiet { font-size: .86rem; color: var(--txt-3); }

.land-grid { margin-top: 1.6rem; display: grid; gap: .8rem; grid-template-columns: 1fr; }
@media (min-width: 768px) { .land-grid { grid-template-columns: repeat(3, 1fr); gap: 1rem; } }
.land-tile {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.35rem 1.35rem 1.45rem;
}
/* (.land-tile > i: §37 landing rule — DS8 item 5) */
.land-tile h3 { margin: 1rem 0 0; font-size: 1.08rem; font-weight: 800; letter-spacing: -.02em; color: var(--txt-1); }
.land-tile p { margin: .5rem 0 0; font-size: .9rem; line-height: 1.55; color: var(--txt-2); }
.land-fig { color: var(--txt-1); font-weight: 900; }

.land-split { display: grid; gap: 1.6rem; grid-template-columns: 1fr; align-items: center; }
@media (min-width: 900px) {
  .land-split { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 3.5rem; }
  .land-split-rev { direction: ltr; }          /* subject rule; the order swap below is the work */
  .land-split-rev .land-sec-head { order: 2; }
}
.land-list { margin: 0; padding: 0; list-style: none; display: grid; gap: .55rem; }
.land-list li {
  display: flex; align-items: center; gap: .85rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .95rem 1.1rem; font-size: .95rem; font-weight: 600; color: var(--txt-1);
}
.land-list li i { font-size: .85rem; width: 1.1rem; text-align: center; flex: none; }   /* lime ink DELETED (DS7); §37.11 inks it --txt-2 */

/* The coach panel names the three things the coach RETURNS — it is not a
   transcript, and it carries no invented reading (test:nofake's whole point). */
.land-chat {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.1rem; display: grid; gap: .6rem;
}
.land-chat-row { display: flex; }
.land-chat-row span {
  font-size: .9rem; font-weight: 600; padding: .7rem 1rem; border-radius: 18px; max-width: 78%;
}
.land-chat-you { justify-content: flex-end; }
.land-chat-you span { background: var(--accent-fill); color: var(--accent-on); border-bottom-right-radius: 6px; }
.land-chat-op { justify-content: flex-start; }
.land-chat-op span { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line); border-bottom-left-radius: 6px; }

/* — pricing — */
.land-plans { margin-top: 1.8rem; display: grid; gap: .9rem; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 900px) { .land-plans { grid-template-columns: repeat(3, 1fr); gap: 1rem; } }
.land-plan {
  position: relative;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.5rem 1.4rem 1.4rem; display: flex; flex-direction: column;
}
.land-plan.is-hi { border-color: rgba(206,255,86,.5); background: var(--raised); box-shadow: var(--lift-2); }
.land-plan-flag {
  position: absolute; top: -.75rem; left: 1.4rem;
  background: var(--accent-fill); color: var(--accent-on);
  font-size: .66rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  padding: .3rem .7rem; border-radius: 999px;
}
.land-plan-name { font-size: 1.15rem; font-weight: 850; letter-spacing: -.02em; color: var(--txt-1); }
.land-plan-tag { margin-top: .3rem; font-size: .86rem; line-height: 1.45; color: var(--txt-3); min-height: 2.5rem; }
.land-plan-price { margin-top: 1.1rem; display: inline-flex; align-items: baseline; gap: .2rem; white-space: nowrap; }
.land-plan-fig { font-size: 2.3rem; font-weight: 900; letter-spacing: -.04em; line-height: 1; color: var(--txt-1); font-variant-numeric: tabular-nums; }
.land-plan-per { font-size: .95rem; font-weight: 700; color: var(--txt-3); }
.land-plan-year { margin-top: .35rem; font-size: .78rem; color: var(--txt-3); }
/* Launch pricing: the struck regular figure sits beside the charged one, in a
   quieter weight so the price actually charged stays the loudest thing. */
.land-plan-was { font-size: 1.15rem; font-weight: 700; color: var(--txt-3); text-decoration-thickness: 2px; font-variant-numeric: tabular-nums; }
.land-plan-launch { margin-top: .35rem; font-size: .78rem; line-height: 1.45; color: var(--txt-2); }
.land-plan-feats { margin: 1.2rem 0 0; padding: 1.1rem 0 0; list-style: none; border-top: 1px solid var(--line); display: grid; gap: .55rem; flex: 1; }
.land-plan-feats li { display: flex; gap: .65rem; align-items: flex-start; font-size: .88rem; line-height: 1.45; color: var(--txt-2); }
.land-plan-feats li i { color: var(--txt-1); font-size: .72rem; margin-top: .3rem; flex: none; }
.land-plan-excl { margin: .8rem 0 0; padding: 0; list-style: none; display: grid; gap: .3rem; }
.land-plan-excl li { font-size: .78rem; color: var(--txt-3); padding-left: 1.37rem; position: relative; }
.land-plan-excl li::before { content: '–'; position: absolute; left: .3rem; }
.land-plan-btn { margin-top: 1.3rem; width: 100%; padding: .95rem 1rem; font-size: .95rem; }

/* — academies + close — */
.land-gym {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 1.8rem 1.5rem; display: grid; gap: 1.4rem; align-items: center;
}
@media (min-width: 900px) { .land-gym { grid-template-columns: minmax(0, 1fr) auto; padding: 2.4rem 2.6rem; gap: 2.5rem; } }
.land-gym .section-label { display: block; margin-bottom: .6rem; }
.land-close { text-align: center; padding: 4.5rem 0 2rem; }
.land-close .land-p { margin: .8rem auto 0; max-width: 30rem; }
.land-close .land-btn { margin-top: 1.6rem; }

@media (prefers-reduced-motion: reduce) {
  .land-shot, .land-shot + .land-shot { transition: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   20. ONBOARDING FUNNEL — additions to §7-11 (views.js VIEWS.onboarding)

   §7 already owns the rail, question, option rows, grid, belt swatch, footer
   and screen transition; §8 the contrast panel; §9 the prep ("scan") stage;
   §11 the offer primitives. This block adds only what the 15-screen funnel
   needs on top: the academy search, sub-labels on option rows, the clip
   picker, the Pro Week sheet, the done state. Tokens only.
   ══════════════════════════════════════════════════════════════════════════ */
/* The onboarding view renders INSIDE page()'s <main>, which carries padding
   and a max-width. The funnel is a full-bleed phone flow, so it pulls itself
   out to the viewport edges on phones and centres as a column on desktop. */
#app > main.pg-main-ob-2bfe { padding: 0; max-width: none; }
/* No app chrome around the funnel: the account is not set up yet, so a bottom
   nav to Ladder / Game / Coach and a Check-in pill are doors onto empty rooms.
   The topbar still renders (brand + avatar) — the capsule and its clearance go. */
#app.pg-app-main-ob-11c6 > .navdock { display: none; }
#app.pg-app-main-ob-11c6 > .app-footer { display: none; }
#app.pg-app-main-ob-11c6 > header nav,
#app.pg-app-main-ob-11c6 > header .btn-primary,
#app.pg-app-main-ob-11c6 > header .nav-item { display: none; }
.ob { max-width: 30rem; margin: 0 auto; width: 100%; min-height: calc(100dvh - 4rem - env(safe-area-inset-top)); }
@media (min-width: 640px) { .ob { padding-top: 2.5rem; min-height: 0; } }
.ob-back.is-hidden { visibility: hidden; pointer-events: none; }
.ob-back:hover { color: var(--txt-1); border-color: var(--line-2); }

/* Option rows with a second line (belt note, academy city). */
.ob-opt-l { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.ob-opt-l small { font-size: .76rem; font-weight: 500; color: var(--txt-3); margin-top: .12rem; }
.ob-opt.on .ob-opt-l small { color: var(--txt-2); }
.ob-note { margin-top: .9rem; font-size: .78rem; line-height: 1.5; color: var(--txt-3); }
.ob-note.is-live { color: var(--txt-2); display: flex; gap: .5rem; align-items: flex-start; }
.ob-note.is-live i { color: var(--txt-1); margin-top: .2rem; }
.ob-fine { margin-top: 1.1rem; font-size: .82rem; color: var(--txt-3); text-align: center; }

/* Academy search: one text input in the whole funnel, and it is a filter, not
   an answer — Solo is the tap above it. */
.ob-search { position: relative; margin-top: .9rem; }
.ob-search i { position: absolute; left: 1rem; top: 50%; transform: translateY(-50%); color: var(--txt-3); font-size: .85rem; pointer-events: none; }
.ob-search .input { padding-left: 2.6rem; height: 3.1rem; border-radius: var(--radius-sm); }
.ob-gym-list { margin-top: .6rem; max-height: 17rem; overflow-y: auto; scrollbar-width: thin; }

/* THE GUARDIAN PAIR (Wave 4b, WAVE1-COPY (h10)) — two optional inputs under
   the age grid, shown only while 13–15 is picked. Quiet by design: label in
   the tertiary ink, the same .input as the academy search, no asterisk, no
   warning colour, and the (h10) helper as an .ob-note beneath. A field that
   "everything works either way" must not look like a form gate. The wrapper
   fades in with the same easing the option rows use, so it arrives as part of
   the answer rather than as a second screen. */
.ob-guardian { margin-top: 1.1rem; display: grid; gap: .7rem; animation: obGuardianIn .28s var(--ease) both; }
@keyframes obGuardianIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.ob-field { display: grid; gap: .38rem; }
.ob-field-l { font-size: .78rem; font-weight: 650; letter-spacing: -.005em; color: var(--txt-3); }
.ob-field .input { height: 3.1rem; border-radius: var(--radius-sm); font-size: .95rem; }
.ob-guardian .ob-note { margin-top: .1rem; }

/* Footer: Continue full width, Skip a quiet text button beneath. */
.ob-foot { display: flex; flex-direction: column; gap: .5rem; }
.ob-skip { padding: .7rem; font-size: .86rem; font-weight: 600; color: var(--txt-3); text-align: center; }
.ob-skip:hover { color: var(--txt-1); }

/* Clip picker. A generous target — this is the tap the funnel exists for. */
.ob-drop {
  margin-top: 1.6rem; display: flex; flex-direction: column; align-items: center; gap: .35rem;
  padding: 2.4rem 1.2rem; text-align: center; cursor: pointer;
  background: var(--card); border: 1px dashed var(--line-2); border-radius: var(--radius-lg);
  transition: border-color .16s, background .16s, transform .12s var(--ease);
}
.ob-drop:hover { border-color: rgba(206,255,86,.55); background: var(--raised); }
.ob-drop:active { transform: scale(.985); }
.ob-drop-ico {
  width: 3.4rem; height: 3.4rem; display: grid; place-items: center; margin-bottom: .6rem;
  border-radius: 999px; background: var(--accent-fill); color: var(--accent-on); font-size: 1.25rem;
}
.ob-drop-t { font-size: 1.05rem; font-weight: 750; color: var(--txt-1); letter-spacing: -.015em; }
.ob-drop-s { font-size: .82rem; color: var(--txt-3); }

/* The prep stage inside the funnel: §9 sizes it; here the video never autoplays
   and the poster frame is enough. */
.ob .scan { padding: 0; }
.ob .scan-stage { margin-top: 1.4rem; aspect-ratio: 4 / 3; max-height: 34dvh; }
.ob .scan-stage video { opacity: .85; }

/* The Pro Week sheet. Built on .sheet (§ style.css:1130 + theme §5); this is
   its content. Price figures are the server's display strings, never formatted
   here; the strikethrough is the plan's monthly price and the "now" figure is
   the intro price, both from /billing/intro. */
.ob-sheet { max-width: 30rem; padding-bottom: calc(1rem + env(safe-area-inset-bottom)); max-height: 92dvh; overflow-y: auto; }
.ob-sheet-in { padding: 0 1.3rem; }
.ob-sheet-h { margin: .1rem 0 0; font-size: 1.5rem; font-weight: 850; letter-spacing: -.03em; line-height: 1.1; color: var(--txt-1); text-wrap: balance; }
.ob-sheet-sub { margin: .55rem 0 0; font-size: .92rem; line-height: 1.5; color: var(--txt-2); }
.ob-sheet-list { margin: 1.1rem 0 0; padding: 0; list-style: none; display: grid; gap: .5rem; }
.ob-sheet-list li { display: flex; gap: .7rem; align-items: center; font-size: .9rem; font-weight: 600; color: var(--txt-1); }
.ob-sheet-list li i { color: var(--txt-1); width: 1.1rem; text-align: center; font-size: .82rem; flex: none; }
.ob-offer { margin-top: 1.2rem; padding: 1rem 1.1rem; background: var(--card); border: 1px solid rgba(206,255,86,.42); border-radius: var(--radius); }
.ob-offer-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.ob-offer-name { font-size: 1rem; font-weight: 800; color: var(--txt-1); letter-spacing: -.015em; }
.ob-offer-price { display: inline-flex; align-items: baseline; gap: .45rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ob-offer-price .offer-now { font-size: 1.5rem; letter-spacing: -.03em; }
.ob-offer-per { font-size: .82rem; font-weight: 700; color: var(--txt-3); }
.ob-offer-line { margin: .5rem 0 0; font-size: .84rem; line-height: 1.5; color: var(--txt-2); }
.ob-offer-line strong { color: var(--txt-1); font-weight: 700; }
.ob-offer-feats { margin: .8rem 0 0; padding: .8rem 0 0; list-style: none; border-top: 1px solid var(--line); display: grid; gap: .38rem; }
.ob-offer-feats li { display: flex; gap: .55rem; align-items: flex-start; font-size: .82rem; line-height: 1.4; color: var(--txt-2); }
.ob-offer-feats li i { color: var(--txt-1); font-size: .68rem; margin-top: .3rem; flex: none; }
.ob-sheet-go { width: 100%; margin-top: 1.1rem; padding: 1.05rem; font-size: 1rem; }
.ob-sheet-fine { margin: .55rem 0 0; font-size: .76rem; line-height: 1.5; color: var(--txt-3); text-align: center; }
.ob-sheet-not { display: block; width: 100%; margin-top: .6rem; padding: .8rem; font-size: .92rem; font-weight: 650; color: var(--txt-2); }
.ob-sheet-not:hover { color: var(--txt-1); }
.ob-sheet-alt { display: block; width: 100%; padding: .4rem .8rem .2rem; font-size: .82rem; font-weight: 600; color: var(--txt-1); }

/* Done state (already onboarded). */
.ob-done { padding: 2rem 0; }
.ob-done-card { max-width: 26rem; margin: 0 auto; padding: 2rem 1.6rem; text-align: center; }
.ob-done-ico { width: 3.2rem; height: 3.2rem; margin: 0 auto 1rem; display: grid; place-items: center; border-radius: 999px; background: var(--good-weak); color: var(--txt-1); font-size: 1.2rem; }
.ob-done-card h1 { font-size: 1.35rem; font-weight: 850; letter-spacing: -.025em; color: var(--txt-1); }
.ob-done-card p { margin: .6rem 0 1.4rem; font-size: .9rem; line-height: 1.5; color: var(--txt-2); }
.ob-done-card .btn { width: 100%; padding: .95rem; }
.ob-done-actions { display: grid; gap: .55rem; }

@media (prefers-reduced-motion: reduce) {
  .ob-drop, .ob-drop:active { transition: none; transform: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   21. ANALYZE FLOW  (views2.js VIEWS.analysis — where the funnel lands)

   The screen the onboarding sheet sells. Three steps a person can see —
   Pick · Trim · Queue — on one column, in the funnel's own vocabulary
   (§7 option geometry, §9 stage, §20 drop target). The trimmer's ids and
   range mechanics are unchanged (style.css:1900 owns the strip + range);
   this block gives them a surface, a hierarchy and a state.

   LOCKED: `.lock-card` came from the pre-theme layer with a coral gradient,
   a coral hairline and an "Example output" that was three typed coaching
   reads. §2 already strips the gradient; the hairline and the demo are
   retoned here. The demo rows are SHAPE ONLY — a timestamp slot, a bar and a
   role tag — so nothing on the screen reads as a result someone's clip
   produced. Tokens only, no new colours.
   ══════════════════════════════════════════════════════════════════════════ */
.ra { max-width: 30rem; margin: 0 auto; }
.ra-head { margin-bottom: 1.1rem; }
.ra-h1 { color: var(--txt-1); }

/* — the three visible steps — */
.ra-form { display: flex; flex-direction: column; gap: .9rem; }
.ra-steps {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: .4rem;
  margin: 0; padding: 0; list-style: none;
}
.ra-step {
  display: flex; align-items: center; justify-content: center; gap: .45rem;
  padding: .55rem .5rem; border-radius: var(--radius-pill);
  background: var(--card); border: 1px solid var(--line);
  font-size: .8rem; font-weight: 650; color: var(--txt-3);
  transition: color .16s, border-color .16s, background .16s;
}
.ra-step-n {
  display: grid; place-items: center; width: 1.25rem; height: 1.25rem; flex: none;
  border-radius: 999px; font-size: .68rem; font-weight: 800; font-variant-numeric: tabular-nums;
  background: var(--raised); color: var(--txt-2); border: 1px solid var(--line-2);
}
.ra-step.is-now { color: var(--txt-1); border-color: var(--accent-fill); background: var(--accent-weak); }
.ra-step.is-now .ra-step-n { background: var(--accent-fill); color: var(--accent-on); border-color: transparent; }
.ra-step.is-done { color: var(--txt-2); }
.ra-step.is-done .ra-step-n { color: var(--txt-1); border-color: rgba(206,255,86,.45); }

/* — 1. pick: the same drop target the funnel used — */
.ra-drop {
  display: flex; flex-direction: column; align-items: center; gap: .3rem;
  padding: 2.3rem 1.2rem; text-align: center; cursor: pointer;
  background: var(--card); border: 1px dashed var(--line-2); border-radius: var(--radius-lg);
  transition: border-color .16s, background .16s, transform .12s var(--ease);
}
@media (hover: hover) { .ra-drop:hover { border-color: rgba(206,255,86,.55); background: var(--raised); } }
.ra-drop:active { transform: scale(.985); }
.ra-drop:focus-within { border-color: var(--k-focus); }
.ra-drop-ico {
  width: 3.4rem; height: 3.4rem; display: grid; place-items: center; margin-bottom: .55rem;
  border-radius: 999px; background: var(--accent-fill); color: var(--accent-on); font-size: 1.25rem;
}
.ra-drop-t { font-size: 1.05rem; font-weight: 750; color: var(--txt-1); letter-spacing: -.015em; }
.ra-drop-s { font-size: .82rem; color: var(--txt-3); }
.ra-dur { font-size: .82rem; color: var(--txt-3); min-height: 0; margin-top: 0; }
.ra-dur:empty { display: none; }
.ra-dur.is-ok { color: var(--txt-1); }
.ra-dur.is-err { color: #FFB4AB; }   /* the danger ramp's light step; 9.6:1 on ground */

/* — 2. trim — */
.ra-trim { display: flex; flex-direction: column; gap: .7rem; }
.ra-stage {
  position: relative; overflow: hidden;
  border-radius: var(--radius-lg); background: var(--sunken); border: 1px solid var(--line);
}
.ra-stage video { display: block; width: 100%; aspect-ratio: 16 / 9; max-height: 40dvh; object-fit: contain; background: var(--sunken); }
.ra-swap {
  position: absolute; top: .7rem; right: .7rem;
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .45rem .8rem; border-radius: var(--radius-pill);
  background: rgba(10,10,12,.78); border: 1px solid var(--line-2);
  color: var(--txt-1); font-size: .76rem; font-weight: 650;
}
.ra-swap i { font-size: .7rem; }
.ra-trim-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: 0 .15rem; }
.ra-trim-l { font-size: .95rem; font-weight: 750; color: var(--txt-1); letter-spacing: -.015em; }
.ra-trim-sel { font-size: .82rem; font-weight: 650; color: var(--txt-1); }
.ra .ra-filmstrip { height: 52px; border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.ra .ra-filmstrip img { height: 52px; }
.ra .ra-range { margin-top: -1px; border-radius: 0 0 var(--radius-sm) var(--radius-sm); height: 60px; }
.ra .ra-range input::-webkit-slider-thumb { height: 60px; width: 14px; }
.ra .ra-range input::-moz-range-thumb { height: 60px; width: 14px; }
.ra .ra-window { top: 2px; bottom: 2px; }
.ra-trim-foot { display: flex; justify-content: space-between; gap: .6rem; }
.ra-mark { padding: .55rem .95rem; font-size: .82rem; color: var(--txt-1); }
.ra-mark:active { background: var(--k-fill); border-color: var(--txt-1); }
.ra-fine { margin: 0; font-size: .78rem; line-height: 1.5; color: var(--txt-3); }
.ra-fine-c { text-align: center; margin-top: var(--s3); }

/* — 3. name + queue — */
.ra-field { display: flex; flex-direction: column; gap: .45rem; margin-top: .2rem; }
.ra-field-l { font-size: .8rem; font-weight: 650; color: var(--txt-2); padding-left: .15rem; }
.ra-title { height: 3.3rem; border-radius: var(--radius-sm); font-size: .95rem; }
.ra-status {
  padding: .8rem 1rem; border-radius: var(--radius-sm); font-size: .84rem; line-height: 1.45;
  background: var(--card); border: 1px solid var(--line); color: var(--txt-2);
}
.ra-status.is-queued, .ra-status.is-done { border-color: color-mix(in srgb, var(--good) 45%, transparent); color: var(--txt-1); }
.ra-status.is-err, .ra-status.is-failed { border-color: rgba(255,180,171,.45); color: #FFB4AB; }
.ra-go { width: 100%; padding: 1.05rem; font-size: 1rem; margin-top: .2rem; }
/* Step-driven emphasis: before a clip exists the button is present but quiet,
   so the eye goes to the one thing that can happen next — the drop target. */
.ra-form[data-step="pick"] .ra-go { background: var(--raised); color: var(--txt-3); border: 1px solid var(--line); }
.ra-form[data-step="pick"] .ra-field, .ra-form[data-step="pick"] .ra-fine-c { opacity: .55; }

/* — the free door, kept — */
.ra-alt {
  margin-top: 1.4rem; padding: 1.15rem 1.15rem 1.2rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
}
.ra-alt-t { font-size: 1rem; font-weight: 750; color: var(--txt-1); letter-spacing: -.015em; }
.ra-alt-s { margin: .35rem 0 .9rem; font-size: .84rem; line-height: 1.5; color: var(--txt-2); }

/* — locked — */
.ra-lock.lock-card { background: var(--card); border-color: var(--line); padding: 1.4rem 1.25rem 1.2rem; border-radius: var(--radius); }
.ra-lock .lock-title { font-size: 1.5rem; letter-spacing: -.03em; color: var(--txt-1); text-wrap: balance; }
.ra-lock .lock-line { color: var(--txt-2); font-size: .9rem; margin-top: .6rem; }
.ra-demo, .ra-lock .lock-demo { background: var(--sunken); border-color: var(--line); border-radius: var(--radius-sm); padding: 1rem 1rem .9rem; }
.ra-demo-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: .7rem; padding: .5rem 0; }
.ra-demo-row + .ra-demo-row { border-top: 1px solid var(--line); }
.ra-demo-ts {
  font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--txt-3); font-variant-numeric: tabular-nums;
  padding: .2rem .5rem; border-radius: 6px; background: var(--card); border: 1px solid var(--line);
}
.ra-demo-bar { display: block; height: 6px; border-radius: 999px; background: rgba(255,255,255,.07); overflow: hidden; }
.ra-demo-bar > span { display: block; height: 100%; width: 78%; border-radius: 999px; background: var(--raised); border: 1px solid var(--line-2); }
.ra-demo-bar.is-mid > span { width: 56%; }
.is-mid, .is-short { flex: none; }
.ra-demo-bar.is-short > span { width: 34%; background: var(--accent-weak); border-color: rgba(206,255,86,.45); }
.ra-demo-tag { font-size: .74rem; font-weight: 600; color: var(--txt-3); white-space: nowrap; }
.ra-demo-tag.is-key { color: var(--txt-1); }
.ra-demo-note { margin: .8rem 0 0; font-size: .76rem; line-height: 1.5; color: var(--txt-3); }
.ra-lock .lock-alt { color: var(--txt-2); font-size: .84rem; padding: .7rem; }
.ra-lock .lock-alt:hover { color: var(--txt-1); }

@media (prefers-reduced-motion: reduce) {
  .ra-drop, .ra-step, .ra-mark { transition: none; }
  .ra-drop:active { transform: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   22. TIERS SCREEN  (views11.js VIEWS.plans — Designer, Wave 2, 2026-09-04)

   Built to the dashboard mockup's grammar: one radius language (--radius on
   the card, --radius-sm inside it), a hairline plus a flat surface step, a
   big tabular figure, and the accent held for ONE thing per screen — here the
   hero tier's border and its primary pill. The pre-theme .plan-card rules in
   style.css (coral tint, 22px, white flag) are overridden by the `.tier`
   compound below rather than edited: style.css is the pre-theme fallback
   frame and this layer is the source of truth.

   Every figure on the card is the server's string. The Pro Week sentence
   renders from /billing/intro and ONLY while it says eligible — a covered
   member never sees it (test:intro guards the server half).
   ══════════════════════════════════════════════════════════════════════════ */
.tiers { max-width: 30rem; margin: 0 auto; }
.tiers-head { margin-bottom: 1rem; }
.tiers-h1 { color: var(--txt-1); text-wrap: balance; }
.tiers-sub { margin-top: .5rem; font-size: .92rem; line-height: 1.45; color: var(--txt-2); }
.tiers-controls { display: flex; flex-direction: column; gap: .5rem; margin-bottom: 1.1rem; }
.tiers-seg { display: grid; grid-template-columns: 1fr 1fr; }
.tiers-seg .seg-btn { min-height: 44px; font-size: .84rem; }
.tiers-list { display: flex; flex-direction: column; gap: .8rem; }

.plan-card.tier {
  position: relative;
  padding: 1.25rem 1.2rem 1.2rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--lift-1);
}
.plan-card.tier.featured { background: var(--card); border-color: var(--line-2); }
.plan-card.tier.current { border-color: color-mix(in srgb, var(--good) 40%, transparent); }
/* THE HERO. One accent border on the whole screen, and the extra top room is
   for the flag, which sits ON the border rather than floating beside it. */
.plan-card.tier.is-hero { border-color: var(--accent-fill); padding-top: 1.6rem; }
.plan-card.tier.is-intro { padding-top: 1.6rem; }
/* (.tier-flag: §37 plans rule — DS8 item 5) */
.tier-flag.is-quiet { background: var(--raised); color: var(--txt-2); border: 1px solid var(--line-2); }
.tier-flag.is-intro { background: var(--raised); color: var(--txt-1); border: 1px solid rgba(206,255,86,.45); text-transform: none; letter-spacing: 0; font-size: .74rem; }
.plan-card.tier:has(> .tier-flag) { padding-top: 1.6rem; }

.tier-head { display: flex; align-items: baseline; justify-content: space-between; gap: .8rem; }
.tier-name { font-size: 1.25rem; font-weight: 850; letter-spacing: -.025em; color: var(--txt-1); }
.tier-price { margin-left: auto; }
.tier-price .pp-amt { font-size: 1.9rem; font-weight: 850; letter-spacing: -.04em; color: var(--txt-1); }
.tier-price .pp-per { font-size: .78rem; font-weight: 700; color: var(--txt-3); margin-left: .15rem; }
.tier-tag { margin-top: .35rem; font-size: .92rem; line-height: 1.4; color: var(--txt-2); }
.tier-save { margin-top: .6rem; display: inline-flex; align-items: center; gap: .4rem; font-size: .76rem; font-weight: 700; color: var(--txt-1); }
.tier-save i { font-size: .68rem; }

/* The headline feature — the one sentence the hero tier exists to sell,
   lifted out of the list onto its own raised panel. */
.tier-headline {
  margin-top: 1rem; padding: .9rem 1rem;
  background: var(--raised); border: 1px solid var(--line-2); border-radius: var(--radius-sm);
}
.tier-headline-k {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .66rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-1);
}
.tier-headline-k i { font-size: .62rem; }
.tier-headline-t { margin: .4rem 0 0; font-size: .92rem; line-height: 1.45; font-weight: 600; color: var(--txt-1); }

.plan-feats.tier-feats { margin-top: 1rem; gap: .5rem; }
.plan-feats.tier-feats li { font-size: .88rem; line-height: 1.4; color: var(--txt-1); gap: .65rem; }
.plan-feats.tier-feats li i { color: var(--txt-1); font-size: .68rem; margin-top: .3rem; }
.plan-excl.tier-excl { margin-top: .75rem; padding-top: .75rem; border-top: 1px solid var(--line); gap: .45rem; }
.plan-excl.tier-excl li { font-size: .84rem; line-height: 1.4; }
.tier-note { margin: .9rem 0 0; font-size: .82rem; line-height: 1.45; color: var(--txt-3); }
.tier-intro { margin: .9rem 0 0; font-size: .88rem; line-height: 1.45; color: var(--txt-2); }
.tier-intro strong { color: var(--txt-1); font-weight: 750; }
.tier-go { margin-top: 1rem; }
.plan-cta.tier-cta {
  margin-top: 1rem; min-height: 52px; display: flex; align-items: center; justify-content: center; gap: .5rem;
  border-radius: var(--radius-pill); font-size: .95rem; font-weight: 700;
}
.plan-cta.tier-cta.is-free { background: var(--raised); color: var(--txt-2); border: 1px solid var(--line-2); }

.tiers-fair { margin-top: 1.1rem; padding: 1.1rem 1.15rem; }
.tiers-fair-p { margin: .5rem 0 0; font-size: .82rem; line-height: 1.5; color: var(--txt-2); }
.tiers-caps { margin: .9rem 0 0; display: grid; grid-template-columns: 1fr 1fr; gap: .45rem .9rem; }
.tiers-cap { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; font-size: .78rem; min-width: 0; }
.tiers-cap dt { color: var(--txt-3); min-width: 0; }
.tiers-cap dd { margin: 0; font-weight: 750; color: var(--txt-1); flex: none; }
.tiers-note { margin-top: 1rem; text-align: center; font-size: .78rem; color: var(--txt-3); }
@media (max-width: 380px) { .tiers-caps { grid-template-columns: 1fr; } }


/* ── 21a. CONSENT ROWS: THE LONG-TEXT VARIANT (Wave 4a, P1a / P10) ───────
   The two original consents are one short line each ("I agree to the Terms of
   Service"), so `.consent-row` in style.css is sized for a single line beside
   a 22px box. P1a is a 24-word sentence and P10 is longer still, and both are
   legal instruments that ship verbatim — the layout has to take the words, not
   the other way round (Copywriter (h11): "where a slot is tight the answer is
   layout, never words").

   So `.is-long` gives the row top-aligned items, a slightly taller line and a
   little more breathing room, and nothing about it is optional: a consent that
   is hard to read is a consent that is hard to defend. The tick box stays the
   same size and the same 44px-equivalent target — it is the TEXT that grows. */
.consent-row.is-long { align-items: flex-start; padding-top: .7rem; padding-bottom: .7rem; }
.consent-row.is-long .consent-box { margin-top: .1rem; flex: none; }
.consent-row.is-long .consent-text { font-size: 12.5px; line-height: 1.5; text-wrap: pretty; }

/* THE WAIVER'S OWN FINE LINE (P10). Copywriter's, and load-bearing: a buyer
   ticking away a statutory right has to see in the same glance that faults
   are a different matter. Quieter than the tick, never smaller than the
   surrounding fine print, and NOT inside the label — it is not part of what
   is being agreed to. */
.consent-aside {
  margin: .45rem 0 0 2.1rem;
  font-size: .74rem; line-height: 1.5; color: var(--txt-3);
}
.consent-aside a { color: var(--txt-2); text-decoration: underline; text-underline-offset: .16em; }


/* ── 21b. STAFF DASHBOARD HEADER (Wave 4a, DATA-4) ───────────────────────
   The verified-member count used to be labelled with the PLAN NAME, so an
   academy on Academy Plus read as "12 / ACADEMY PLUS" — a figure labelled with
   something it is not a count of. The count keeps "members"; the plan becomes
   its own quiet line underneath. Two facts, two elements, no new colour. */
.staff-head-meta { display: flex; flex-direction: column; align-items: flex-end; gap: .1rem; }
.staff-head-plan {
  margin-top: .25rem;
  font-size: .68rem; font-weight: 700; letter-spacing: -.005em;
  color: var(--txt-3); white-space: nowrap;
}


/* ══════════════════════════════════════════════════════════════════════════
   22b. THE IN-APP PLANS UI, REBUILT IN THE LANDING'S LANGUAGE
        (Wave 4a-7, Reqwa: "Our plans UI in landing page is very good but
        horrid in home page etc, its design doesnt even match our design and
        colors and plans ui could be horizontal everywhere except for the
        landing page.")
   ══════════════════════════════════════════════════════════════════════════
   WHY THE IN-APP CARD LOOKED WRONG, since the diagnosis decides the fix. It
   was not a colour problem — §22 already used the same tokens as the landing.
   It was ANATOMY. The landing card (`.land-plan`, §20) sets the name on its
   own line, then the price as a 2.3rem figure with the cadence beside it, then
   a fixed-height tagline, then a hairline, then the feature list — a vertical
   read where the price is the second thing you see. The in-app card put the
   name and the price on ONE baseline row with `justify-content: space-between`
   at 1.9rem, so on a 390px phone a long tier name and a five-character price
   collided into the middle of the card and the figure stopped being the
   headline. Same tokens, different grammar, and the landing's grammar is the
   one Reqwa signed off.

   So this block re-points the SAME `.plan-card.tier` markup at the landing's
   anatomy instead of introducing a third card. One card language, two
   layouts:

     LANDING  — untouched (`.land-plans`, §20). Explicitly out of scope.
     IN-APP   — a horizontal snap-scroll rail on phones, a row on desktop.

   WHY A RAIL RATHER THAN A STACK. Three stacked cards on a phone put the
   third tier below two full screens of scroll, so the tier the screen exists
   to sell is the one nobody reaches. A rail makes the comparison lateral,
   which is how a price table is read, and `scroll-snap-type: x mandatory` with
   85% card width means one card is centred at rest and the NEXT one is visibly
   peeking — the affordance that tells a thumb there is more. Fixed widths were
   the alternative and they break at 320px.

   The rail applies to every in-app plan surface: `VIEWS.plans` (`.tiers-list`),
   the paywall sheet's plan rail (`.pw-plans`, §22c) and the welcome sheet's
   mini row (`.intro-paid-row`, §22d).

   ACCESSIBILITY, not an afterthought: the rail is a scroll container with real
   focusable buttons inside it, so keyboard and screen-reader order is DOM
   order and unchanged. `overscroll-behavior-x: contain` stops a horizontal
   swipe from triggering the browser's back gesture, which is the bug every
   snap rail ships with once.
   ────────────────────────────────────────────────────────────────────────── */
.tiers { max-width: 64rem; }

.tiers-list {
  /* From `flex-direction: column` to a rail. */
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 85%;
  gap: .8rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: .1rem;
  /* The cards carry a flag that sits ON the top border (-.7rem), and an
     overflow container clips it. The padding is that overhang plus room for
     the lift shadow, and the negative margin puts the content back on the
     page's own gutter so the first card is not indented. */
  padding: 1.1rem .1rem 1.1rem;
  margin-inline: -.1rem;
  /* A rail with a visible scrollbar on desktop looks like a bug; the cards
     themselves are the affordance. */
  scrollbar-width: none;
  align-items: start;
}
.tiers-list::-webkit-scrollbar { display: none; }
.tiers-list > .plan-card { scroll-snap-align: center; height: 100%; }
/* Two tiers (the academy side can be short) should not leave a gap on the
   right; three or more scroll. */
@media (min-width: 720px) {
  .tiers-list {
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
    overflow-x: visible;
    scroll-snap-type: none;
  }
}

/* ── 22b.1 THE CARD, IN THE LANDING'S ANATOMY ────────────────────────────
   Every value below is the landing card's own, so the two cannot drift: name
   1.15rem/850, tagline .86rem on --txt-3 with a fixed min-height so three
   cards keep their prices on one line, price figure 2.3rem/900 tabular, the
   feature list behind a hairline with .55rem gaps. */
.plan-card.tier {
  padding: 1.5rem 1.4rem 1.4rem;
  display: flex;
  flex-direction: column;
  box-shadow: none;
}
.plan-card.tier.is-hero,
.plan-card.tier.is-intro,
.plan-card.tier:has(> .tier-flag) { padding-top: 1.6rem; }
.plan-card.tier.is-hero { background: var(--raised); box-shadow: var(--lift-2); }

/* The head stops being a baseline row: name over price, like the landing. */
.tier-head { display: block; }
.tier-name {
  font-size: 1.15rem; font-weight: 850; letter-spacing: -.02em; color: var(--txt-1);
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
}
.tier-price {
  margin-left: 0; margin-top: 1.1rem;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: .2rem .45rem;
  white-space: nowrap;
}
.tier-price .pp-amt {
  font-size: 2.3rem; font-weight: 900; letter-spacing: -.04em; line-height: 1;
  color: var(--txt-1); font-variant-numeric: tabular-nums;
}
.tier-price .pp-per { font-size: .95rem; font-weight: 700; color: var(--txt-3); margin-left: 0; }
/* DS7 (Reqwa 20:52 UTC): the tagline was pulled ABOVE the name with `order:-1`
   and a negative bottom margin, and overprinted "Academy Plus"/"Academy Pro" at
   390 px. ONE rule now (the DS4 rule at :2480 is restated here, no fight): below
   the name and price, normal flow, quiet ink — same family as .land-plan-tag. */
.tier-tag {
  order: 0;
  margin: var(--s2) 0 0; padding: 0;
  font-size: .86rem; line-height: 1.45; color: var(--txt-3); min-height: 0;
}
.plan-feats.tier-feats {
  margin: 1.2rem 0 0; padding: 1.1rem 0 0;
  border-top: 1px solid var(--line);
  gap: .55rem; flex: 1;
}
.plan-feats.tier-feats li { font-size: .88rem; line-height: 1.45; color: var(--txt-2); }
.tier-go, .plan-cta.tier-cta { margin-top: 1.3rem; }

/* ── 22b.2 CURRENT — the badge, from plan.id ─────────────────────────────
   Was a teal-ish border literal (rgba(45,212,191,.4)) — an off-palette colour
   surviving from the pre-lime theme, exactly the class of leftover this round
   is sweeping. "Current" is a STATE, not an accent, so it takes the neutral
   raised surface and the primary ink; the accent stays on the hero. */
.plan-card.tier.current { border-color: var(--line-2); background: var(--raised); }
.tier-current-badge {
  font-size: .62rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  padding: .22rem .5rem; border-radius: var(--radius-pill);
  background: var(--sunken); border: 1px solid var(--line-2); color: var(--txt-2);
}

/* ── 22b.3 THE LAUNCH PRICE ──────────────────────────────────────────────
   A LABEL and a DISCLOSURE, never a comparator: no strike-through, no "was",
   no percentage, no client countdown (Legal's forbidden list). The chip sits
   beside the figure; the four-element line sits directly under it, in the same
   visual field as the price it qualifies, which is the point Legal made about
   vertical space in a horizontal row — this is where that space is spent. */
.plan-launch {
  align-self: center;
  font-size: .64rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: .24rem .5rem; border-radius: var(--radius-pill);
  background: var(--accent-fill); color: var(--accent-on);
}
/* Struck regular price + saving chip on the tier cards. The charged figure
   stays the loudest element; these are its context, not competition. */
.plan-was {
  align-self: baseline; margin-right: .35rem;
  font-size: 1.05rem; font-weight: 700; color: var(--txt-3);
  text-decoration-thickness: 2px; font-variant-numeric: tabular-nums;
}
.plan-save-pct {
  align-self: center; margin-left: .4rem;
  font-size: .64rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: .24rem .5rem; border-radius: var(--radius-pill);
  background: var(--ok-fill, var(--accent-fill)); color: var(--ok-on, var(--accent-on));
}
.plan-fine {
  margin: .55rem 0 0;
  font-size: .74rem; line-height: 1.45; color: var(--txt-3);
  text-wrap: pretty;
}
.plan-fine .tnum { color: var(--txt-2); font-weight: 700; }
/* The short variant is browse-only (Legal §6.2) and gets one line. */
.plan-fine.is-short { white-space: normal; }

/* ── 22b.4 THE CONTROLS ──────────────────────────────────────────────────
   Two stacked full-width segmented controls ate 100px above the fold. Side by
   side on anything wider than a small phone, and the audience switch keeps
   priority because it changes WHICH plans exist. */
.tiers-controls { flex-direction: row; flex-wrap: wrap; gap: .5rem; }
.tiers-controls > .seg { flex: 1 1 12rem; min-width: 0; }
/* THE 12rem-TALL PILLS (Wave 4b light-mode walk, both themes, ≤400px).
   `flex: 1 1 12rem` is a WIDTH basis in the row layout above. When the
   container turns into a column here, the same basis becomes the HEIGHT — so
   each segmented control rendered as a 192px blob with the two options
   floating in it (plans-390 screenshots, Checkpoint 6). The basis has to be
   reset in the same query that changes the axis. */
@media (max-width: 400px) {
  .tiers-controls { flex-direction: column; }
  .tiers-controls > .seg { flex: 0 0 auto; }
}


/* ══════════════════════════════════════════════════════════════════════════
   22e. THE PRE-CHECKOUT SHEET  (P10 — the withdrawal waiver)
   ══════════════════════════════════════════════════════════════════════════
   The last screen before Paddle. Three things and nothing else: what is being
   bought and what renews (the four ARL facts), the tick, and the button. No
   upsell, no tier comparison, no reassurance block — Legal is explicit that no
   marketing may sit above the renewal terms, and Copywriter's rule is that
   reading it must take five seconds.

   The cancel route is never the smallest text on the surface. That is why the
   aside under the tick is .74rem and the facts paragraph is .86rem, rather
   than the other way round: the sentence a buyer needs later must not be the
   one they cannot read now. */
.ck-sheet { padding-bottom: 1rem; }
.ck-head { margin-bottom: .9rem; }
.ck-title { margin: 0; font-size: 1.2rem; font-weight: 850; letter-spacing: -.02em; color: var(--txt-1); }
.ck-facts {
  margin: .55rem 0 0;
  font-size: .86rem; line-height: 1.55; color: var(--txt-2);
  text-wrap: pretty;
}
.ck-facts strong { color: var(--txt-1); font-weight: 750; }
.ck-facts .tnum { color: var(--txt-1); font-weight: 750; }
.ck-go { margin-top: 1rem; }
/* A disabled primary must read as "not yet", not as broken: the fill drops to
   the sunken step and the ink to the tertiary level, so it is obviously
   inert without going invisible. */
.ck-go:disabled { background: var(--sunken); color: var(--txt-3); border-color: var(--line); box-shadow: none; }


/* ══════════════════════════════════════════════════════════════════════════
   22c. THE PAYWALL SHEET'S PLAN RAIL  (window.paywall)
   ══════════════════════════════════════════════════════════════════════════
   Same decision as §22b and the same reason: the sheet listed the paid tiers
   as full-width stacked rows, so on a phone the second tier was below the fold
   of a sheet the user opened by accident. A rail shows both, and the "unlocks
   this" tier is scroll-snapped first in DOM order.

   A PAYWALL IS A PURCHASE SURFACE, so every card in it owes the full
   disclosure — the price charged, the renewal price and cadence, the cancel
   route. Legal was explicit that the "no dollar figures" rule cannot reach
   here: a paywall showing no price is unlawful. The rule it DOES obey is the
   one about academy credits, and no pool figure renders on this sheet. */
.pw-plans {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 82%;
  gap: .55rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-bottom: .2rem;
}
.pw-plans::-webkit-scrollbar { display: none; }
.pw-plan { scroll-snap-align: center; align-items: flex-start; }
@media (min-width: 560px) {
  .pw-plans { grid-auto-columns: minmax(0, 1fr); overflow-x: visible; scroll-snap-type: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   22d. THE WELCOME SHEET'S TIERS  (plansIntro) — DS2-FIX 2026-09-06
   ══════════════════════════════════════════════════════════════════════════
   Reqwa: "looks very cheap, especially that green and red text box". The
   sheet is now the landing pricing section (§20 .land-plan) at 380 px: the
   same card surface, the same hairline, the same name / figure type scale,
   lime only on the highlighted tile's border + flag and on the check glyphs.
   No semantic green or red anywhere on the sheet — free is not "good" and
   paid is not "danger"; they are two tiers. */
.intro-tiers { display: grid; gap: .6rem; }
.intro-tier {
  position: relative;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .9rem 1rem .85rem;
}
.intro-tier.is-hi { border-color: rgba(206,255,86,.5); background: var(--raised); box-shadow: var(--lift-2); }
.intro-tier.is-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: .75rem;
  padding: .7rem 1rem;
}
.intro-tier-flag {
  position: absolute; top: -.7rem; left: 1rem;
  background: var(--accent-fill); color: var(--accent-on);
  font-size: .6rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  padding: .26rem .6rem; border-radius: 999px;
}
.intro-tier-head { display: flex; align-items: baseline; justify-content: space-between; gap: .75rem; }
.intro-tier-name { font-size: 1rem; font-weight: 850; letter-spacing: -.02em; color: var(--txt-1); }
.intro-tier.is-row .intro-tier-name { font-size: .9rem; font-weight: 700; color: var(--txt-2); }
.intro-tier-price { display: inline-flex; align-items: baseline; gap: .15rem; white-space: nowrap; }
.intro-tier-fig { font-size: 1.35rem; font-weight: 900; letter-spacing: -.04em; line-height: 1; color: var(--txt-1); font-variant-numeric: tabular-nums; }
.intro-tier.is-row .intro-tier-fig { font-size: 1.05rem; }
.intro-tier-per { font-size: .78rem; font-weight: 700; color: var(--txt-3); }
.intro-tier-tag { margin-top: .3rem; font-size: .8rem; line-height: 1.45; color: var(--txt-3); }
.intro-tier .intro-list { margin-top: .75rem; padding-top: .75rem; border-top: 1px solid var(--line); gap: .42rem; }
.intro-tier .intro-list li { font-size: .84rem; line-height: 1.45; color: var(--txt-2); gap: .6rem; }
.intro-tier .intro-list li i { font-size: .7rem; margin-top: .3rem; }
.intro-paid { display: grid; gap: .6rem; }
.intro-paid > .section-label { margin: .35rem 0 -.1rem .15rem; }
.intro-paid > .intro-tier.is-hi { margin-top: .45rem; }


/* ══════════════════════════════════════════════════════════════════════════
   23. COACH PAGE — the two peer pills and the Competition panel
   (views4.js VIEWS.coach / mountCompetition — Designer polish on Engineer's
   Wave 1 markup; ids, handlers and request bodies untouched.)

   THE LOCKED-PILL BUG, found on the served page: §10's `.is-locked` is the
   blurred-result tease (filter: blur(9px); pointer-events: none) and Engineer
   reused the same class name on the Competition pill, so the pill rendered as
   an unreadable smear that could not be tapped — the upgrade path was dead.
   Fixed HERE by scoping the pill's own rule back to sharp + tappable, rather
   than renaming the class (the handler and Engineer's tests read `.is-locked`).
   ══════════════════════════════════════════════════════════════════════════ */
.mode-switch {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 4px;
  margin-bottom: 1rem;
  background: var(--sunken); border: 1px solid var(--line); border-radius: var(--radius-pill);
}
.mode-pill {
  position: relative;
  display: flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 48px; padding: .6rem .9rem;
  border-radius: var(--radius-pill); border: 1px solid transparent;
  background: transparent; color: var(--txt-2);
  font-size: .92rem; font-weight: 700; letter-spacing: -.01em;
  transition: background .16s, color .16s, transform .12s var(--ease);
}
.mode-pill i { font-size: .8rem; }
.mode-pill:active { transform: scale(.975); }
/* .mode-pill.is-active lime DELETED (DS7) — §37.7 makes the active tab a surface step. */
/* Locked: full opacity type, quieter colour, lock glyph — and, critically,
   NO blur and pointer events restored (the §10 tease rule is overridden). */
.mode-pill.is-locked { filter: none; opacity: 1; pointer-events: auto; user-select: auto; color: var(--txt-3); }
.mode-pill.is-locked.is-active { background: var(--raised); color: var(--txt-1); }
.mode-pill .mode-lock { font-size: .68rem; opacity: 1; color: var(--txt-1); margin-left: .1rem; }
.mode-pill.is-active .mode-lock { color: var(--accent-on); }

/* — the Competition panel — one column, funnel geometry, accent on selection only — */
.comp-new { display: flex; flex-direction: column; gap: .8rem; }
.comp-new > .card { padding: 1.05rem 1.1rem; }
.comp-choices { display: grid; gap: .5rem; margin-top: .8rem; }
.comp-choice {
  display: flex; flex-direction: column; align-items: flex-start; gap: .15rem;
  width: 100%; text-align: left; min-height: 56px; padding: .85rem 1rem;
  background: var(--sunken); border: 1px solid var(--line); border-radius: var(--radius-sm);
  color: var(--txt-1); transition: border-color .16s, background .16s, transform .12s var(--ease);
}
.comp-choice:active { transform: scale(.985); }
@media (hover: hover) { .comp-choice:hover { border-color: var(--line-2); background: var(--raised); } }
.comp-choice.is-on { border-color: var(--txt-1); background: var(--k-fill); }
.comp-choice-l { font-size: .95rem; font-weight: 700; letter-spacing: -.01em; }
.comp-choice-s { font-size: .8rem; line-height: 1.4; color: var(--txt-3); }
.comp-choice.is-on .comp-choice-s { color: var(--txt-2); }
/* Rule set: three peers in one row when they fit — a federation is a single
   word and a tall stack of three one-word rows reads as a form. */
.comp-choices[aria-label="Rule set"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.comp-choices[aria-label="Rule set"] .comp-choice { align-items: center; text-align: center; padding: .8rem .5rem; min-height: 64px; justify-content: center; }
.comp-choices[aria-label="Rule set"] .comp-choice-l { font-size: 1rem; font-weight: 800; letter-spacing: .01em; }
.comp-choices[aria-label="Rule set"] .comp-choice-s { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-size: .68rem; }
@media (max-width: 359px) { .comp-choices[aria-label="Rule set"] { grid-template-columns: 1fr; } }

.comp-clips { display: grid; gap: .5rem; margin-top: .8rem; }
.comp-clip {
  display: flex; align-items: center; gap: .8rem; min-height: 52px; padding: .75rem .95rem;
  background: var(--sunken); border: 1px solid var(--line); border-radius: var(--radius-sm); cursor: pointer;
  transition: border-color .16s, background .16s;
}
.comp-clip.is-on { border-color: var(--txt-1); background: var(--k-fill); }
.comp-clip-box { width: 20px; height: 20px; border-radius: 6px; border: 1.5px solid var(--line-2); }
.comp-clip-box:checked { background: var(--accent-fill); border-color: transparent; }
.comp-clip-t { font-size: .92rem; font-weight: 650; }
.comp-clip-s { font-size: .8rem; color: var(--txt-3); }
.comp-new .input { min-height: 52px; border-radius: var(--radius-sm); font-size: .95rem; }
.comp-new #comp-start { margin-top: .2rem; }
.comp-new #comp-start:disabled { background: var(--raised); color: var(--txt-3); border: 1px solid var(--line); opacity: 1; }
.comp-dossier { border-radius: var(--radius-sm); padding: .75rem .5rem; }
.comp-dossier .comp-clip-t { flex: 1; }

/* Session view: the turn counter is the honesty signal (20 is the point), so
   it gets a pill, not a caption. Colour joins the number only at the end. */
.comp-session .chip { min-height: 32px; font-size: .74rem; }
.comp-turns {
  display: inline-flex; align-items: center; gap: .35rem; min-height: 32px; padding: 0 .75rem;
  border-radius: var(--radius-pill); background: var(--raised); border: 1px solid var(--line-2);
  font-size: .78rem; font-weight: 800; color: var(--txt-1); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.comp-turns small { font-size: .66rem; font-weight: 700; color: var(--txt-3); letter-spacing: .04em; text-transform: uppercase; }
.comp-turns.is-last { border-color: rgba(206,255,86,.5); color: var(--txt-1); }
.comp-turns.is-locked-turns { color: var(--txt-3); }


/* — §21 addendum: the analyze strip's RUNNING state. The poller emits
   is-queued / is-running / is-done / is-failed; §21 styled queued/done/err/
   failed and "running" fell to the default border. Running is the accent —
   the one moment the strip is live — queued stays the semantic teal. — */
.ra-status.is-running {
  border-color: rgba(206,255,86,.55); color: var(--txt-1);
  padding-left: 2.4rem; position: relative;
}
.ra-status.is-running::before {
  content: ''; position: absolute; left: 1rem; top: 50%; width: .7rem; height: .7rem; margin-top: -.35rem;
  border-radius: 999px; border: 2px solid rgba(206,255,86,.35); border-top-color: var(--accent-ink);
  animation: raSpin .9s linear infinite;
}
@keyframes raSpin { to { transform: rotate(360deg); } }
.ra-status.is-info { border-color: var(--line-2); color: var(--txt-2); }

@media (prefers-reduced-motion: reduce) {
  .ra-status.is-running::before { animation: none; border-top-color: var(--accent-ink); }
  .mode-pill, .comp-choice { transition: none; }
  .mode-pill:active, .comp-choice:active { transform: none; }
}
.comp-empty { margin: 0 .15rem .2rem; font-size: .95rem; line-height: 1.45; color: var(--txt-2); }
.comp-fine { margin: 0; text-align: center; font-size: .78rem; line-height: 1.5; color: var(--txt-3); }

/* — the chat dock's surface. style.css painted it with a gradient that §2
   strips, leaving a TRANSPARENT sticky input over the conversation (found on
   the served Coach page: the composer sat on top of the bubble text). A flat
   ground fill with a hairline above; same fix for the Competition thread. — */
.chat-dock { background: var(--ground); border-top: 1px solid var(--line); }
.chat-dock .input { min-height: 52px; border-radius: var(--radius-pill); padding-left: 1.1rem; }
.chat-dock .btn-primary { min-width: 52px; }


/* ══════════════════════════════════════════════════════════════════════════
   24. SPOTLIGHT  (views2.js — the step between Trim and Queue; copy §(d))

   Reqwa's bar: reads as premium, not as a form. So: the funnel's kicker +
   big statement headline (§7), chips in the funnel's own option geometry
   (card surface, hairline, accent tint when on — three channels, never colour
   alone), one label per group, 44px+ targets throughout, and errors that sit
   ON the group that needs them rather than in a banner. No number is typed.
   ══════════════════════════════════════════════════════════════════════════ */
.sl { display: flex; flex-direction: column; gap: 1.15rem; }
.sl-head { display: flex; flex-direction: column; }
.sl-head .ob-kicker { margin-bottom: .45rem; }
.sl-h { font-size: 1.72rem; line-height: 1.1; font-weight: 800; letter-spacing: -.032em; color: var(--txt-1); text-wrap: balance; }
.sl-sub { margin-top: .5rem; font-size: .92rem; line-height: 1.45; color: var(--txt-2); }
.sl-group { display: flex; flex-direction: column; gap: .55rem; }
.sl-label { font-size: .8rem; font-weight: 700; color: var(--txt-2); padding-left: .15rem; letter-spacing: -.005em; }
.sl-group.is-set .sl-label { color: var(--txt-1); }
.sl-chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.sl-chip {
  display: inline-flex; align-items: center; gap: .55rem;
  min-height: 46px; padding: .6rem 1.05rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-pill);
  color: var(--txt-1); font-size: .92rem; font-weight: 600; letter-spacing: -.01em;
  transition: background .15s, border-color .15s, transform .12s var(--ease);
}
.sl-chip:active { transform: scale(.97); }
@media (hover: hover) { .sl-chip:hover { background: var(--raised); border-color: var(--line-2); } }
.sl-chip.on { background: var(--k-fill); border-color: var(--txt-1); }
.sl-chip.on::before { content: ''; width: .45rem; height: .45rem; border-radius: 999px; background: var(--accent-fill); flex: none; }
.sl-chip .ob-belt { width: 18px; height: 18px; border-radius: 5px; }
/* Junior swatches: the belt IS the answer, so the swatch shows the rank.
   Belt hues are RANK colours, not accents — declared as --belt-* tokens so the
   design gate's semantic-hue reader files them where they belong. */
:root { --belt-grey: #9CA3AF; --belt-yellow: #FBBF24; --belt-orange: #F97316; --belt-green: #10B981; }
.ob-belt.is-grey   { background: var(--belt-grey); }
.ob-belt.is-yellow { background: var(--belt-yellow); }
.ob-belt.is-orange { background: var(--belt-orange); }
.ob-belt.is-green  { background: var(--belt-green); }
.sl-help { margin: 0; padding-left: .15rem; font-size: .8rem; line-height: 1.45; color: var(--txt-3); }
.sl-err { display: none; margin: 0; padding-left: .15rem; font-size: .8rem; line-height: 1.45; color: #FFB4AB; }
.sl-group.is-open .sl-err { display: block; }
.sl-group.is-open .sl-chip { border-color: rgba(255,180,171,.45); }
.sl-err-all.is-show { display: block; text-align: center; padding: 0; }
.sl-field { margin-top: .1rem; }
.sl-optional { font-size: .78rem; color: var(--txt-3); padding-left: .15rem; }
.sl-actions { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: .6rem; margin-top: .3rem; }
.sl-back { color: var(--txt-1); }
.sl-go { font-weight: 750; }
.sl-go i { font-size: .85rem; }
/* The stepper grows to four; keep it one row down to 360 by letting the
   labels tighten rather than wrapping. */
.ra-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .35rem; }
.ra-step { padding: .55rem .3rem; font-size: .76rem; gap: .35rem; min-height: 40px; white-space: nowrap; }
@media (max-width: 379px) { .ra-step { font-size: .7rem; } .ra-step .ra-step-n { width: 1.1rem; height: 1.1rem; font-size: .62rem; } }
.ra-prequeue { display: flex; flex-direction: column; gap: .9rem; }
.ra-form[data-step="spotlight"] .ra-fine-c, .ra-form[data-step="queue"] .ra-fine-c { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .sl-chip { transition: none; } .sl-chip:active { transform: none; } }


/* ══════════════════════════════════════════════════════════════════════════
   25. ROLLS LIBRARY  (views2.js VIEWS['rolls-library'] — placeholder id)
   The dashboard mockup's "Recent rolls" row, made a list: 56px tile, title,
   quiet sub-line, day chip; the detail keeps the Roll-analysis header.
   ══════════════════════════════════════════════════════════════════════════ */
.rl { max-width: 30rem; margin: 0 auto; }
.rl-detail { padding-bottom: .5rem; }
.rl-list { display: flex; flex-direction: column; gap: .6rem; }
.rl-card {
  display: flex; align-items: center; gap: .85rem; width: 100%; text-align: left;
  min-height: 72px; padding: .8rem .9rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--txt-1); transition: background .15s, border-color .15s, transform .12s var(--ease);
}
.rl-card:active { transform: scale(.985); }
@media (hover: hover) { .rl-card:hover { background: var(--raised); border-color: var(--line-2); } }
.rl-thumb {
  width: 48px; height: 48px; flex: none; display: grid; place-items: center;
  border-radius: var(--radius-sm); background: var(--sunken); border: 1px solid var(--line);
  color: var(--txt-3); font-size: .85rem;
}
/* Wave 3 §3G rhythm: the same .6rem gap and 72px row as the Home docks; a
   finished read's thumb takes the accent as INK so the list scans by state
   (done / pending / failed) without a second colour. */
/* .rl-thumb.is-done lime tint DELETED (DS7) — done is a state, not a CTA; §37.2 inks it. */
.rl-card + .rl-card { margin-top: 0; }
.rl-main { display: flex; flex-direction: column; gap: .2rem; min-width: 0; flex: 1; }
.rl-t { font-size: .97rem; font-weight: 700; letter-spacing: -.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rl-s { font-size: .8rem; color: var(--txt-2); }
.rl-s.is-pending { color: var(--txt-1); }
.rl-cleared { color: var(--txt-3); }
.rl-day { flex: none; min-height: 30px; font-size: .74rem; }
.rl-fine { margin-top: 1rem; }
.rl-empty { display: flex; flex-direction: column; align-items: center; gap: .3rem; padding: 2.3rem 1.3rem 1.6rem; text-align: center; }
.rl-empty .ra-drop-s { max-width: 22rem; }
.rl-empty-go { margin-top: 1.1rem; width: 100%; }

.rl-detail-head { display: flex; align-items: flex-start; gap: .85rem; }
.rl-back { margin-top: .15rem; }
.rl-title { overflow-wrap: anywhere; }
.rl-stage { margin-bottom: .9rem; }
.rl-stage video { display: block; width: 100%; aspect-ratio: 16 / 9; max-height: 40dvh; object-fit: contain; background: var(--sunken); }
.rl-nofootage {
  display: flex; align-items: center; gap: .65rem; margin-bottom: .9rem;
  padding: .85rem 1rem; border-radius: var(--radius-sm);
  background: var(--sunken); border: 1px dashed var(--line-2); color: var(--txt-3); font-size: .84rem;
}
.rl-read, .rl-chat { padding: 1.1rem 1.15rem; }
.rl-chat { margin-top: .9rem; }
.rl-read-head { display: flex; align-items: center; justify-content: space-between; gap: .8rem; }
.rl-score {
  display: inline-flex; align-items: baseline; gap: .35rem; font-size: 1.35rem; font-weight: 850; letter-spacing: -.03em; color: var(--txt-1);
}
.rl-score small { font-size: .64rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--txt-3); }
.rl-summary { margin: .7rem 0 0; font-size: .95rem; color: var(--txt-1); }
.rl-sec { margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--line); }
.rl-sec-k { display: inline-flex; align-items: center; gap: .4rem; font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-1); }
.rl-sec-t { margin: .4rem 0 0; font-size: .92rem; line-height: 1.5; color: var(--txt-1); }
.rl-log { display: flex; flex-direction: column; gap: .5rem; margin-top: .8rem; }
.rl-bub {
  max-width: 88%; padding: .7rem .95rem; border-radius: var(--radius-sm);
  background: var(--raised); border: 1px solid var(--line); color: var(--txt-1); font-size: .9rem; line-height: 1.5; align-self: flex-start;
}
.rl-bub.is-you { align-self: flex-end; background: var(--accent-fill); color: var(--accent-on); border-color: transparent; }
.rl-bub.is-typing { color: var(--txt-3); }
.rl-chat-empty { margin: .8rem 0 0; font-size: .88rem; line-height: 1.5; color: var(--txt-2); }
.rl-chat-done { margin: .9rem 0 0; font-size: .84rem; line-height: 1.5; color: var(--txt-3); }
.rl-compose { display: flex; gap: .5rem; margin-top: .9rem; }
.rl-compose .input { min-height: 52px; border-radius: var(--radius-pill); padding-left: 1.1rem; }
.rl-compose .btn { min-width: 52px; flex: none; }
@media (prefers-reduced-motion: reduce) { .rl-card { transition: none; } .rl-card:active { transform: none; } }

/* — dashboard: Recent rolls (the mockup's rows), views4.js — */
.rr { min-width: 0; }
.rr-all { display: inline-flex; align-items: center; gap: .35rem; min-height: 32px; padding: 0 .35rem; font-size: .8rem; font-weight: 700; color: var(--txt-1); }
.rr-list { display: flex; flex-direction: column; gap: .55rem; }
.rr-row {
  display: flex; align-items: center; gap: .85rem; width: 100%; text-align: left;
  min-height: 68px; padding: .7rem .85rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--txt-1); transition: background .15s, border-color .15s, transform .12s var(--ease);
}
.rr-row:active { transform: scale(.985); }
@media (hover: hover) { .rr-row:hover { background: var(--raised); border-color: var(--line-2); } }
.rr-thumb { width: 46px; height: 46px; flex: none; display: grid; place-items: center; border-radius: var(--radius-sm); background: var(--sunken); border: 1px solid var(--line); color: var(--txt-3); font-size: .8rem; }
.rr-thumb.is-done { color: var(--txt-1); border-color: var(--line-2); }
.rr-main { display: flex; flex-direction: column; gap: .15rem; min-width: 0; flex: 1; }
.rr-t { font-size: .95rem; font-weight: 700; letter-spacing: -.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rr-s { font-size: .78rem; color: var(--txt-2); }
.rr-s.is-pending { color: var(--txt-1); }
.rr-day { flex: none; min-height: 28px; font-size: .72rem; }
@media (prefers-reduced-motion: reduce) { .rr-row { transition: none; } .rr-row:active { transform: none; } }


/* ── 23b. COMPETITION — the two doors (Wave 3, copy (g5)) ──────────────────
   Two equal choices on the .comp-choice primitive with an icon, stacked on a
   phone and side by side from 480px. Nothing marks one as the default. */
.comp-doors { grid-template-columns: 1fr; }
@media (min-width: 480px) { .comp-doors { grid-template-columns: 1fr 1fr; } }
.comp-door { display: grid; grid-template-columns: 1.6rem 1fr; column-gap: .7rem; align-items: start; text-align: left; }
.comp-door-i { grid-row: 1 / span 2; margin-top: .2rem; color: var(--txt-3); font-size: .95rem; text-align: center; }
.comp-door.is-on .comp-door-i { color: var(--txt-1); }
.comp-door .comp-choice-l, .comp-door .comp-choice-s { grid-column: 2; }
.comp-door .comp-choice-s { white-space: normal; line-height: 1.4; }
.comp-built { margin: 0 0 .75rem; font-size: .8rem; line-height: 1.5; color: var(--txt-3); }

/* ══════════════════════════════════════════════════════════════════════════
   28. ACADEMY ROLL CREDITS  (Round 3 §3 — owner dashboard, roster cell, member
       pill and refusals; Designer Wave 3). Tokens only. The meter is the same
       flat track + accent fill as every progress bar here; the 80% state is a
       heads-up (accent stays), the spent state moves the fill to the quiet ink
       — never a warning colour (f2 framing).
   ══════════════════════════════════════════════════════════════════════════ */
.rc { position: relative; }
.ra-refusal { display: block; }
.rc-title { font-size: 1rem; font-weight: 750; letter-spacing: -.015em; line-height: 1.25; }
.rc-line { margin-top: .35rem; font-size: .84rem; line-height: 1.5; color: var(--txt-2); }
.rc-fig { font-size: 1.6rem; font-weight: 850; letter-spacing: -.03em; line-height: 1; }
.rc-fig span { font-size: .95rem; font-weight: 650; color: var(--txt-3); letter-spacing: -.01em; }
.rc-left { margin-top: .5rem; font-size: .95rem; font-weight: 700; color: var(--txt-1); }
.rc-meter { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; }
.rc-meter > span { display: block; height: 100%; border-radius: inherit; background: var(--accent-fill); transition: width .6s var(--ease); }
.rc-meter.is-spent > span { background: var(--txt-3); }
.rc-foot { margin: .5rem 0 0; font-size: .76rem; line-height: 1.45; color: var(--txt-3); }
.rc-block { margin-top: 1.25rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.rc-label { display: block; font-size: .92rem; font-weight: 750; letter-spacing: -.01em; }
.rc-help { margin: .3rem 0 .7rem; font-size: .8rem; line-height: 1.45; color: var(--txt-3); }
.rc-row { display: flex; gap: .5rem; align-items: center; }
.rc-num { width: 6.5rem; flex: none; text-align: center; }
.rc-packs { display: grid; gap: .5rem; }
@media (min-width: 640px) { .rc-packs { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.rc-pack {
  display: block; width: 100%; text-align: left; min-height: 56px; padding: .9rem 1rem;
  background: var(--sunken); border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-size: .86rem; line-height: 1.45; color: var(--txt-1);
  transition: border-color .15s, background .15s, transform .12s var(--ease);
}
.rc-pack-l { display: block; }
@media (hover: hover) { .rc-pack:not([disabled]):hover { border-color: var(--line-2); background: var(--raised); } }
.rc-pack:not([disabled]):active { transform: scale(.985); }
.rc-packs.is-off .rc-pack { opacity: .55; cursor: default; }
/* Roster cell: label, value, and an inline editor that stays on one row. */
.rc-roster-help { margin: -.25rem 0 .75rem; font-size: .78rem; color: var(--txt-3); }
.rc-cell { display: grid; grid-template-columns: 1fr; gap: .3rem; margin-top: .6rem; padding-top: .6rem; border-top: 1px dashed var(--line); }
.rc-cell-h { font-size: .66rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-3); }
.rc-cell-v { font-size: .9rem; font-weight: 750; }
.rc-cell-v small { font-size: .78rem; font-weight: 500; color: var(--txt-3); }
.rc-cell-edit { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }
.rc-cell-edit .rc-num { width: 5.2rem; min-height: 40px; }
.btn-sm { min-height: 40px; padding: .45rem .9rem; }
/* Member pill on the analyze / Film Room headers. */
.ra-allow { margin-top: .7rem; background: var(--accent-weak); color: var(--txt-1); border: 1px solid transparent; font-weight: 700; }
/* Refusal block replaces the status strip: a state, not an error. */
.ra-status.is-refusal { border-color: var(--line-2); color: var(--txt-1); text-align: left; padding: 1rem 1.1rem; }
.ra-refusal-t { font-weight: 750; font-size: .98rem; letter-spacing: -.015em; }
.ra-refusal-l { margin: .35rem 0 .8rem; font-size: .84rem; line-height: 1.5; color: var(--txt-2); }
.tier-fair { margin: .7rem 0 0; font-size: .78rem; line-height: 1.45; color: var(--txt-3); }

/* ══════════════════════════════════════════════════════════════════════════
   26. ACCOUNT CONTROLS  (views2.js VIEWS.profile — Me screen, Wave 2)
   Quiet rows, one destructive row on the danger ramp (desaturated, per §9),
   sheets built on the Pro Week sheet primitives (§20) so they read as one
   family. The grace line is drawn from a data attribute via attr() and shows
   nothing when the attribute is empty — a number is never typed here.
   ══════════════════════════════════════════════════════════════════════════ */
.acct { margin-top: 1rem; padding: 1rem; }
.acct-rows { display: flex; flex-direction: column; gap: .45rem; }
.acct-row {
  display: grid; grid-template-columns: 1.5rem 1fr; column-gap: .8rem; align-items: center;
  width: 100%; text-align: left; min-height: 52px; padding: .75rem .95rem;
  background: var(--sunken); border: 1px solid var(--line); border-radius: var(--radius-sm);
  color: var(--txt-1); font-size: .95rem; font-weight: 650; letter-spacing: -.01em;
  transition: background .15s, border-color .15s;
}
@media (hover: hover) { .acct-row:hover { background: var(--raised); border-color: var(--line-2); } }
.acct-row i { grid-row: 1 / span 2; color: var(--txt-3); font-size: .9rem; text-align: center; }
.acct-row small { grid-column: 2; font-size: .78rem; font-weight: 500; color: var(--txt-3); line-height: 1.35; margin-top: .1rem; }
.acct-row.is-danger { color: #FFB4AB; border-color: rgba(255,180,171,.22); }
.acct-row.is-danger i { color: #FFB4AB; }
.acct-row.is-scheduled { cursor: default; border-color: rgba(232,184,75,.42); background: var(--card); }
.acct-row.is-scheduled i { color: #E4CE93; }
.acct-row.is-scheduled span { color: #E4CE93; }
.acct-cancel { grid-column: 1 / -1; margin-top: .6rem; justify-self: start; min-height: 44px; }
.acct-sheet { max-width: 30rem; padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }
.acct-form { display: flex; flex-direction: column; gap: .9rem; margin-top: 1.1rem; }
.acct-go { margin-top: .2rem; }
.acct-grace:not([data-grace-days=""])::before { content: ' You have ' attr(data-grace-days) ' days to change your mind.'; }
/* Coach header mark: the Tailwind gradient tile (op→flame) is a §2 violation
   that only survived because it was painted from the utility ramp. One flat
   accent tile with dark ink, like the mockup's FAB. */
.coach-mark { width: 44px; height: 44px; border-radius: var(--radius-sm); background: var(--accent-fill); color: var(--accent-on); font-size: 1.05rem; }

/* ═══════════ §27 — Engineer Round 2 hooks (append-only; Designer to restyle) ═══════════
   Three states the Round 2 wiring introduces and Designer's §21-26 had no class for.
   Tokens only, no new colours. Designer: fold into §21/§23/§25 in your pass. */
/* Film Room detail: timestamped moment rows (the paywall demo's row shape, real data). */
.rl-moments { margin: .9rem 0 .4rem; }
.rl-moment.ra-demo-row { grid-template-columns: auto 1fr; align-items: start; }
.rl-moment-t { font-size: .86rem; line-height: 1.5; color: var(--txt-2); }
.rl-moment-who { color: var(--txt-3); }
/* Analyze strip: the clip-floor refusal reads as a plain refusal, not a failure. */
.ra-status.is-too_short { border-color: var(--line-2); color: var(--txt-2); }
.ra-rotated { margin-top: .6rem; }
/* Coach page: the one quiet transient line (Addendum K) in place of the diagnostic card. */
.coach-quiet { margin: 0 0 .75rem; font-size: .8rem; line-height: 1.5; color: var(--txt-3); }


/* ── 28a. WELCOME / PATH SHEETS get a real surface (Wave 3). `.intro-card`
   in style.css was painted ONLY by a gradient, which §2 strips — so the card
   rendered transparent over the page (visible in the 2026-09-04 light-mode
   screenshots as content bleeding through). A flat raised surface + hairline,
   same as every sheet. The cropped belt mark above the title is gone (Reqwa). */
.intro-card { background: var(--raised); border: 1px solid var(--line); box-shadow: var(--lift-3); }
.intro-hero { margin-top: .25rem; }

/* ══════════════════════════════════════════════════════════════════════════
   29. LIGHT MODE  (Designer, Wave 3, 2026-09-04 — Reqwa: "integrate light
       mode and dark mode, togglable and by default synced with the device")
   ══════════════════════════════════════════════════════════════════════════
   HOW IT WORKS
   · The dark set in §1 stays THE theme and is untouched. Light is a second
     value for every token, keyed on html[data-theme="light"]. Nothing else in
     this file changes for light mode to exist — every rule that already reads
     a token re-paints itself.
   · Bootstrap (src/shell.ts, inline in <head> BEFORE the stylesheets): reads
     localStorage 'op-theme' ∈ light|dark|system (default system), resolves
     system against prefers-color-scheme, sets data-theme on <html>, and keeps
     listening to the media query while the choice is 'system'. Setting it in
     <head> means the first frame is already the right colour — no flash.
   · The toggle lives on the Me screen (views2.js, "Appearance", copy (g4)) and
     writes localStorage only (R4-B5: client-side, no server column).

   THE FOUR RULES HOLD IN LIGHT TOO: no gradients on UI surfaces, no coloured
   glow, one accent, depth = hairline + flat step. Elevation shadows soften
   (black at lower alpha) because a black shadow on a white page is a bigger
   visual event than on near-black.

   THE ACCENT — ONE LIME IN BOTH MODES (Reqwa, 2026-09-05, final).
   The Wave 3 answer was a second lime: --accent-ink darkened to #3F6E00 for
   text on white. Reqwa rejected it twice — the deep olive is not the brand,
   and a brand whose accent changes hue between modes has two accents. My
   #6C9800 compromise was rejected for the same reason. So:
     --accent-fill stays #CEFF56 (brand fill: primary button, FAB, active nav,
       progress), carrying --accent-on dark ink at 16.9:1. Unchanged.
     --accent-ink stays #CEFF56 TOO. The lime is the lime in both modes.
   #CEFF56 as text on #FFFFFF is 1.16:1, so the contrast is not solved by the
   colour — it is solved by the SURFACE. §29.4 gives every element that paints
   accent-ink as text or as a glyph a dark backing in light mode: an inline
   chip for glyphs and labels, a pill for badges, an inline highlight for the
   few prose accents. #CEFF56 on the backing #16171B is 15.4:1 — the same
   reading experience as dark mode, because it IS dark mode, locally.
   Two consequences, both deliberate:
     · The dark set is untouched: §29.4 is scoped to html[data-theme="light"],
       so dark mode never pays for a chip it does not need.
     · Anything that paints accent-ink as a BORDER, a FILL or an ::before dot
       needs no chip — a lime hairline on white is a hairline, not text. Those
       are listed as exempt in §29.4 so the next reader does not "fix" them.
   The Tailwind ramp (src/shell.ts) cannot be re-keyed per theme, so the
   text-op-* utilities are remapped below by attribute selector — same trick
   the ramp comment warns about, applied deliberately and documented here.

   CONTRAST (computed, light set):
     txt-1 #16171B on card #FFFFFF 17.9:1 · on ground #F4F4F6 16.3:1
     txt-2 #474B54 on card  8.7:1  · on ground 8.0:1
     txt-3 #676C76 on card  5.3:1  · on ground 4.8:1   ← the floor, ≥ 4.5 on both
     accent-ink #CEFF56 on its own backing #16171B 15.42:1 (§29.4 — never
       painted as bare text on card or ground; the chip is the contrast)
     good #0B6B63 6.4:1 · flame/warn #8A5B00 5.9:1 · danger #9A404F 6.6:1
     accent-on #0A0A0C on accent-fill #CEFF56 17.0:1 (unchanged)
   ────────────────────────────────────────────────────────────────────────── */
html[data-theme="light"] {
  color-scheme: light;

  --ground:   #F4F4F6;   /* page — a cool off-white, same 240° cast as the dark ground so the two modes are one family */
  --card:     #FFFFFF;   /* card on ground — the step is UP in light mode; cards are the brightest surface, like paper */
  --raised:   #FFFFFF;   /* sheet, popover, stat panel — same paper; separation carried by the hairline + lift */
  --sunken:   #EAEAEE;   /* inputs, media wells, the scan stage — a step DOWN from the ground */

  --line:     rgba(20,21,26,.09);
  --line-2:   rgba(20,21,26,.16);

  --txt-1:    #16171B;
  --txt-2:    #474B54;
  --txt-3:    #676C76;

  /* ONE lime, both modes (Reqwa 2026-09-05). The hex does not change per
     theme — but HOW it is used does (DS4 item 1, Reqwa 2026-09-06: "remove the
     black outline on text, icons and anything like that in light mode
     everywhere"). The Wave 3 answer put a dark plate (--accent-back, #16171B)
     behind every lime glyph and label so the lime stayed legible on white.
     Those plates ARE the black outlines Reqwa sees: a black pill behind "BJJ"
     in the wordmark, a black chip behind every feature tick, a black box
     behind the streak figure. §29.4 no longer paints them.
     In light mode the lime is a FILL colour only (primary button, FAB, active
     dot, progress ring, focus ring, selected borders) — all of which are
     legible as shapes at any contrast. Lime as TYPE falls back to the page
     ink (--txt-1 / --txt-2) in §29.4, so a light screen has exactly the same
     accent as a dark one, on exactly the surfaces where a colour is a shape
     rather than a letter. */
  --accent-ink:  #CEFF56;
  --accent-fill: #CEFF56;
  --accent-on:   #0A0A0C;
  --accent-back: #16171B;   /* declared for var() honesty; painted only on media wells (§29.4) */
  /* --accent-weak stays a SUBTLE tint: it marks selected rows, and a row tint
     is not a text backing. Lime-tinted (not neutral) so a selected row in
     light mode reads as "the brand chose this", the same as in dark. */
  --accent-weak: rgba(206,255,86,.28);

  --good:      #1C1C1E;   /* light theme A (Uozot 10 Oct): no greens */
  --good-soft: #1C1C1E;   /* light theme A (Uozot 10 Oct): no greens */
  --good-fill: #CEFF56;   /* light theme A (Uozot 10 Oct): no greens */
  --good-weak: rgba(206,255,86,.32);   /* light theme A (Uozot 10 Oct): no greens */

  /* Semantic warn/danger inks, light. (Dark mode paints these as literals in
     §13/§26 — #E4CE93 and #FFB4AB — which are remapped by the overrides
     below rather than tokenised, so the dark declarations stay byte-identical.) */
  --warn-ink:   #8A5B00;
  --danger-ink: #9A404F;

  --lift-1: 0 1px 2px rgba(20,21,26,.08);
  --lift-2: 0 8px 24px -10px rgba(20,21,26,.16);
  --lift-3: 0 20px 50px -18px rgba(20,21,26,.22);
}
/* Dark declares the two semantic inks too, so var() never dangles and
   test:tokens' "every unguarded var() is declared" check stays honest. */
:root { --warn-ink: #E4CE93; --danger-ink: #FFB4AB; }
/* Dark declares --accent-back too so §29.4's var() never dangles if a rule
   ever escapes the light scope; in dark it resolves to the ground, i.e. no
   visible chip. Same honesty rule as the two semantic inks above. */
:root { --accent-back: transparent; }

/* ── 29.1 STRUCTURAL LITERALS — rules that paint a white overlay or a fixed
   dark hex and therefore vanish or invert on a light ground. Each is the
   light-mode twin of a rule above or in style.css; the dark original is left
   exactly as it was. ───────────────────────────────────────────────────────── */
html[data-theme="light"] body,
html[data-theme="light"] .bg-ink-900 { background: var(--ground); color: var(--txt-1); }
html[data-theme="light"] ::-webkit-scrollbar-thumb { background: #C9CBD1; }
html[data-theme="light"] ::-webkit-scrollbar-thumb:hover { background: #B4B7BE; }
html[data-theme="light"] .glass,
html[data-theme="light"] .topbar { background: var(--ground); border-color: var(--line); }
html[data-theme="light"] .sheet-grab { background: #C9CBD1; }
html[data-theme="light"] .sheet-back,
html[data-theme="light"] .intro-back { background: rgba(20,21,26,.42); }  /* one step deeper on white without a second lime hex */
html[data-theme="light"] .legal-cta:hover { background: var(--k-main-fill-hover); }
html[data-theme="light"] .legal-tabs a:hover,
html[data-theme="light"] .legal-top .legal-back:hover,
html[data-theme="light"] .legal-toc a:hover { background: rgba(20,21,26,.045); }
/* Inputs: style.css paints `.input` with a near-black literal (rgba(8,11,18))
   that the token rule on bare `input` does not reach because the class wins. */
html[data-theme="light"] .input,
html[data-theme="light"] input, html[data-theme="light"] textarea, html[data-theme="light"] select { background: var(--sunken); border-color: var(--line); color: var(--txt-1); }
html[data-theme="light"] .input::placeholder, html[data-theme="light"] input::placeholder, html[data-theme="light"] textarea::placeholder { color: var(--txt-3); }
html[data-theme="light"] .input:focus { border-color: var(--k-focus); box-shadow: none; }
/* .chip surface — but NEVER the belt badge: BELT_BG (app.js) paints rank
   colours through bg-blue-600 / bg-violet-600 / … and rank colours do not
   move with the theme. The :not() list is exactly BELT_BG's fills. */
html[data-theme="light"] .chip:not([class*="bg-blue-"]):not([class*="bg-violet-"]):not([class*="bg-amber-9"]):not([class*="bg-slate-9"]):not([class*="bg-slate-2"]):not([class*="bg-slate-5"]):not([class*="bg-yellow-"]):not([class*="bg-orange-"]):not([class*="bg-emerald-6"]):not([class*="bg-op-"]):not([class*="bg-flame-"]):not([class*="bg-danger-"]):not([class*="bg-good-"]):not([class*="bg-emerald-5"]) { background: rgba(20,21,26,.05); }
html[data-theme="light"] .ring-track { stroke: rgba(20,21,26,.08); }
html[data-theme="light"] .scan-bar,
html[data-theme="light"] .lk-bar,
html[data-theme="light"] .ra-demo-bar,
html[data-theme="light"] .sm-ms-bar,
html[data-theme="light"] .wip-meter { background: rgba(20,21,26,.08); }
html[data-theme="light"] .scan-bracket { border-color: rgba(20,21,26,.45); }
html[data-theme="light"] .offer-ring .bg { stroke: rgba(20,21,26,.1); }
html[data-theme="light"] .pw-sheet.is-message-only .pw-icon { background: rgba(20,21,26,.06); }
html[data-theme="light"] .ba-col.is-after { background: rgba(206,255,86,.22); }
html[data-theme="light"] .ob-belt.is-black { border-color: rgba(20,21,26,.25); }

/* style.css surfaces that were white-alpha on dark: card/panel already read
   tokens via §4, but the pre-theme fallbacks below only exist in style.css. */
html[data-theme="light"] .dtile { background: var(--card); border-color: var(--line); }
html[data-theme="light"] .dtile-l { color: var(--txt-1); }
@media (hover: hover) {
  html[data-theme="light"] .dtile:hover { background: var(--sunken); border-color: var(--line-2); }
}
html[data-theme="light"] .seg,
html[data-theme="light"] .pr-belt,
html[data-theme="light"] .tap-row,
html[data-theme="light"] .pw-plan,
html[data-theme="light"] .lock-row,
html[data-theme="light"] .plan-cta.is-free,
html[data-theme="light"] .path-opt { background: var(--sunken); border-color: var(--line); }
html[data-theme="light"] .intro-title,
html[data-theme="light"] .path-name { color: var(--txt-1); }
html[data-theme="light"] .intro-sub,
html[data-theme="light"] .path-line { color: var(--txt-3); }
html[data-theme="light"] .seg-btn.on { color: var(--txt-1); background: var(--sunken); box-shadow: none; }
html[data-theme="light"] .panel-head { border-color: var(--line); color: var(--txt-3); }
html[data-theme="light"] .tap:hover { border-color: var(--line-2); background: var(--sunken); }

/* Semantic inks painted as literals in dark (§13 amber, §26 danger) → tokens. */
html[data-theme="light"] .consumer-notice,
html[data-theme="light"] .legal-prose .legal-notice p:first-child strong,
html[data-theme="light"] .acct-row.is-scheduled i,
html[data-theme="light"] .acct-row.is-scheduled span { color: var(--warn-ink); }
html[data-theme="light"] .ra-dur.is-err,
html[data-theme="light"] .ra-status.is-err, html[data-theme="light"] .ra-status.is-failed,
html[data-theme="light"] .sl-err,
html[data-theme="light"] .acct-row.is-danger, html[data-theme="light"] .acct-row.is-danger i { color: var(--danger-ink); }
html[data-theme="light"] .acct-row.is-danger { border-color: rgba(154,64,79,.3); }

/* THE MARK. The belt-knot lockup is Reqwa's own PNG layers, drawn WHITE for a
   near-black ground (shell.ts explains why nothing is redrawn). Outer CSS
   cannot recolour a <use> shadow tree, and the pixels are white regardless —
   so the mark vanishes on a light page. `filter: invert(1)` flips white to
   near-black for the whole lockup at once and touches no asset; it is a
   monochrome mark, so inversion IS the light-mode version of it. The boot
   splash keeps its own dark stage and is not inverted (see below). */
html[data-theme="light"] .logo-mark,
html[data-theme="light"] .land-shot-mark { filter: invert(1); }

/* ── 29.5 THE BOOT SPLASH FOLLOWS THE THEME (Wave 4a-2/3, Reqwa 2026-09-05)
   SUPERSEDES the Wave 3 exemption, which read: "the boot splash stays dark in
   BOTH modes on purpose ... a 600ms dark frame that cross-fades into a light
   app is a normal launch feel". Reqwa's call: it is not. A dark splash handing
   off to a white app is a flash of the wrong theme with extra steps, and it is
   worst for exactly the users who chose Light deliberately.

   So the splash resolves with everything else: light splash in light, dark in
   dark, and it follows a signed-in user's FIXED Light/Dark choice, not the
   device — which it gets for free, because it keys on html[data-theme] and
   the pre-paint script has already resolved preference against the media
   query before this stylesheet is read. No second code path, no flicker.

   NO SECOND SET OF ASSETS, which was the real objection in the Wave 3 note.
   The mark is a monochrome PNG lockup drawn WHITE, and §29's `filter:
   invert(1)` already exists for exactly this case — the light splash inverts
   the same pixels the light topbar does. Three things move: the stage colour,
   the mark's polarity, and the wordmark's left half (the lime right half is
   the brand and does not move). The belt ramp is rank colours, which never
   follow the theme.

   The decorative glow is transparent in light mode: lime multiplied onto
   paper tints the centre of the logo. Dark mode keeps its existing glow. */
html[data-theme="light"] .boot-splash {
  background-color: var(--ground);
  background-image:
    radial-gradient(120% 90% at 50% 42%, #FFFFFF 0%, #F4F4F6 55%, #ECECEF 100%);
}
/* The mark: same inversion the topbar lockup takes in §29. */
html[data-theme="light"] .boot-mark { filter: invert(1); }
/* The wordmark's left half is the ink half — it must not stay near-white. */
html[data-theme="light"] .boot-word-l { color: var(--txt-1); }
/* The clip wipe rect and the brackets are part of the inverted mark, so they
   need nothing; the glow is a separate element and does. */
html[data-theme="light"] .boot-glow {
  background: transparent;
  mix-blend-mode: normal;
}
/* The exit blurs and scales the splash; on a white stage the blur is what
   sells the push, so it is unchanged. */

/* ── 29.6 NO SPLASH ON THE LANDING ROUTE (Wave 4a-2) ─────────────────────
   Reqwa: "designer removing boot up animation for landing page". The gate is
   an attribute set by shell.ts's pre-paint script (html[data-boot="off"]),
   NOT a route check in CSS and not a class added by app.js — both of those
   run after the first paint, which would show one frame of splash to the
   visitor it is being removed for.

   `display: none` rather than `opacity: 0`: an invisible overlay at z-index
   9999 still eats every tap on the landing page's own call to action, which is
   the bug shape this file has hit twice (§10's .is-locked, .mode-pill).
   The paired half is in app.js — dismissSplash() returns immediately when the
   attribute is set, so the app does not sit through the 1.65s minimum hold
   for an animation nobody is watching. Both halves are asserted by
   test:boot. */
html[data-boot="off"] .boot-splash { display: none; }
html[data-boot="off"] #app.boot-reveal { animation: none; opacity: 1; }


/* ── 29.3b THE LEGAL PAGES IN LIGHT MODE (Wave 4a-4, L26) ────────────────
   These three documents render outside the SPA, so until Wave 4a they never
   received data-theme at all and came up in the dark set on a light device.
   The bootstrap (shell.ts's exported THEME_BOOTSTRAP, now also in legal.ts)
   fixes the ATTRIBUTE; this block fixes the paint.

   Most of .legal-body already reads tokens and re-paints itself for free —
   that was the point of the Wave 3 token pass. What is listed here is only
   what does NOT: three white-alpha hover surfaces, the amber notice literal,
   the lime is-on rules, and the logo, which is a white PNG.

   THE ONE THING THAT IS NOT A TOKEN SWAP: `.legal-logo`. The lockup is a
   white-drawn raster, so on paper it disappears. §29 already inverts the
   in-app marks for exactly this reason and the same one-line filter applies —
   no second asset, consistent with the boot splash's answer in §29.5. */
html[data-theme="light"] .legal-body { background: var(--ground); color: var(--txt-2); }
/* The three white-alpha hovers (the tabs, the back button, the TOC rows). */
html[data-theme="light"] .legal-tabs a:hover,
html[data-theme="light"] .legal-top .legal-back:hover,
html[data-theme="light"] .legal-toc a:hover { background: rgba(20,21,26,.045); color: var(--txt-1); }
/* The document surface: card on ground, hairline, same step as the app. */
html[data-theme="light"] .legal-doc th { background: var(--sunken); }
html[data-theme="light"] :is(.legal-doc, .legal-prose) th { color: var(--txt-2); }   /* --txt-3 on --sunken is 4.4:1; --txt-2 is 6.9:1 */
html[data-theme="light"] .legal-prose { color: var(--txt-2); }
html[data-theme="light"] .legal-prose strong,
html[data-theme="light"] .legal-prose h3,
html[data-theme="light"] .legal-prose > h2 { color: var(--txt-1); }
/* The statutory notice keeps its amber SEMANTICS (conspicuous by law) and
   takes the light amber ink; the surface and the two amber rules are already
   alpha values that read on paper, so only the ink moves. */
html[data-theme="light"] .legal-prose .legal-notice { background: var(--card); }
html[data-theme="light"] .legal-prose .legal-notice p:first-child strong { color: var(--warn-ink); }
/* The active TOC row's lime marker: an inset box-shadow is a FILL, not type,
   so it is exempt from §29.4's backing — but the phone variant's lime border
   at 55% alpha is nearly invisible on white and takes the ink weight. */
html[data-theme="light"] .legal-toc a.is-on { background: var(--card); color: var(--txt-1); }
@media (max-width: 900px) {
  html[data-theme="light"] .legal-toc a.is-on { border-color: var(--accent-back); }
}
/* The white-drawn lockup, same inversion as the in-app marks (§29). */
html[data-theme="light"] .legal-logo { filter: invert(1); }
/* The CTA is a lime FILL carrying dark ink — correct in both modes. Its hover
   literal (#DBFF74) is a lighter lime, which on paper reads as a wash; §29.1
   already routes the hover through brightness() instead. Nothing to add. */


/* ── 29.4 THE LIME BACKING — SUPERSEDED (DS4 item 1, Reqwa 2026-09-06) ────
   Wave 3 painted a dark plate (--accent-back) behind every lime glyph, label
   and inline accent in light mode — a CHIP behind icons, a PILL behind
   kickers and figures, a MARK behind prose links. It solved the 1.16:1 lime-
   on-white number and created the thing Reqwa flagged as "the black outline
   on text, icons and anything like that in light mode everywhere": the
   wordmark carried a black pill around "BJJ", every feature tick sat in a
   black square, the streak figure wore a black box, a highlighted phrase
   became a black bar.

   THE RULE NOW: in light mode the lime is a FILL, never TYPE. Anything that
   paints --accent-ink as text or as a glyph colour takes the page ink instead
   (--txt-1 for figures, active items and links; --txt-2 for kickers and list
   ticks — the same two steps the surrounding type already uses). Anything
   that paints the lime as a fill, a border, a dot or a ring is untouched and
   needs no backing: a lime pill on white is a shape, and shapes do not have
   contrast floors. The accent is therefore identical in both modes — the
   primary button, the FAB, the active-tab dot, the progress ring, the focus
   ring, the selected border — and light mode has no second visual language.

   THE ONE PLACE A DARK PLATE STAYS: media wells. .scan-stage and the Roll
   library's thumbnail well hold video frames, which are dark content on any
   page; a white well around a dark frame is the same "black box" complaint in
   reverse. They keep --accent-back as their surface, which is also why the
   token is still declared and still painted (test:design asserts both).

   The dark set is untouched: everything here is scoped to
   html[data-theme="light"], and --accent-ink in dark is still the lime. */

/* GLYPHS that were chipped: take the ink of the text beside them. */
html[data-theme="light"] :is(
  .ba-col.is-after .ba-li i,
  .scan-step.is-done i,
  .a2hs-steps i,
  .plan-feats li i,
  .plan-feats.tier-feats li i,
  .land-list li i,
  .land-plan-feats li i,
  .intro-tier .intro-list li i,
  .intro-list li i,
  .land-eyebrow i,
  .ob-sheet-list li i,
  .ob-offer-feats li i,
  .ob-note.is-live i,
  .sm-stat i,
  .sm-ms.target i,
  .dtile.is-key i,
  .dtile.is-locked.is-key > i:not(.dtile-lock),
  .ra-demo-tag.is-key i,
  .comp-door.is-on .comp-door-i,
  .ba-col.is-after .ba-h i,
  .billing-resume i,
  .rc-ico,
  .rl-thumb.is-done,
  .ra-allow
) {
  background: none;
  color: var(--txt-2);
  padding: 0;
  border-radius: 0;
}
html[data-theme="light"] :is(.theme-seg button.on i, .ob-opt.on .ob-ico, .comp-door.is-on .comp-door-i) { color: var(--txt-1); }
/* .rc-ico / .rl-thumb / .ra-allow / .land-tile > i are TILES with their own
   box: they keep the sunken surface and take ink, not a dark plate. */
html[data-theme="light"] :is(.rc-ico, .rl-thumb.is-done, .land-tile > i) {
  background: var(--sunken); color: var(--txt-1); border-color: transparent;
}
html[data-theme="light"] .ra-allow { background: var(--sunken); color: var(--txt-1); border-color: var(--line); }
/* The lock badge on a locked tile is a small pill with a hairline; the glyph
   inside is ink. It used to be a black pill. */
html[data-theme="light"] .dtile-lock {
  background: var(--card);
  border-color: var(--line-2);
  color: var(--txt-1) !important;
}

/* LABELS, KICKERS, BADGES, FIGURES that were pilled: plain type. */
html[data-theme="light"] :is(
  .ob-kicker,
  .legal-kicker,
  .land-sec-head .section-label,
  .tier-headline-k,
  .lock-demo-head,
  .rl-sec-k,
  .rr-all,
  .rc-left,
  .pw-all,
  .ob-sheet-alt,
  .staff-dock-k.is-live b,
  .sm-ms-pct,
  .sm-xp-txt em,
  .board-pick.on .bp-sub,
  .rl-s.is-pending,
  .rr-s.is-pending,
  .ob-cell.on small,
  .comp-turns.is-locked-turns
) { color: var(--txt-2); }
html[data-theme="light"] :is(
  .land-fig,
  .lock-badge,
  .rl-score,
  .rk-row.is-me .rk-num,
  .ba-col.is-after .ba-h,
  .hero-figure,
  .boot-word-r,
  .logo-word,
  .grad-text,
  .nav-item.active,
  .path-meta,
  .mode-pill .mode-lock,
  .lock-ts
) { color: var(--txt-1); }
/* .tier-flag.is-intro and .ra-trim-sel keep their own surface + hairline
   (declared in §22/§24) and take ink for the text. */
html[data-theme="light"] :is(.tier-flag.is-intro, .ra-trim-sel) { color: var(--txt-1); border-color: var(--line-2); background: var(--sunken); }

/* PROSE accents and links: ink with the lime underline as the affordance.
   A lime underline on white is a thin shape, legible as a marker, and it is
   the same underline dark mode draws. */
html[data-theme="light"] :is(
  .legal-prose a,
  .legal-doc a,
  .legal-wordmark em,
  .app-footer a:hover,
  .legal-contact a:not(.btn):hover,
  .legal-foot a:hover,
  .legal-doc .legal-back:hover,
  .legal-doc .legal-toc a:hover
) {
  background: none; padding: 0; border-radius: 0;
  color: var(--txt-1);
  text-decoration: underline; text-decoration-color: var(--accent-fill); text-decoration-thickness: 2px; text-underline-offset: 3px;
}
html[data-theme="light"] .legal-prose a:hover { text-decoration-color: var(--txt-1); }
/* .btn-outline is a CONTROL: hairline in ink, lime only on hover fill. */
html[data-theme="light"] .nav-item.active { background: var(--accent-weak); }
/* .grad-text is the landing h1 — primary ink, no plate (unchanged intent). */
html[data-theme="light"] .grad-text { background: none; color: var(--txt-1); padding: 0; }

/* MEDIA WELLS — the one legitimate dark surface on a light page (see above). */
html[data-theme="light"] .scan-stage { background: var(--accent-back); border-color: var(--accent-back); }
html[data-theme="light"] .scan-bracket { border-color: rgba(255,255,255,.55); }


/* ── 29.2 TAILWIND UTILITY REMAP ──────────────────────────────────────────
   ~450 utility colour uses across views*.js paint text and surfaces from the
   ramp in src/shell.ts. The ramp is one set of hexes and cannot change per
   theme, and we do not rewrite 450 markup sites in a polish round (DESIGNER-
   BRIEF §2 trap 3 — and it would collide with Engineer's parallel drop).
   So: in light mode the utilities are remapped BY CLASS to the token they
   mean. The mapping is by ROLE, read from how the markup actually uses each
   step (grep counts 2026-09-04):
     text-slate-100/200  primary ink (23)         → --txt-1
     text-slate-300/400  secondary ink (121)      → --txt-2
     text-slate-500      tertiary/label ink (172) → --txt-3
     text-slate-600/700  quiet ink, icons (123)   → --txt-3  (600/700 were
                         below the floor even in dark; on white they would be
                         near-invisible, so they lift to the floor)
     text-op-300/400/450 accent ink (75)          → --accent-ink (deep lime)
     bg-white/N          hairline surfaces (60+)  → a dark-alpha of the same N
     border-white/N, divide-white/N, ring-white/N → --line / --line-2
     text-white on bg-op-500 does not exist (7 sites use text-op-on, kept).
   Deliberate one-offs that are NOT remapped: belt colours (BELT_BG in app.js —
   rank colours never move), the medal fills, the emerald/good/flame/danger
   TINT backgrounds (the bg-emerald-500 / 15 shape — alpha tints that read fine on
   white), and bg-black/70 modal backdrops. */
html[data-theme="light"] .text-slate-100,
html[data-theme="light"] .text-slate-200,
html[data-theme="light"] .hover\:text-slate-100:hover,
html[data-theme="light"] .hover\:text-slate-200:hover { color: var(--txt-1); }
html[data-theme="light"] .text-slate-300,
html[data-theme="light"] .text-slate-400,
html[data-theme="light"] .hover\:text-slate-300:hover,
html[data-theme="light"] .hover\:text-slate-400:hover { color: var(--txt-2); }
html[data-theme="light"] .text-slate-500,
html[data-theme="light"] .text-slate-600,
html[data-theme="light"] .text-slate-700 { color: var(--txt-3); }
html[data-theme="light"] .fill-slate-300 { fill: var(--txt-2); }
html[data-theme="light"] .fill-slate-500,
html[data-theme="light"] .fill-slate-600 { fill: var(--txt-3); }
/* The ~75 text-op-* sites: lime as TYPE in light mode takes the page ink
   (DS4 item 1 — §29.4 rule: lime is a fill, not a letter). No plate, no
   padding, no pill: the element keeps its own box exactly as in dark. */
html[data-theme="light"] .text-op-300,
html[data-theme="light"] .text-op-400,
html[data-theme="light"] .text-op-450,
html[data-theme="light"] .text-op-500,
html[data-theme="light"] .text-op-400\/80,
html[data-theme="light"] .text-op-450\/70,
html[data-theme="light"] .hover\:text-op-300:hover,
html[data-theme="light"] .hover\:text-op-400:hover {
  color: var(--txt-1);
}
/* The one place lime type rides ON the lime fill (a text-op-* span inside a
   .btn-primary / the roll-tab count chip) is already handled by the fill's own
   dark ink rule; nothing to add. */
/* fill-op-* (SVG glyphs) are FILLS, not type — exempt per §29.4's list. */
/* Semantic inks from the ramp: light steps that vanish on white → light-mode
   semantic tokens. Tints (the 15 percent alpha shape) are left alone. */
html[data-theme="light"] .text-emerald-300, html[data-theme="light"] .text-emerald-400, html[data-theme="light"] .text-emerald-500,
html[data-theme="light"] .text-emerald-500\/70,
html[data-theme="light"] .text-good-300, html[data-theme="light"] .text-good-400 { color: var(--txt-1); }
html[data-theme="light"] .text-flame-300, html[data-theme="light"] .text-flame-400, html[data-theme="light"] .text-flame-500,
html[data-theme="light"] .text-flame-400\/90,
html[data-theme="light"] .text-amber-300, html[data-theme="light"] .text-amber-400 { color: var(--warn-ink); }
html[data-theme="light"] .text-danger-300, html[data-theme="light"] .text-danger-400, html[data-theme="light"] .text-danger-500,
html[data-theme="light"] .text-rose-300, html[data-theme="light"] .text-rose-400, html[data-theme="light"] .text-red-400 { color: var(--danger-ink); }
/* White-alpha surfaces → dark-alpha of the same weight. */
html[data-theme="light"] .bg-white\/\[\.02\],
html[data-theme="light"] .bg-white\/\[0\.03\] { background-color: rgba(20,21,26,.03); }
html[data-theme="light"] .bg-white\/\[0\.04\],
html[data-theme="light"] .bg-white\/5 { background-color: rgba(20,21,26,.045); }
html[data-theme="light"] .bg-white\/6,
html[data-theme="light"] .bg-white\/\[0\.06\] { background-color: rgba(20,21,26,.055); }
html[data-theme="light"] .bg-white\/8,
html[data-theme="light"] .bg-white\/\[0\.07\] { background-color: rgba(20,21,26,.07); }
html[data-theme="light"] .bg-white\/10 { background-color: rgba(20,21,26,.09); }
html[data-theme="light"] .hover\:bg-white\/6:hover,
html[data-theme="light"] .hover\:bg-white\/\[0\.05\]:hover { background-color: rgba(20,21,26,.05); }
html[data-theme="light"] .hover\:bg-white\/8:hover,
html[data-theme="light"] .hover\:bg-white\/\[0\.07\]:hover { background-color: rgba(20,21,26,.07); }
html[data-theme="light"] .border-white\/5, html[data-theme="light"] .border-white\/6,
html[data-theme="light"] .border-white\/8, html[data-theme="light"] .border-white\/10 { border-color: var(--line); }
html[data-theme="light"] .border-white\/15, html[data-theme="light"] .hover\:border-white\/20:hover { border-color: var(--line-2); }
html[data-theme="light"] .divide-white\/5 > :not([hidden]) ~ :not([hidden]),
html[data-theme="light"] .divide-white\/6 > :not([hidden]) ~ :not([hidden]) { border-color: var(--line); }
html[data-theme="light"] .ring-white\/10, html[data-theme="light"] .ring-white\/15 { --tw-ring-color: var(--line-2); }
html[data-theme="light"] .ring-ink-900, html[data-theme="light"] .ring-ink-950 { --tw-ring-color: var(--ground); }
html[data-theme="light"] .bg-ink-700, html[data-theme="light"] .bg-ink-900 { background-color: var(--sunken); }
/* ── 29.2b THE BLACK BOXES (Wave 4a-5, Reqwa: "we have glitches such as black
   unreadable text boxes in some places") ────────────────────────────────────
   Every one of these is the same shape: a rule that paints a DARK SURFACE or
   near-white TEXT from a literal, on the assumption that the page behind it is
   near-black. In light mode the surface stays dark and the text on it goes
   dark too (because §29.2's ink remap reaches the text but not the plate), so
   the element reads as a black box with invisible writing.

   Found by scanning the SHIPPED markup for every dark-surface utility rather
   than by clicking through screens — the enumeration lesson this file has now
   learned four times (§2 gradients, §15b cyan, §17.6 coral literals, §29.2's
   own 25 missed selectors). The list is what the scan returned, and the four
   found this way are the four that were still wrong.

   1. bg-black/25 + text-white — the roll-tab count chip (views9.js:135). It
      rides INSIDE a .btn-primary, i.e. on the lime fill, so the dark plate is
      correct in both modes and it is the WHITE text that fails: white on a
      25%-black-over-lime plate is ~2:1. It takes the accent's own dark ink,
      which is what everything else on the fill uses.
   2. bg-black/70 — the two modal backdrops (views5/views6). Deliberately NOT
      changed: a backdrop is meant to be dark, in both modes. Listed so the
      next scan does not "fix" it.
   3. bg-ink-900 + ring-ink-950 — the academy page's logo plate (views7.js:51).
      The ring is a page-coloured halo (already remapped in §29.2) but the
      plate itself is the ground literal, which on paper is a black square with
      a lime glyph. It becomes the sunken step, and the glyph keeps the accent
      — which §29.4 then backs, so it is legible either way.
   4. ring-ink-900 — the avatar edit badge's halo (views2.js:136). Same
      mechanism as the ring above; already covered by §29.2's ring-ink rule, so
      nothing to add. Listed for completeness. */
html[data-theme="light"] .bg-black\/25.text-white,
html[data-theme="light"] .btn-primary .bg-black\/25 { color: var(--accent-on); }
html[data-theme="light"] .bg-ink-900 { background-color: var(--sunken); }
/* The plate above also carries `bg-ink-900` as a BODY class in the shell, and
   §29.1 already maps that to the ground. A class doing two jobs is why this is
   scoped by the element having a ring as well — the body has none. */
html[data-theme="light"] body.bg-ink-900 { background: var(--ground); }

/* The one `bg-white` marker line (views4 percentile "you" tick) is a marker on
   a dark bar; on light it needs to be ink. */
html[data-theme="light"] .bg-white { background-color: var(--txt-1); }

/* ── 29.2c THE SECOND SWEEP (Wave 4b — every route walked in light mode at
   390 and 1280, plus a scan of both stylesheets for a dark-surface literal in
   a rule with no light twin). What the walk found, in the order it was seen:

   5. .rk-me-dock — the leaderboard's sticky "Your position" bar (views5.js).
      style.css paints it rgba(14,15,18,.9) with a coral hairline; the ink
      remap turned its text near-black, so in light mode it was a black pill
      with invisible writing floating over the list — Reqwa's exact "black
      unreadable text box". It takes the raised surface + hairline + lift,
      like every other floating control. The `!text-op-300` rank number keeps
      its lime and gets the §29.2 pill for free.
   6. .intro-list li / .intro-paid-sub / .intro-free-badge / .intro-paid-head
      — the welcome sheet (views11 plansIntro) painted its list in #cbd5e1 and
      its badges in the pre-theme emerald / coral literals from style.css:1631-
      1665. On white: light-grey text on a white card. Tokens by role.
   7. .lock-row / .lock-line / .lock-demo-head / .lock-alt — the locked-feature
      pitch (views11 lockedScreen) reads #94a3b8 / #5a6577 / #64748b from
      style.css:1755-1778 — all three are slate inks for a dark ground and sit
      at 2-3:1 on white. Tokens. .lock-demo itself (rgba(4,6,10,.55), a
      near-black well) was already re-pointed for the .ra-lock variant only
      (§21) — the plans-side variant gets the same sunken step here.
   8. .ra-swap — the "swap clip" pill over the video stage (views2.js) is
      rgba(10,10,12,.78): correct over footage in both modes (it sits ON the
      video, which is dark), so it is listed as EXEMPT, not fixed.
   9. .toast — rgba(17,23,38,.95) with white-alpha hairline. A toast is a
      floating notice; on paper it becomes the raised surface with the ink,
      and keeps its semantic border colour.
   10. .wip-peek::after — the blurred "coming soon" teaser fade is a dark
       gradient to rgba(16,17,20,.92); on white it is a black plate over a
       blurred card. The fade goes to the ground instead.
   11. .heat-cell / .mini-bar OFF states (#1e2025) — never rendered on this
       tree (zero markup hits), left alone: dead rules are a §10 item, not a
       light-mode one.
   12. .btn-google — white with #1f1f1f ink in both modes by Google's brand
       rule; correct as is. Listed so the scan does not "fix" it.
   13. .badge-dot — style.css paints its count in #fff over the lime fill
       (1.16:1 in BOTH modes; the §15b re-point changed the fill and not the
       ink). Fixed at the §15b rule, not here; listed because the walk found it. */
html[data-theme="light"] .rk-me-dock {
  background: var(--raised);
  border-color: var(--line-2);
  box-shadow: var(--lift-2);
  color: var(--txt-1);
}
html[data-theme="light"] .intro-list li { color: var(--txt-2); }
html[data-theme="light"] .lock-row,
html[data-theme="light"] .lock-line { color: var(--txt-2); }
html[data-theme="light"] .lock-row + .lock-row { border-top-color: var(--line); }
html[data-theme="light"] .lock-demo-head,
html[data-theme="light"] .lock-alt { color: var(--txt-3); }
html[data-theme="light"] .lock-demo { background: var(--sunken); border-color: var(--line); }
/* .toast light twin — no longer needed here: §30 paints the toast from
   tokens (--raised / --line-2 / --lift-3) in BOTH modes, so it has no dark
   literal to invert. Listed so the §29.1 walk stays complete. */
html[data-theme="light"] .wip-peek::after {
  background: linear-gradient(180deg, rgba(244,244,246,.15), rgba(244,244,246,.94));
}
html[data-theme="light"] .wip-lock { color: var(--txt-2); }

/* Active desktop nav item paints bg-white/5 — covered above; the active text
   colour comes from .nav-item.active (accent ink), already a token. */

/* ── 29.3 APPEARANCE CONTROL (Me screen) ─────────────────────────────────
   A three-way segmented control on the sheet surface. Selected segment is a
   flat raised step with the accent as INK (not a fill — the fill is reserved
   for primary actions, §1 rule 3). 44px targets. */
.appearance { margin-top: 1rem; padding: 1rem; }
.theme-seg {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .3rem;
  padding: .3rem; border-radius: var(--radius-sm);
  background: var(--sunken); border: 1px solid var(--line);
}
.theme-seg button {
  min-height: 44px; border-radius: calc(var(--radius-sm) - .3rem);
  font-size: .86rem; font-weight: 650; letter-spacing: -.01em; color: var(--txt-2);
  display: flex; align-items: center; justify-content: center; gap: .45rem;
  transition: background .15s, color .15s;
}
.theme-seg button i { font-size: .8rem; color: var(--txt-3); }
.theme-seg button.on { background: var(--card); color: var(--txt-1); box-shadow: var(--lift-1); border: 1px solid var(--line); }
.theme-seg button.on i { color: var(--txt-1); }
.theme-help { margin: .6rem .15rem 0; font-size: .78rem; line-height: 1.45; color: var(--txt-3); }


/* ══════════════════════════════════════════════════════════════════════════
   30. FEEDBACK SURFACES — toast · confirm sheet · install banner · field error
   (Designer, Wave 5, DS2 items 1–3; behaviour in app.js "UNIFIED FEEDBACK
   SURFACES"; strings COPY-WAVE2 §3–§4.)

   Four rules, all inherited from §1: no gradient, black shadow only, the
   accent appears exactly once per surface (the primary action), depth is a
   hairline on a flat step. Semantic colour is INK on the leading glyph and a
   2px edge, never a tinted plate — a tinted plate is the "push-up alert"
   look this replaces. Every animation is transform/opacity, every one has a
   reduced-motion twin that lands on the end state.
   ══════════════════════════════════════════════════════════════════════════ */

/* — stack — bottom-centre on phones (above the nav capsule), bottom-right on
   desktop. pointer-events pass through the empty stack; each toast re-enables
   them so the dismiss control is tappable. */
.toast-root {
  position: fixed; left: 0; right: 0; z-index: 100;
  bottom: calc(5.4rem + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: center; gap: .5rem;
  padding: 0 .75rem; pointer-events: none;
}
@media (min-width: 768px) {
  .toast-root { left: auto; right: 1.25rem; bottom: 1.25rem; align-items: flex-end; padding: 0; }
}
.toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: .7rem;
  width: 100%; max-width: 26rem; min-height: 52px;
  padding: .8rem .55rem .8rem .95rem;
  border-radius: var(--radius-sm);
  background: var(--raised); color: var(--txt-1);
  border: 1px solid var(--line-2);
  border-left-width: 3px; border-left-color: var(--txt-3);
  box-shadow: var(--lift-3);
  font-size: .9rem; line-height: 1.4; font-weight: 550; letter-spacing: -.005em;
  animation: toastIn .32s var(--ease) both;
}
.toast.is-out { animation: toastOut .26s var(--ease) both; }
.toast-ico { flex: none; margin-top: .18rem; font-size: .9rem; width: 1.1rem; text-align: center; color: var(--txt-3); }
.toast-body { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; padding-top: .08rem; }
.toast-act {
  display: block; margin-top: .3rem; padding: .35rem 0; min-height: 44px;
  font-size: .86rem; font-weight: 750; color: var(--txt-1); text-align: left;
}
.toast-x {
  flex: none; width: 44px; height: 44px; margin: -.55rem -.2rem -.55rem 0;
  display: grid; place-items: center; border-radius: 999px;
  color: var(--txt-3); font-size: .85rem;
  transition: background .15s, color .15s;
}
.toast-x:hover { background: rgba(255,255,255,.06); color: var(--txt-1); }
/* the four kinds — ink on the glyph and the edge, nothing else changes */
.toast.ok   { border-left-color: var(--good); }
.toast.ok   .toast-ico { color: var(--txt-1); }
.toast.info { border-left-color: var(--accent-ink); }
.toast.info .toast-ico { color: var(--txt-1); }
.toast.warn { border-left-color: var(--warn-ink); }
.toast.warn .toast-ico { color: var(--warn-ink); }
.toast.err  { border-left-color: var(--danger-ink); }
.toast.err  .toast-ico { color: var(--danger-ink); }
@keyframes toastIn  { from { opacity: 0; transform: translateY(12px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes toastOut { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(8px) scale(.98); } }
html[data-theme="light"] .toast-x:hover { background: rgba(20,21,26,.06); }
/* light mode: the accent as INK needs its backing (§29.4 rule) */
html[data-theme="light"] .toast.info { border-left-color: var(--accent-back); }
html[data-theme="light"] .toast.info .toast-ico { color: var(--txt-1); }
html[data-theme="light"] .toast-act { color: var(--txt-1); text-decoration: underline; text-underline-offset: 3px; }

/* — confirm sheet — the acctSheet() shell (style.css .sheet-wrap / .sheet)
   with the §3.2 grammar laid out: consequence as the title, one body line,
   the verb, Cancel. Both buttons are full-width 52px targets, stacked, the
   named action on top where the thumb already is. */
.cf-sheet { max-width: 30rem; }
.cf-in { padding: .15rem 1.3rem calc(1.1rem + env(safe-area-inset-bottom)); }
.cf-cancel { color: var(--txt-1); }
.cf-title {
  margin: .1rem 0 0; font-size: 1.35rem; font-weight: 850; letter-spacing: -.03em; line-height: 1.15;
  color: var(--txt-1); text-wrap: balance; overflow-wrap: anywhere;
}
.cf-body { margin: .65rem 0 0; font-size: .95rem; line-height: 1.5; color: var(--txt-2); overflow-wrap: anywhere; }
.cf-body strong { color: var(--txt-1); font-weight: 750; }
.cf-actions { margin-top: 1.3rem; display: grid; gap: .55rem; }
.cf-wrap.is-out .sheet-back { animation: sheetFadeOut .24s ease both; }
.cf-wrap.is-out .sheet { animation: sheetDown .24s var(--ease) both; }
@keyframes sheetDown { from { transform: none; opacity: 1; } to { transform: translateY(16px); opacity: 0; } }
@keyframes sheetFadeOut { from { opacity: 1; } to { opacity: 0; } }

/* — install banner — a card docked above the nav capsule. It is a
   complementary region, not a dialog: nothing behind it is blocked and it
   never takes focus on its own. The mark is the same <symbol> the topbar
   draws, so the offer is visibly THIS app and not a browser chrome element. */
.install-banner {
  position: fixed; left: .75rem; right: .75rem; z-index: 45;
  bottom: calc(5.4rem + env(safe-area-inset-bottom));
  display: grid; grid-template-columns: auto 1fr; gap: .8rem 1rem; align-items: start;
  padding: 1rem 1rem 1rem 1.05rem;
  background: var(--raised); border: 1px solid var(--line-2);
  border-radius: var(--radius); box-shadow: var(--lift-3);
  animation: toastIn .36s var(--ease) both;
}
.install-banner.is-out { animation: toastOut .3s var(--ease) both; }
@media (min-width: 640px) {
  .install-banner { left: auto; right: 1.25rem; bottom: 1.25rem; max-width: 26rem; }
}
.ib-mark {
  width: 46px; height: 46px; border-radius: 14px; display: grid; place-items: center;
  background: var(--sunken); border: 1px solid var(--line);
}
.ib-mark svg { width: 30px; height: 30px; }
.ib-text { min-width: 0; }
.ib-title { font-size: 1rem; font-weight: 800; letter-spacing: -.02em; color: var(--txt-1); }
.ib-body { margin: .3rem 0 0; font-size: .86rem; line-height: 1.45; color: var(--txt-2); }
.ib-share { font-size: .8em; margin: 0 .05em; color: var(--txt-1); vertical-align: -.02em; }
.ib-steps { margin: .6rem 0 0; padding-left: 1.2rem; font-size: .86rem; line-height: 1.5; color: var(--txt-1); display: grid; gap: .25rem; }
.ib-steps[hidden] { display: none; }
.ib-actions { grid-column: 1 / -1; display: flex; gap: .5rem; }
.ib-actions .btn { flex: 1 1 0; }
.ib-go { font-weight: 750; }
.ib-not { color: var(--txt-2); }
html[data-theme="light"] .ib-mark svg { filter: invert(1); }

/* — inline field error — COPY-WAVE2 §3.3: a field error belongs next to the
   field, never in a toast and never in the browser's bubble. */
.field-err { margin: .4rem .15rem 0; font-size: .8rem; line-height: 1.45; color: var(--danger-ink); }
.field-err[hidden] { display: none; }
/* §3.3 email_taken action line: lives INSIDE the field-error slot, so it is
   inline under the field (never a toast) and clears with the error. A real
   button, ink-coloured, underlined — the one link in the slot. */
.field-err-link-wrap { display: inline; }
.field-err-link {
  position: relative; display: inline-block; padding: .2rem 0; min-height: 0; border: 0; background: none;
  font: inherit; font-weight: 700; color: var(--txt-1); text-decoration: underline; text-underline-offset: .15em;
}
/* §31 touch floor for an inline link: hit area grows, drawing does not. */
.field-err-link::before { content: ''; position: absolute; inset: -12px -6px; }
.field-err-link:hover { color: var(--txt-1); }
html[data-theme="light"] .field-err-link:hover { color: var(--txt-1); }
.input.is-invalid, input.is-invalid { border-color: var(--danger-ink); }
.input.is-invalid:focus, input.is-invalid:focus { box-shadow: 0 0 0 3px rgba(255,180,171,.18); }
html[data-theme="light"] .input.is-invalid:focus { box-shadow: 0 0 0 3px rgba(154,64,79,.18); }

@media (prefers-reduced-motion: reduce) {
  .toast, .toast.is-out, .install-banner, .install-banner.is-out,
  .cf-wrap.is-out .sheet, .cf-wrap.is-out .sheet-back { animation: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   31. ERGONOMICS PASS — touch floor, spacing scale, top nav, icon tone
   (Designer, Wave 5, DS2 items 4–5. 390 px first, both themes.)

   THE FLOOR IS 48 PX. Apple's HIG says 44, Material says 48, and on a phone
   held in one hand the difference is a miss-tap on every third try. Every
   rule here raises a control that sat between 32 and 44 to at least 48 on
   the axis a thumb lands on; nothing is made visually heavier to do it —
   where a control must LOOK small (the onboarding back rail, the "All rolls"
   link, a chip that toggles a filter) the hit area grows and the drawing
   does not, via padding or a ::before extension.

   SPACING SCALE. One step: .5rem · .75rem · 1rem · 1.5rem · 2rem. Section
   gaps on the dashboard and plans pages were .6 / .9 / 1.1 / 1.25 — five
   values within 10 px of each other, which is what reads as "crowded"
   without any single element being wrong.

   ICON TONE. One weight (solid 900), one colour rule: an icon is INK, the
   same ink as the text beside it — --txt-2 on a card, --txt-3 when quiet,
   --txt-1 when active. The accent appears on an icon exactly when the
   ELEMENT is the primary action or the active nav item (§1 rule 3) — never
   as decoration on a heading, a KPI or a list bullet. The white/lime pairs
   that dashboards and academy pages accumulated (a white glyph in a lime
   ring, a lime glyph on a white label) are what this section removes; the
   Tailwind text-op-* utilities on inline <i> are overridden here by
   selector rather than edited out of 60 call sites, so the rule lives in ONE
   place and a future call site that reaches for text-op-400 on an icon gets
   the same answer.
   ══════════════════════════════════════════════════════════════════════════ */

/* — top bar — §31 sizes DELETED in DS7 (they were fully overridden by §36/§36b;
   keeping them only created the specificity dependency noted in
   HANDOFF-Designer-wave7 §5.3). The header keeps its literal class list
   (test:design asserts it). */
.glass .tb-brand { border-radius: var(--r-inner); }
.glass .nav-item { min-height: 44px; }

/* — bottom capsule — the tabs were 50 px tall and the FAB 50; both go to 52
   and the capsule's own padding keeps the bar's silhouette. */
.navtab { height: 52px; }
.navfab { flex: 0 0 52px; width: 52px; height: 52px; }
.navcapsule { padding: .3rem .34rem; }

/* — buttons and inputs — the primitive floor rises from 44 to 48; the
   compact variant from 36 to 40 VISUALLY but hits 48 via a transparent
   extension, so dense rows (roster actions, admin) keep their rhythm. */
.btn-sm { min-height: 40px; position: relative; }
.btn-sm::before { content: ''; position: absolute; inset: -4px 0; }
.input, input.input, select.input, textarea.input { min-height: 48px; }
.seg-btn { min-height: 44px; }
.theme-seg button { min-height: 48px; }
.dest { min-height: 48px; }
.dtile { min-height: 72px; }
.consent-row { min-height: 48px; }
.ob-opt { min-height: 56px; }
.ob-sheet-not, .ob-sheet-alt, .pw-all, .pw-not { min-height: 48px; }
.rr-all { min-height: 44px; padding: 0 .5rem; margin-right: -.5rem; }
.acct-row { min-height: 56px; }
.staff-dock-go { min-height: 44px; }
/* a filter chip that is a <button> gets the floor; a status chip does not */
button.chip, label.chip, .chip[onclick] { min-height: 44px; padding-top: .55rem; padding-bottom: .55rem; }
/* generic tap rows */
.tap-row, .tap { min-height: 48px; }
/* onboarding back: visual 34, hit 48 (was 44) */
.ob-back::before { inset: -7px; }
/* toast dismiss and actions are 44 (they are secondary, inside a 52 surface) */

/* — spacing scale — dashboard / home / plans / onboarding */
main.page-rise { padding-top: 1.25rem; padding-bottom: calc(7rem + env(safe-area-inset-bottom)); }
@media (min-width: 768px) { main.page-rise { padding-top: 2rem; padding-bottom: 4rem; } }
.section-label { margin-bottom: .5rem; }
.card + .card, .panel + .panel { margin-top: 0; }
.space-y-2\.5 > :not([hidden]) ~ :not([hidden]) { margin-top: .75rem; }
.kpi-strip { gap: .75rem; }
.kpi-strip .panel { padding: 1rem .75rem; }
.kpi-strip .kpi-v { margin-top: .5rem; }
.ob-opts { gap: .75rem; }
.land-sec { padding-top: 4rem; }
@media (min-width: 768px) { .land-sec { padding-top: 5.5rem; } }
.land-cta { margin-top: 2rem; }
.land-shots { margin-top: 3.5rem; }
.land-link { min-height: 48px; display: inline-flex; align-items: center; padding: 0 .75rem; }
.land-btn { min-height: 56px; }
.land-plan-btn { min-height: 52px; }
.app-footer { padding-top: 2rem; padding-bottom: 1rem; }
.app-footer a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 .35rem; }

/* — icon tone: one weight, one colour rule — */
/* accent utilities on inline glyphs collapse to ink … */
i.fa-solid.text-op-300, i.fa-solid.text-op-400, i.fa-solid.text-op-450, i.fa-solid.text-op-500,
i.fa-regular.text-op-400, i.fa-regular.text-op-450 { color: var(--txt-2); }
/* … except where the glyph IS the active/primary signal */
.navtab.active i, .navfab i, .btn-primary i, .theme-seg button.on i, .ob-opt.on .ob-ico,
.consent-box::after, .seg-btn.on i, .board-pick.on i, .mode-btn.on i { color: inherit; }
.navfab i { color: var(--accent-on); }
/* the lime ring + white glyph pair on dashboard docks: ring goes, glyph is ink */
.staff-dock .ring-1, #my-gym-dock .ring-1 { box-shadow: none; background: var(--sunken); border: 1px solid var(--line); }
#my-gym-dock .w-10 { width: 44px; height: 44px; }
/* KPI / panel heading glyphs — ink, not accent */
.kpi-strip .panel i, .panel-head i, .land-tile > i, .sec-head i, .rc-ico { color: var(--txt-2); }
/* "flame" heat on non-actionable glyphs reads as an alert; it is ink unless
   the row is a real alert (alertRow keeps its tone classes on the container) */
.card:not(.tap) > i.text-flame-400, .card > .text-xs > i.text-flame-400 { color: var(--txt-3); }
/* single weight: the two `fa-regular` scan-step circles stay regular by
   design (they are empty checkboxes); everything else is solid. */
html[data-theme="light"] .navfab i, html[data-theme="light"] .btn-primary i { color: var(--accent-on); }
html[data-theme="light"] .land-tile > i { background: var(--accent-back); color: #F4F4F5; }

/* inline text links that switch auth doors, the plans-intro "See the plans",
   the roster name, the consent links: hit area grows, drawing does not */
.auth-alt { position: relative; display: inline-block; padding: .35rem .25rem; margin: -.35rem -.25rem; }
.auth-alt::before { content: ''; position: absolute; inset: -10px -4px; }
.intro-later { min-height: 48px; }
.roster-name { display: block; max-width: 100%; text-align: left; min-height: 44px; padding: .55rem 0; margin: -.55rem 0; }
.consent-link { position: relative; display: inline-block; padding: .2rem 0; }
.consent-link::before { content: ''; position: absolute; inset: -12px -6px; }

/* — public academy page states (views7.js, JOURNEY-AUDIT D1/D2) — */
.gym-state { padding: 1rem; border-radius: var(--radius-sm); background: var(--sunken); border: 1px solid var(--line); }
.gym-state-row { display: flex; align-items: center; gap: .75rem; font-size: .9rem; line-height: 1.45; color: var(--txt-2); }
.gym-state-row i { flex: none; width: 1.2rem; text-align: center; color: var(--txt-3); }
.gym-state.is-member { border-color: var(--good-weak); }
.gym-state.is-member .gym-state-row i { color: var(--txt-1); }


/* ══════════════════════════════════════════════════════════════════════════
   32. WAVE 6a (DS3) — Billing card · history window · game-map drafts line
   Same §26 account-row primitive; tokens only. The billing "state" row is a
   static sentence block (role=status), not a tap target, so it drops the
   hover ramp and the pointer while keeping the row geometry the column reads
   as. Cancel sits on the §26 danger ramp; Resume is a plain row — the calmer
   word for the calmer action (WAVE1-COPY (h11): no win-back pitch).
   ══════════════════════════════════════════════════════════════════════════ */
.acct-row.is-static { cursor: default; background: var(--card); align-items: start; }
@media (hover: hover) { .acct-row.is-static:hover { background: var(--card); border-color: var(--line); } }
.acct-row.is-static i { margin-top: .15rem; }
.acct-row.is-static small { margin-top: .3rem; }
.acct-row.is-static small + small { margin-top: .45rem; }
/* (h11): the cancellation route is never the smallest text on the surface —
   it takes the body weight and ink, one step above the renewal fine print. */
.billing-route { font-size: .84rem !important; font-weight: 600 !important; color: var(--txt-2) !important; }
.billing-renews { color: var(--txt-2) !important; }
.billing-pastdue { color: var(--warn-ink) !important; font-weight: 600 !important; }
.billing-wait { min-height: 52px; opacity: .55; }
.billing-state.is-static { border-color: var(--line-2); }
.billing-resume i { color: var(--txt-1); }
.billing-cancel { margin-top: .15rem; }
/* history window (D9): quiet, informative, one tap to the paywall */
.history-window i { color: var(--txt-3); }
.history-window small { color: var(--txt-3); }
/* game-map drafts (D7-11): the Auto-Log draft count line, both states */
.gm-drafts { border-color: var(--line-2); }
.gm-drafts i { color: var(--txt-3); }
html[data-theme="light"] .billing-resume i { color: var(--txt-1); }
html[data-theme="light"] .acct-row.is-static { background: var(--card); }
.billing { margin-top: 1rem; }
.billing-rows { display: flex; flex-direction: column; gap: .45rem; }


/* ══════════════════════════════════════════════════════════════════════════
   33. DS4 — CONSISTENCY FIX WAVE (Designer 2, Wave 6b part 1, 2026-09-06)
   Reqwa's seven items (#msg 3733031), fixed at the lowest layer that reaches
   every site. Every rule here is BOTH-THEME unless scoped; the light-only
   half of item 1 is the §29.4 rewrite above.

   The one structural idea: markup carries Tailwind colour utilities at ~450
   sites (text-slate-500 alone 157×). Those classes resolve to Tailwind's
   default hexes in tw.css, which is linked LAST and therefore wins on order.
   §29.2 already remaps them in light mode by attribute selector; dark mode
   had no remap at all, so a `text-slate-500` in dark painted Tailwind's
   #64748b — a cool blue-grey that is not one of this theme's three inks, and
   is precisely "text that is a different colour without intent" (item 7).
   The same is true of every `text-emerald-*` (Tailwind's teal), every
   `text-danger-*` / `text-rose-*` / `text-red-*` (a saturated pink-red the
   theme never declared) and the one `text-sky-300` (a literal blue) — item 2.

   The rules below key on `:root .class` — one attribute-level step above
   tw.css's bare `.class`, so they win by specificity in BOTH themes without
   an !important, and the §29.2 light rules (html[data-theme="light"] .class,
   equal specificity, earlier in the file) are restated here where they must
   differ. The classes stay in the markup: a future call site that reaches
   for text-slate-500 still gets the theme's answer.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 33.1 ITEM 2 — semantic colours: in the palette, not Tailwind's ─────── */
/* good = green (--good), never teal. Includes the !important variants. */
:root .text-emerald-300, :root .text-emerald-400, :root .text-emerald-500,
:root .text-emerald-500\/70,
:root .text-good-300, :root .text-good-400, :root .text-good-500,
:root .\!text-emerald-300, :root .\!text-emerald-400 { color: var(--txt-1) !important; }
/* danger = the theme's salmon ink, never Tailwind's #fb7185 / #f87171. */
:root .text-danger-300, :root .text-danger-400, :root .text-danger-500,
:root .text-rose-300, :root .text-rose-400, :root .text-red-400,
:root .\!text-rose-300 { color: var(--danger-ink) !important; }
/* warn = the theme's amber ink. */
:root .text-flame-300, :root .text-flame-400, :root .text-flame-500, :root .text-flame-400\/90,
:root .text-amber-300, :root .text-amber-400,
:root .\!text-flame-300, :root .\!text-flame-400 { color: var(--warn-ink) !important; }
/* the ONE literal blue in the product (admin role chip, views8.js:26 coach):
   a role is not a semantic state; it takes the secondary ink like its
   siblings (owner / student chips already do). */
:root .text-sky-300 { color: var(--txt-2) !important; }
:root .bg-sky-500\/15 { background-color: var(--sunken) !important; }
/* podium bronze (views7.js:276) — amber-700 is invisible on dark; use warn ink */
:root .text-amber-700 { color: var(--warn-ink) !important; }
/* tints that carried the teal: alpha of the good token instead */
:root .bg-emerald-500\/5, :root .bg-emerald-500\/8, :root .bg-emerald-500\/10, :root .\!bg-emerald-500\/10,
:root .bg-emerald-500\/12, :root .bg-emerald-500\/15, :root .bg-emerald-500\/18,
:root .bg-good-500\/8, :root .bg-good-500\/15 { background-color: var(--good-weak) !important; }
:root .border-emerald-500\/20, :root .border-emerald-500\/25, :root .\!border-emerald-500\/25,
:root .border-emerald-500\/30, :root .border-good-500\/25 { border-color: color-mix(in srgb, var(--good) 30%, transparent) !important; }
:root .bg-emerald-500, :root .bg-emerald-600, :root .\!bg-emerald-600 { background-color: var(--good-fill) !important; color: var(--accent-on) !important; }
:root .\!bg-emerald-600.\!text-white { color: var(--accent-on) !important; }
/* danger tints → alpha of the danger ink */
:root .bg-danger-500\/15, :root .bg-danger-500\/18, :root .bg-danger-600\/10, :root .bg-rose-500\/15 { background-color: color-mix(in srgb, var(--danger-ink) 14%, transparent) !important; }
:root .border-danger-500\/40 { border-color: color-mix(in srgb, var(--danger-ink) 40%, transparent) !important; }
/* the at-risk chip (views6.js riskBadge) paints its band colour inline; the
   "healthy" band is the good token, read from the theme via a class hook so
   the JS literal can go. */
.risk-chip.is-healthy { color: var(--txt-1) !important; background: var(--good-weak) !important; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--good) 33%, transparent) !important; }

/* ── 33.2 ITEM 7 — the neutral inks: three steps, not Tailwind's slate ──── */
:root .text-slate-100, :root .text-slate-200,
:root .hover\:text-slate-100:hover, :root .hover\:text-slate-200:hover { color: var(--txt-1); }
:root .text-slate-300, :root .text-slate-400,
:root .hover\:text-slate-300:hover, :root .hover\:text-slate-400:hover { color: var(--txt-2); }
:root .text-slate-500, :root .text-slate-600, :root .text-slate-700 { color: var(--txt-3); }
/* the !important variants need the flag to beat tw.css's own !important */
:root .\!text-slate-400 { color: var(--txt-2) !important; }
:root .\!text-slate-500, :root .\!text-slate-700 { color: var(--txt-3) !important; }
:root .fill-slate-300 { fill: var(--txt-2); }
:root .fill-slate-500, :root .fill-slate-600 { fill: var(--txt-3); }
/* belt chips keep their own ink (BELT_BG): white-belt text-slate-900 on the
   light chip is a rank colour, exempt (see §29.1 :not() list). */
/* ICONS IN A ROW TAKE THEIR SIBLINGS' INK (item 7, second half). A glyph in a
   list row, a panel head, a KPI tile or a nav is never its own colour: it is
   --txt-3 when the row is quiet, --txt-2 on a card row, --txt-1 when active.
   The utilities that gave individual icons a colour are collapsed here. */
.panel-head i, .kpi-strip .panel i, .sec-head i, .section-label i,
.acct-row i, .dest i, .dtile > i:not(.dtile-lock), .tap-row i, .tap i,
.land-list li i, .plan-feats li i, .ob-sheet-list li i, .staff-dock i { color: var(--txt-2); }
.acct-row.is-danger i { color: var(--danger-ink); }
.acct-row.is-scheduled i { color: var(--warn-ink); }
/* a heading glyph that carried a semantic tint (panel heads with text-flame-400
   / text-emerald-400): the heading is not a state; the glyph is ink. */
.panel-head i.text-flame-400, .panel-head i.text-emerald-400, .panel-head i.text-danger-400,
.sec-head i.text-flame-400, .sec-head i.text-emerald-400, .sec-head i.text-op-400 { color: var(--txt-2) !important; }
/* status glyphs INSIDE a row (a check for done, a fire for a live streak) keep
   the semantic ink — those are the two the eye is meant to catch. */
.acct-row i.text-emerald-400, li i.fa-check.text-emerald-400 { color: var(--txt-1) !important; }

/* ── 33.3 ITEM 3 — focus ring, text-box outline, toast bar: the lime ────── */
/* One focus treatment for every field: 1px lime border + a soft lime halo.
   style.css still declares a coral halo on .input:focus (rgba(198,43,36,.18))
   and theme-v2 §5 only re-inked the border, so the halo was the old colour
   in dark and the §29.1 light rule used the neutral accent-weak. */
.input:focus, input:focus, textarea:focus, select:focus,
.input:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: none;
  border-color: var(--k-focus);
  box-shadow: none;
}
html[data-theme="light"] .input:focus, html[data-theme="light"] input:focus,
html[data-theme="light"] textarea:focus, html[data-theme="light"] select:focus {
  border-color: var(--k-focus);
  box-shadow: none;
}
/* an invalid field keeps the danger border; its halo is danger too, both modes
   (the light rule is restated because html[data-theme] adds specificity) */
.input.is-invalid:focus, input.is-invalid:focus, textarea.is-invalid:focus,
html[data-theme="light"] .input.is-invalid:focus, html[data-theme="light"] input.is-invalid:focus, html[data-theme="light"] textarea.is-invalid:focus {
  border-color: var(--danger-ink);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger-ink) 22%, transparent);
}
/* checkboxes / radios / range: the native accent is the lime, not the UA blue */
input[type="checkbox"], input[type="radio"], input[type="range"], progress { accent-color: var(--accent-fill); }
/* Google's button focus halo was still coral (style.css:604) */
.btn-google:focus-visible { box-shadow: 0 0 0 3px var(--k-focus); }
/* Chrome autofill paints a UA blue-white field; keep the token surface */
input:-webkit-autofill, input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--txt-1);
  -webkit-box-shadow: 0 0 0 1000px var(--sunken) inset;
  caret-color: var(--txt-1);
}
/* toast: the success bar and glyph are the signature lime (Reqwa: "Cancelled.
   You keep everything…" carried a cyan bar). Semantic warn/err stay. */
.toast.ok { border-left-color: var(--accent-fill); }
.toast.ok .toast-ico { color: var(--txt-1); }
html[data-theme="light"] .toast.ok .toast-ico { color: var(--txt-1); }
html[data-theme="light"] .toast.info { border-left-color: var(--accent-fill); }
html[data-theme="light"] .toast.info .toast-ico { color: var(--txt-1); }
/* selection highlight follows the accent too */
::selection { background: color-mix(in srgb, var(--accent-fill) 45%, transparent); color: var(--txt-1); }

/* ── 33.4 ITEM 4 — .btn-good is the primary treatment ───────────────────── */
/* An approve / confirm / accept button is the primary action of its row, and
   the product has ONE primary: dark ink on lime. The cyan fill was the old
   semantic-green fill on a control, which is a second primary. */
/* the pending-approval row (views6.js gymApprove): identity on line one,
   actions on their own line, right-aligned, equal height — the button no
   longer fights the belt chip for the same 40px of row. */
.pend-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .65rem .75rem; align-items: center; }
.pend-row .pend-id { min-width: 0; }
.pend-row .pend-meta { display: flex; align-items: center; gap: .5rem; margin-top: .25rem; flex-wrap: wrap; }
.pend-row .pend-acts { grid-column: 1 / -1; display: flex; justify-content: flex-end; align-items: center; gap: .5rem; }
.pend-row .pend-acts .btn-good { padding: 0 1.05rem; }
.pend-row .pend-acts .btn-ghost { width: 44px; padding: 0; }
@media (min-width: 640px) {
  .pend-row { grid-template-columns: auto minmax(0, 1fr) auto; }
  .pend-row .pend-acts { grid-column: auto; }
}

/* ── 33.5 ITEM 5 — the @ prefix sits on the input's text baseline ───────── */
/* The old shape was `absolute left-3 top-1/2 -translate-y-1/2` on a wrapper.
   fieldError() inserts the inline error <p> AFTER the input, INSIDE that
   wrapper, so the wrapper grows and 50% of it is no longer the middle of the
   input — the @ drifted down onto the error line (Reqwa's screenshot). The
   affix is now sized to the INPUT (top/bottom 0 of a wrapper that contains
   only the input's box via `height: var(--field-h)`), centred with a grid,
   and the input's own left padding is the token, not a Tailwind override. */
.field-affix { position: relative; }
.field-affix > .input, .field-affix > input.input { padding-left: 2.15rem !important; }
.field-affix > .affix {
  position: absolute; left: 0; top: 0; height: 48px; width: 2.15rem;
  display: grid; place-items: center;
  font-weight: 700; font-size: .94rem; line-height: 1;
  color: var(--txt-3); pointer-events: none; user-select: none;
}
@media (max-width: 767px) { .field-affix > .affix { font-size: 16px; } }
.field-affix > .input:focus ~ .affix, .field-affix > .input:not(:placeholder-shown) ~ .affix { color: var(--txt-2); }
.field-affix > .input.is-invalid ~ .affix { color: var(--danger-ink); }

/* ── 33.6 ITEM 6 — the top bar (DS4) — SUPERSEDED by §36 (DS6) and deleted in
   the same pass so the bar has one owner. The `.glass` flat-ground rule moved
   to §36 verbatim; `fa-calendar-check` for check-in (D9-3) still holds. ── */
/* ── 33.7 ITEM 1 (both modes) — no outline on type or glyphs, ever ──────── */
/* :focus-visible is the one legitimate outline; it is a 2px lime ring 2px
   outside the control and never on a text node. The .path-opt duplicate and
   the review-only dashed outline (§17.8, commented) are the only others. */
:focus-visible { outline: 2px solid var(--k-focus); outline-offset: 2px; }
.input:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible, .path-opt:focus-visible { outline: none; }
/* no text-stroke / text-shadow anywhere in the product; asserted by the DS4 probe */


/* ══════════════════════════════════════════════════════════════════════════
   §34. WAVE 6b PART 2 — DS5 (Designer, 2026-09-07). The Roll Card + the tier
   surfaces + Phase-4 hardening. Every rule below paints with the §1 tokens
   (dark) and inherits the light block through them; where light needs its own
   statement it says `html[data-theme="light"]` — D9-3: lime is a FILL in light,
   never type; --good is green; no plates behind glyphs.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 34.1 SCORE CARD — the first block after the header (PRD-F1 §3.1) ─────── */
.rl-scorecard { padding: 1.15rem 1.15rem 1.1rem; margin-bottom: .9rem; }
.rl-sc-top { display: grid; grid-template-columns: auto 1fr; gap: .4rem 1.1rem; align-items: end; }
.rl-sc-fig { min-width: 0; }
.rl-sc-fig .section-label { margin-bottom: .1rem; }
.rl-sc-num { font-size: 3.6rem; line-height: .95; font-weight: 900; letter-spacing: -.045em; color: var(--txt-1); }
html[data-theme="light"] .rl-sc-num { color: var(--txt-1); }
.rl-sc-sub { margin: 0; align-self: end; padding-bottom: .35rem; font-size: .84rem; line-height: 1.45; color: var(--txt-2); text-wrap: pretty; }
@media (max-width: 419px) { .rl-sc-top { grid-template-columns: 1fr; } .rl-sc-sub { padding-bottom: 0; } }
.rl-sc-axes { margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--line); display: grid; gap: .5rem; }
.rl-sc-axes-h { font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-3); margin-bottom: .1rem; }
.rl-sc-axis { display: grid; grid-template-columns: 7.2rem 1fr 2.2rem; align-items: center; gap: .7rem; min-height: 28px; }
.rl-sc-axis-l { font-size: .7rem; font-weight: 750; letter-spacing: .06em; color: var(--txt-2); }
.rl-sc-axis-v { font-size: .86rem; font-weight: 750; text-align: right; color: var(--txt-2); }
.rl-sc-bar { display: block; height: 8px; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line); overflow: hidden; }
.rl-sc-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--txt-3); }
.rl-sc-axis.is-top .rl-sc-axis-l, .rl-sc-axis.is-top .rl-sc-axis-v { color: var(--txt-1); font-weight: 850; }
.rl-sc-axis.is-top .rl-sc-bar > span { background: var(--accent-fill); }
.rl-sc-pre, .rl-sc-coverage { margin: .9rem 0 0; font-size: .84rem; line-height: 1.5; color: var(--txt-2); }
.rl-sc-coverage { display: flex; gap: .5rem; align-items: flex-start; color: var(--txt-3); }
.rl-sc-coverage i { margin-top: .2rem; color: var(--txt-3); }
.rl-share { margin-top: 1.1rem; width: 100%; }

/* phases — the structured long read (F1-PROMPT §5); falls back to .rl-summary */
.rl-phases { margin-top: .5rem; display: grid; gap: .1rem; }
.rl-phase { padding: .7rem 0; }
.rl-phase + .rl-phase { border-top: 1px solid var(--line); }
.rl-phase-h { display: flex; align-items: baseline; gap: .6rem; }
.rl-phase-t { font-size: .95rem; font-weight: 750; letter-spacing: -.01em; color: var(--txt-1); }
.rl-phase-p { margin: .35rem 0 0; font-size: .9rem; line-height: 1.55; color: var(--txt-2); }

/* ── 34.2 ROLL CARD SHEETS — frame step, consent step ──────────────────── */
.rc-sheet { max-width: 30rem; }
.rc-stage { margin-top: .9rem; display: grid; place-items: center; }
.rc-preview {
  display: block; width: auto; max-width: 100%; height: min(46dvh, 420px); aspect-ratio: 9 / 16;
  border-radius: var(--radius-sm); border: 1px solid var(--line-2); background: var(--sunken); object-fit: contain;
}
.rc-scrub { display: block; margin-top: .9rem; padding: .3rem 0; }
.rc-scrub input[type="range"] { width: 100%; height: 44px; margin: 0; background: transparent; -webkit-appearance: none; appearance: none; }
.rc-scrub input[type="range"]::-webkit-slider-runnable-track { height: 8px; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line-2); }
.rc-scrub input[type="range"]::-moz-range-track { height: 8px; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line-2); }
.rc-scrub input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 28px; height: 28px; margin-top: -11px; border-radius: 50%; background: #FFFFFF; border: 2px solid var(--ground); box-shadow: var(--lift-1); }
.rc-scrub input[type="range"]::-moz-range-thumb { width: 28px; height: 28px; border-radius: 50%; background: #FFFFFF; border: 2px solid var(--ground); box-shadow: var(--lift-1); }
.rc-consent-line { color: var(--txt-1); }
.rc-consent-row { margin-top: 1rem; }
.rc-consent-note { margin-top: .7rem; }
.rc-wrap .cf-actions { margin-top: 1.1rem; }

/* ── 34.3 FILM ROOM — day groups + Session Read section (PRD-4 §2.6) ────── */
.rl-day-h { display: flex; align-items: center; justify-content: space-between; gap: .7rem; min-height: 44px; margin: .5rem 0 .15rem; padding: 0 .25rem; }
.rl-list > .rl-day-h:first-child { margin-top: 0; }
.rl-day-h-t { font-size: .74rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--txt-3); }
.rl-day-h-go { display: inline-flex; align-items: center; gap: .4rem; min-height: 44px; padding: 0 .85rem; border-radius: 999px; font-size: .8rem; font-weight: 750; color: var(--txt-1); background: var(--accent-weak); border: 1px solid transparent; }
.rl-day-h-go i { color: var(--txt-1); font-size: .78rem; }
html[data-theme="light"] .rl-day-h-go i { color: var(--txt-2); }
.rl-card.is-grouped { border-color: var(--line); }
.rl-session { margin-top: .9rem; padding: 0; overflow: hidden; }
.rl-session-head { display: flex; align-items: center; justify-content: space-between; gap: .8rem; width: 100%; min-height: 64px; padding: .95rem 1.15rem; text-align: left; color: var(--txt-1); background: transparent; }
.rl-session-head i { color: var(--txt-3); transition: transform .18s var(--ease); }
.rl-session.is-open .rl-session-head i { transform: rotate(180deg); }
.rl-session-k { display: grid; gap: .15rem; min-width: 0; }
.rl-session-line { font-size: .9rem; font-weight: 700; color: var(--txt-1); }
.rl-session-body { padding: 0 1.15rem 1.1rem; border-top: 1px solid var(--line); }
.rl-session-body > :first-child { margin-top: .9rem; }
.rl-session-p { margin: 0; font-size: .95rem; line-height: 1.55; color: var(--txt-1); }
.rl-session-warn, .rl-session-note, .rl-handoff-note { margin: .8rem 0 0; font-size: .84rem; line-height: 1.5; color: var(--txt-2); }
.rl-session-warn { color: var(--txt-1); }
.rl-session-go { margin-top: .8rem; width: 100%; min-height: 48px; }
.rl-session-rolls-toggle { display: inline-flex; align-items: center; min-height: 44px; margin-top: .4rem; padding: 0 .25rem; font-size: .84rem; font-weight: 750; color: var(--txt-2); background: transparent; }
.rl-session-rolls { display: grid; gap: .4rem; margin-top: .2rem; }
.rl-session-roll { display: flex; align-items: center; justify-content: space-between; gap: .7rem; min-height: 48px; padding: .6rem .85rem; text-align: left; border-radius: var(--radius-sm); background: var(--sunken); border: 1px solid var(--line); color: var(--txt-1); font-size: .9rem; }
.rl-session-roll.is-here { border-color: var(--line-2); background: var(--raised); }
.rl-session-roll-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rl-session-roll .tnum { color: var(--txt-2); font-weight: 750; }

/* ── 34.4 COACH HANDOFF — athlete side (PRD-4 §3.6) ──────────────────────── */
.rl-handoff { margin-top: .9rem; padding: 1.1rem 1.15rem; }
.rl-handoff-live { display: grid; gap: .5rem; margin-top: .7rem; }
.rl-handoff-row { display: flex; align-items: center; justify-content: space-between; gap: .7rem; min-height: 48px; }
.rl-handoff-who { display: inline-flex; align-items: center; gap: .5rem; min-width: 0; font-size: .92rem; font-weight: 700; color: var(--txt-1); }
.rl-handoff-who i { color: var(--txt-1); }
.rl-handoff-who small { font-weight: 600; color: var(--txt-3); }
.rl-handoff-revoke { min-height: 44px; flex: none; }
.rl-handoff-coachnote { margin: .2rem 0 0; padding: .7rem .9rem; border-radius: var(--radius-sm); background: var(--raised); border: 1px solid var(--line); font-size: .9rem; line-height: 1.5; color: var(--txt-1); }
.rl-handoff-cta { margin-top: .8rem; min-height: 48px; width: 100%; }
.rl-handoff-pick { margin-top: .9rem; }
.rl-handoff-note-f { display: block; margin-top: .8rem; }
.rl-handoff-note-f textarea { min-height: 72px; resize: vertical; }

/* ── 34.5 THEN-VS-NOW (PRD-4 §1.8) ───────────────────────────────────────── */
.tvn-entry { display: flex; align-items: center; gap: .75rem; width: 100%; min-height: 56px; margin-bottom: .9rem; padding: .8rem 1rem; text-align: left; border-radius: var(--radius); background: var(--card); border: 1px solid var(--line); color: var(--txt-1); font-size: .95rem; font-weight: 750; }
.tvn-entry > i:first-child { color: var(--txt-1); }
html[data-theme="light"] .tvn-entry > i:first-child { color: var(--txt-2); }
.tvn-entry > span { flex: 1; min-width: 0; }
.tvn-entry > i:last-child { color: var(--txt-3); font-size: .8rem; }
.tvn-window, .tvn-pair, .tvn-axes, .tvn-leaks, .tvn-read, .tvn-state { padding: 1.05rem 1.15rem; margin-top: .9rem; }
.tvn-seg { grid-template-columns: repeat(2, 1fr); }
@media (min-width: 480px) { .tvn-seg { grid-template-columns: repeat(4, 1fr); } }
.tvn-pair-line { margin: 0; font-size: .92rem; line-height: 1.5; color: var(--txt-1); }
.tvn-pair-rows { display: grid; gap: .45rem; margin-top: .8rem; }
.tvn-pair-row { display: grid; grid-template-columns: 3.2rem 1fr auto; align-items: center; gap: .6rem; min-height: 40px; }
.tvn-pair-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; color: var(--txt-1); font-size: .92rem; }
.tvn-pair-s { font-weight: 800; color: var(--txt-2); }
.tvn-legend { display: flex; gap: 1rem; font-size: .7rem; font-weight: 750; letter-spacing: .06em; text-transform: uppercase; color: var(--txt-3); margin-bottom: .6rem; }
.tvn-legend span { display: inline-flex; align-items: center; gap: .4rem; }
.tvn-swatch { display: inline-block; width: 14px; height: 6px; border-radius: 3px; background: var(--txt-3); }
.tvn-swatch.is-now { background: var(--accent-fill); }
html[data-theme="light"] .tvn-swatch.is-now { background: var(--accent-fill); box-shadow: var(--k-tint-edge); }   /* data lime in both themes (owner theme A) */
.tvn-axis { display: grid; grid-template-columns: 6.6rem 1fr; grid-template-areas: "l bars" "l v"; align-items: center; gap: .15rem .7rem; padding: .55rem 0; }
.tvn-axis + .tvn-axis { border-top: 1px solid var(--line); }
.tvn-axis-l { grid-area: l; font-size: .7rem; font-weight: 750; letter-spacing: .06em; color: var(--txt-2); }
.tvn-axis-bars { grid-area: bars; display: grid; gap: 4px; }
.tvn-bar { display: block; height: 6px; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line); overflow: hidden; }
.tvn-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--txt-3); }
.tvn-bar.is-now > span { background: var(--accent-fill); }
html[data-theme="light"] .tvn-bar.is-now > span { background: var(--accent-fill); box-shadow: var(--k-tint-edge); }
.tvn-axis-v { grid-area: v; font-size: .82rem; font-weight: 750; color: var(--txt-2); display: inline-flex; align-items: center; gap: .4rem; }
.tvn-axis-v i { font-size: .7rem; color: var(--txt-3); }
.tvn-axis-d { grid-area: v; justify-self: end; display: inline-flex; align-items: baseline; gap: .35rem; font-size: .8rem; font-weight: 800; color: var(--txt-3); }
.tvn-axis-d.is-up { color: var(--txt-1); }
.tvn-axis-d.is-down { color: var(--danger-ink); }
.tvn-axis-dl { font-size: .68rem; letter-spacing: .06em; text-transform: uppercase; }
.tvn-axis.is-quiet { grid-template-areas: "l note"; grid-template-columns: 6.6rem 1fr; }
.tvn-axis-note { grid-area: note; font-size: .82rem; line-height: 1.45; color: var(--txt-3); }
.tvn-leaks { display: flex; flex-wrap: wrap; gap: .5rem 1.2rem; }
.tvn-leak { display: inline-flex; align-items: center; gap: .45rem; min-height: 32px; font-size: .88rem; font-weight: 700; color: var(--txt-1); }
.tvn-leak i { color: var(--txt-1); }
.tvn-leak.is-open i { color: var(--txt-3); }
.tvn-distinction { margin: 1rem 0 0; padding-top: .9rem; border-top: 1px solid var(--line); font-size: .82rem; line-height: 1.5; color: var(--txt-3); }
.tvn-card-cta { margin-top: .9rem; width: 100%; min-height: 52px; }
/* subject rules for the state hooks (test:orphans reads subject position) */
.tvn { min-width: 0; }
.tvn-bar.is-then { opacity: .9; }
.tvn-leak.is-open { color: var(--txt-2); }
.rl-session.is-open { border-color: var(--line-2); }

/* ── 34.6 ALLOWANCE STRIP — Progress (PRD-4 §5.3) ────────────────────────── */
.allow-strip { padding: 1.05rem 1.15rem; margin-bottom: 1rem; }
.allow-rows { display: grid; gap: .15rem; }
.allow-row { display: grid; grid-template-columns: 1fr auto; grid-template-areas: "l v" "bar bar" "r r"; align-items: center; gap: .2rem .7rem; min-height: 44px; padding: .55rem 0; }
.allow-row + .allow-row { border-top: 1px solid var(--line); }
.allow-l { grid-area: l; font-size: .9rem; font-weight: 700; color: var(--txt-1); }
.allow-v { grid-area: v; font-size: .9rem; font-weight: 800; color: var(--txt-1); }
.allow-bar { grid-area: bar; display: block; height: 6px; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line); overflow: hidden; }
.allow-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--accent-fill); }
html[data-theme="light"] .allow-bar > span { background: var(--txt-1); }
.allow-r { grid-area: r; font-size: .78rem; color: var(--txt-3); }
.allow-row.is-off .allow-v { font-weight: 650; color: var(--txt-3); }
.allow-row.is-off { grid-template-areas: "l v"; }
.allow-row.is-spent .allow-bar > span { background: var(--txt-3); }
.allow-row.is-academy { grid-template-areas: "l v" "r r"; }
.allow-note { margin: .8rem 0 0; font-size: .78rem; line-height: 1.5; color: var(--txt-3); }

/* ── 34.7 BELT PROGRESS — Progress, solo Pro+ (PRD-4 §6) ─────────────────── */
.bp-card { padding: 1.05rem 1.15rem; margin-bottom: 1rem; }
.bp-frame { margin: .25rem 0 0; font-size: .95rem; font-weight: 700; line-height: 1.45; color: var(--txt-1); text-wrap: pretty; }
.bp-card.is-joined .bp-frame { color: var(--txt-2); font-weight: 600; }
.bp-joined { margin: .6rem 0 0; font-size: .92rem; line-height: 1.5; color: var(--txt-1); }
.bp-sigs { display: grid; gap: .1rem; margin-top: .9rem; }
.bp-sig { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: .6rem; min-height: 44px; padding: .5rem 0; }
.bp-sig + .bp-sig { border-top: 1px solid var(--line); }
.bp-sig-l { font-size: .9rem; color: var(--txt-1); }
.bp-sig-v { font-size: .9rem; font-weight: 800; color: var(--txt-2); }
.bp-sig-s { display: inline-flex; align-items: center; min-height: 28px; padding: 0 .65rem; border-radius: 999px; font-size: .72rem; font-weight: 750; letter-spacing: .02em; color: var(--txt-2); background: var(--sunken); border: 1px solid var(--line); white-space: nowrap; }
.bp-sig.is-met .bp-sig-s { color: var(--txt-1); background: var(--accent-weak); border-color: transparent; }
.bp-sig.is-approaching .bp-sig-s { color: var(--txt-1); }
.bp-sig.is-not_yet .bp-sig-s { color: var(--txt-3); }
.bp-note { margin: .8rem 0 0; font-size: .8rem; line-height: 1.5; color: var(--txt-3); }
.bp-rubric { font-style: normal; }
.bp-hist { margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.bp-hist-h { font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-3); margin-bottom: .4rem; }
.bp-hist-row { display: flex; align-items: center; gap: .7rem; min-height: 40px; }
.bp-hist-when { font-size: .82rem; color: var(--txt-2); }
.bp-hist-k { font-size: .76rem; color: var(--txt-3); }
.bp-card.is-locked .bp-note { color: var(--txt-2); }

/* ── 34.8 STRIPES PICKER — onboarding + Me (PRD-3 §5) ────────────────────── */
.ob-stripes { margin-top: 1rem; }
.ob-stripes .ob-field-l { margin-bottom: .45rem; }
.stripes-pick { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .4rem; }
.stripes-opt { display: grid; place-items: center; gap: .3rem; min-height: 56px; padding: .45rem .2rem; border-radius: var(--radius-sm); background: var(--card); border: 1px solid var(--line); color: var(--txt-2); }
.stripes-opt.on { border-color: transparent; color: var(--txt-1); background: var(--k-fill); }   /* no black selected ring in light */
.stripes-dots { display: inline-flex; gap: 3px; }
.stripes-dots i { display: block; width: 4px; height: 14px; border-radius: 2px; background: var(--line-2); }
.stripes-dots i.is-on { background: currentColor; }
.stripes-n { font-size: .74rem; font-weight: 750; }
.stripes-panel .stripes-row { display: grid; gap: .7rem; }
.stripes-panel .stripes-pick { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.belt-confirm { display: flex; gap: .5rem; align-items: flex-start; margin: .8rem 0 0; font-size: .82rem; line-height: 1.5; color: var(--txt-2); }
.belt-confirm.is-on { color: var(--txt-1); font-weight: 650; }
.belt-confirm.is-on i { color: var(--txt-1); margin-top: .2rem; }
.stripes-panel { margin-top: 1rem; }
.bp-card.is-joined { border-color: var(--line-2); }
.bp-hist-belt { display: inline-flex; }

/* ── 34.9 TIER SURFACES — Weekly Read · Closing Leaks · Partner Log (DS5 item 6, views12.js) ── */
/* Shared frame for the tier screens. `.tier-line` is the card_line from
   COPY-WAVE3 under the title; `.t-locked` is the standard locked card — the
   locked sentence and the door, NO teaser data (PRD-1 §1.6, PRD-2 §2.7). */
.tier { min-width: 0; }
.tier-line { margin: -.2rem 0 1rem; font-size: .92rem; line-height: 1.5; color: var(--txt-2); text-wrap: pretty; }
.tier-line-k { display: inline-block; margin-left: .35rem; font-weight: 800; color: var(--txt-1); }
.t-locked { padding: 1.15rem 1.15rem 1.05rem; margin-bottom: 1rem; }
.t-locked-line { margin: 0; font-size: .95rem; line-height: 1.5; color: var(--txt-1); text-wrap: pretty; }
.t-locked-go { margin-top: .9rem; width: 100%; min-height: 48px; }
/* The Progress-page doors (one row each, below Belt Progress). A gated door is
   a door, not a blurred value: full contrast, lock as the only signal. */
.tier-doors { display: grid; gap: .6rem; margin-bottom: 1rem; }
.tier-doors .tvn-entry { margin-bottom: 0; }
.tier-doors .tvn-entry small { display: block; margin-top: .15rem; font-size: .78rem; font-weight: 500; line-height: 1.4; color: var(--txt-3); }
.tvn-entry.is-gated > i:first-child { color: var(--txt-3); }
.tvn-entry.is-gated > i:last-child { color: var(--txt-1); }
html[data-theme="light"] .tvn-entry.is-gated > i:last-child { color: var(--txt-1); }
.wr-sec { padding: 1.05rem 1.15rem; margin-bottom: .9rem; }
.wr-sec .section-label { margin-bottom: .5rem; }
.wr-empty { margin: 0; font-size: .92rem; line-height: 1.5; color: var(--txt-2); text-wrap: pretty; }
.wr-none { margin: .2rem 0 0; font-size: .95rem; color: var(--txt-3); }

/* Weekly Read Home card — header is the whole tap target; Mon–Wed the body is
   open (PRD-1 §1.6), the rest of the week the header alone is the entry. */
.wr-card { padding: 0; overflow: hidden; margin-bottom: 1rem; }
.wr-head { display: flex; align-items: center; justify-content: space-between; gap: .75rem; width: 100%; min-height: 56px; padding: .85rem 1.15rem; text-align: left; color: var(--txt-1); }
.wr-k { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.wr-week { font-size: .95rem; font-weight: 800; letter-spacing: -.01em; }
.wr-go { display: inline-flex; align-items: center; gap: .4rem; flex: none; font-size: .82rem; font-weight: 750; color: var(--txt-2); }
.wr-go i { font-size: .72rem; color: var(--txt-3); }
.wr-body { padding: 0 1.15rem 1.05rem; border-top: 1px solid var(--line); }
.wr-card.is-open .wr-body { padding-top: .9rem; }
.wr-cols { display: grid; grid-template-columns: 1fr; gap: .9rem; }
@media (min-width: 480px) { .wr-cols { grid-template-columns: 1fr 1fr; } }
.wr-col { min-width: 0; }
.wr-col-h { font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-3); margin-bottom: .35rem; }
.wr-row { display: flex; align-items: center; justify-content: space-between; gap: .7rem; min-height: 40px; padding: .4rem 0; }
.wr-row + .wr-row { border-top: 1px solid var(--line); }
.wr-row-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .92rem; font-weight: 700; color: var(--txt-1); }
.wr-row-v { flex: none; display: inline-flex; align-items: center; gap: .35rem; font-size: .85rem; font-weight: 750; color: var(--txt-2); }
.wr-row-v i { font-size: .7rem; color: var(--txt-3); }
.wr-row.is-good .wr-row-v { color: var(--txt-1); }
.wr-drill { margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.wr-drill p { margin: 0; font-size: .92rem; line-height: 1.5; color: var(--txt-1); }
.wr-drill-t { margin: 0; font-size: .95rem; line-height: 1.55; color: var(--txt-1); text-wrap: pretty; }
.wr-src { margin: .5rem 0 0; font-size: .76rem; font-weight: 700; letter-spacing: .04em; color: var(--txt-3); }

/* Closing Leaks — one track per flagged technique; the state chip is the only
   colour: open/stalled quiet, improving/closing accent-weak, closed --good. */
.cl-chip { display: inline-flex; align-items: center; min-height: 22px; padding: 0 .5rem; margin-left: .4rem; border-radius: 999px; vertical-align: middle; font-size: .66rem; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--txt-2); background: var(--sunken); border: 1px solid var(--line); white-space: nowrap; }
.cl-chip.is-improving, .cl-chip.is-closing { color: var(--txt-1); background: var(--accent-weak); border-color: transparent; }
.cl-chip.is-closed { color: var(--txt-1); background: var(--good-weak); border-color: transparent; }
html[data-theme="light"] .cl-chip.is-closed { color: var(--txt-1); }
.cl-chip.is-stalled { color: var(--txt-3); }
.cl-chip.is-open { color: var(--txt-2); }
.cl-track { padding: .6rem 0; }
.cl-track + .cl-track { border-top: 1px solid var(--line); }
.cl-track-top { display: flex; align-items: center; justify-content: space-between; gap: .7rem; min-height: 32px; }
.cl-track-top .cl-chip { margin-left: 0; flex: none; }
.cl-track-t { min-width: 0; font-size: .95rem; font-weight: 750; color: var(--txt-1); }
.cl-track-t small { display: block; font-size: .76rem; font-weight: 600; color: var(--txt-3); }
.cl-line { margin: .3rem 0 0; font-size: .85rem; font-weight: 700; color: var(--txt-2); }
.cl-note { margin: .35rem 0 0; font-size: .8rem; line-height: 1.5; color: var(--txt-3); }
.cl-closed { min-width: 0; }
.cl-closed .cl-track-t { color: var(--txt-2); }
.cl-track.is-closed .cl-line { color: var(--txt-1); }
.cl-track.is-stalled .cl-track-t { color: var(--txt-2); }
.cl-track.is-open, .cl-track.is-improving, .cl-track.is-closing { min-width: 0; }

/* Partner Log — a row per regular; the delta is the sentence, coloured only
   by its sign. Anonymous partners get the belt badge and a generic avatar. */
.pl-list { display: grid; gap: .5rem; margin-bottom: 1rem; }
.pl-row { display: flex; align-items: center; gap: .8rem; width: 100%; min-height: 64px; padding: .75rem 1rem; text-align: left; border-radius: var(--radius); background: var(--card); border: 1px solid var(--line); color: var(--txt-1); }
.pl-row.is-static { cursor: default; }
.pl-av { flex: none; display: inline-flex; }
.pl-av-anon { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 999px; background: var(--raised); border: 1px solid var(--line); color: var(--txt-3); font-size: .9rem; }
.pl-main { flex: 1; min-width: 0; display: grid; gap: .15rem; }
.pl-t { font-size: .95rem; font-weight: 750; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-s { font-size: .8rem; font-weight: 600; color: var(--txt-3); }
.pl-note { font-size: .76rem; line-height: 1.4; color: var(--txt-3); }
.pl-delta { flex: none; max-width: 42%; text-align: right; font-size: .76rem; font-weight: 750; line-height: 1.35; color: var(--txt-3); }
.pl-delta.is-up { color: var(--txt-1); }
.pl-delta.is-down { color: var(--danger-ink); }
.pl-delta.is-even { color: var(--txt-2); }
.pl-unreg { margin-top: .4rem; }
.pl-unreg .cl-note { margin: 0 0 .7rem; }
.pl-detail-head { display: grid; gap: .3rem; }
.pl-detail-id { display: flex; align-items: center; gap: .7rem; }
.pl-detail-id .pl-av-anon { width: 44px; height: 44px; }
.pl-summary { padding-bottom: 1.1rem; }
.pl-summary .pl-delta { display: block; max-width: none; text-align: left; margin-top: .4rem; font-size: .88rem; }
.pl-big { display: flex; align-items: baseline; gap: .6rem; }
.pl-big-v { font-size: 2.2rem; font-weight: 900; letter-spacing: -.03em; line-height: 1; color: var(--txt-1); }
.pl-big-s { font-size: .9rem; font-weight: 700; color: var(--txt-2); }
.pl-split { margin: .5rem 0 0; font-size: .82rem; font-weight: 700; color: var(--txt-3); }
.pl-methods { display: flex; flex-wrap: wrap; gap: .45rem; }
.pl-method { display: inline-flex; align-items: center; gap: .45rem; min-height: 34px; padding: 0 .75rem; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line); font-size: .82rem; font-weight: 700; color: var(--txt-1); }
.pl-method b { color: var(--txt-2); font-weight: 800; }
.pl-recent { display: grid; grid-template-columns: 4.2rem 1fr auto; align-items: center; gap: .6rem; min-height: 40px; padding: .35rem 0; }
.pl-recent + .pl-recent { border-top: 1px solid var(--line); }
.pl-recent-d { font-size: .8rem; font-weight: 700; color: var(--txt-3); }
.pl-recent-r { font-size: .9rem; font-weight: 750; color: var(--txt-1); text-transform: capitalize; }
.pl-recent.is-win .pl-recent-r { color: var(--txt-1); }
.pl-recent.is-loss .pl-recent-r { color: var(--txt-2); }
.pl-recent.is-draw .pl-recent-r { color: var(--txt-2); }
.pl-recent-m { font-size: .8rem; color: var(--txt-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 9rem; }

/* ══════════════════════════════════════════════════════════════════════════
   35. DS6 — THE OVERHAUL SYSTEM (Second Designer, 2026-09-07)
   Direction note approved by Tech Lead (thread msg 3778989 / 3779011). Form
   changes, content does not. This section is the ONE place the new geometry
   lives; every page pass below (§36+) only applies these tokens. A successor
   styling a page should need nothing that is not declared here.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 35.1 TOKENS ─────────────────────────────────────────────────────────── */
:root {
  /* spacing scale — 4-based; use these, not ad-hoc rem values */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;
  --gutter: var(--s4);        /* page side padding at 390 */
  --card-pad: 20px;           /* inside a card */
  --card-gap: var(--s3);      /* between sibling cards */
  --section-gap: var(--s6);   /* between page sections */
  --label-gap: var(--s3);     /* section label → its content */

  /* radii — ONE scale: cards 20, inner panels/tiles 14, controls pill.
     The old 22/16/30 trio is re-pointed so the ~180 existing call sites
     move without being edited (token map in HANDOFF-Designer-wave7 §3). */
  --r-card: 20px;
  --r-inner: 14px;
  --r-ctl: 999px;
  --radius: var(--r-card);
  --radius-sm: var(--r-inner);
  --radius-lg: var(--r-card);

  /* icon optical sizes — one per context, single-tone (fa-solid only) */
  --ico-row: 16px;   /* inside rows and buttons */
  --ico-nav: 18px;   /* topbar / capsule glyphs */
  --ico-tile: 20px;  /* destination tiles */

  /* control heights */
  --ctl-h: 48px; --ctl-h-sm: 44px; --ctl-h-lg: 52px;   /* DS8: -sm was 40 — QA tap rule is 44 on the MEASURED box (Reqwa: no transparent extension), so the small control floor moves to 44 */

  /* type rhythm */
  --t-title: 24px;   /* page title, 800, -.02em */
  --t-card: 16px;    /* card title, 700 */
  --t-body: 15px;    /* body, 400, --txt-2 */
  --t-kicker: 11px;  /* section kicker, 700, caps, .09em, --txt-3 */
  --t-figure: 40px;  /* KPI figure, 800, tabular */

  /* motion — three durations, one curve (--ease is declared in §1) */
  --dur-1: 120ms;    /* press feedback */
  --dur-2: 220ms;    /* state change, reveal */
  --dur-3: 420ms;    /* page rise */
}

/* ── 35.2 SURFACES — one card geometry ───────────────────────────────────── */
.card, .panel, .stat, .stat-card, .quest-card, .streak-card, .mastery-card {
  border-radius: var(--r-card);
}
.sheet { border-radius: var(--r-card) var(--r-card) 0 0; }
/* inner panels and tiles sit one step inside a card */
.dtile, .dest, .stat-cell, .kpi, .panel .panel, .card .card, .land-tile { border-radius: var(--r-inner); }
/* Tailwind radius utilities in the markup collapse onto the two radii, so the
   page cannot show a 6px corner next to a 20px one. */
:root .rounded-3xl, :root .rounded-2xl { border-radius: var(--r-card); }
:root .rounded-xl, :root .rounded-lg, :root .rounded-md { border-radius: var(--r-inner); }
/* pressed / active rows step UP one surface instead of tinting with colour */
.card[role="button"]:active, .card[onclick]:active, .dest:active, .dtile:active, .row:active, .list-row:active { background: var(--raised); }

/* ── 35.3 ICONS — single tone, one weight, one optical size per context ── */
.btn i, .row i, .list-row i, .dest i, .panel-head i, .section-label i, .acct-row i, .tile i, li > i {
  font-size: var(--ico-row); width: 1.25em; text-align: center; line-height: 1;
}
.dtile > i:not(.dtile-lock) { font-size: var(--ico-tile); }
.navtab i, .glass .tb-ico i, .navfab i { font-size: var(--ico-nav); }
/* the dual-tone artefacts: a lime glyph on a white label or a white glyph in a
   lime ring. Key glyphs in tiles are ink like every other glyph; the lime is
   for the ONE primary action per screen. */
.dtile.is-key i, .dtile.is-locked.is-key > i:not(.dtile-lock) { color: var(--txt-1); }
.dtile-lock { color: var(--txt-3) !important; }
/* regular-weight glyphs, wherever the markup still asks for them, render solid */
.fa-regular { font-weight: 900; }

/* ── 35.4 BUTTONS — primary / secondary / ghost, states, touch targets ──── */
.btn { padding: 0 var(--s4); white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
}
.btn-sm { padding: 0 var(--s4); }   /* 44 via --ctl-h-sm (DS8) */
.btn-lg { padding: 0 var(--s5); }
.btn:active { transform: scale(.97); }
/* primary — lime fill, dark ink; hover one step brighter (darker reads disabled) */
/* secondary — hairline, ink, transparent; hover = the raised surface */
/* ghost — text only */
/* disabled — one rule for every variant: opacity, never a colour change */
.btn:disabled, .btn[disabled], .btn[aria-disabled="true"],
.btn-primary:disabled, .btn-primary[disabled] {
  opacity: .45; cursor: not-allowed; transform: none;
}
/* touch floor: compact buttons still hit 48 through the transparent extension (§33) */
.btn-sm::before { inset: -4px 0; }

/* DS14: inputs share the inner radius and surface instead of inheriting the
   old 13px dark-only .input rule. Named pill composers keep their overrides. */
html .input { border-radius: var(--r-inner); background: var(--sunken); color: var(--txt-1); border: 1px solid var(--line-2); min-height: var(--ctl-h); padding: var(--s3) var(--s4); }
html .input:focus { border-color: var(--txt-3); outline: none; outline-offset: 2px; }

/* ── 35.5 TYPE RHYTHM ────────────────────────────────────────────────────── */
.page-title, main > h1, main > .h1, main > header h1, .page-head h1 {
  font-size: var(--t-title); font-weight: 800; letter-spacing: -.02em; line-height: 1.1; color: var(--txt-1);
}
.section-label, .kicker, .panel-kicker {
  font-size: var(--t-kicker); font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--txt-3);
  margin-bottom: var(--label-gap);
}
.card-title, .panel-head h2, .panel-head h3, .card > h3, .panel > h3 {
  font-size: var(--t-card); font-weight: 700; letter-spacing: -.01em; color: var(--txt-1);
}
.figure, .kpi-v, .stat-v, .stat-cell b, .stat-cell strong {
  font-size: var(--t-figure); font-weight: 800; letter-spacing: -.03em; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--txt-1);
}
body, .body, p { font-size: var(--t-body); }

/* ── 35.6 LAYOUT RHYTHM ──────────────────────────────────────────────────── */
main.page-rise { padding-left: var(--gutter); padding-right: var(--gutter); padding-top: var(--s5); }
main.page-rise > * + * { margin-top: var(--card-gap); }
main.page-rise > section + section, main.page-rise > .dest-group + .dest-group, .dest-group + .dest-group { margin-top: var(--section-gap); }
html .card, html .panel { padding: var(--card-pad); }
/* (no blanket child margin — pages own their vertical rhythm; a generic
   `.card > * + *` rule broke every grid child inside a card) */

/* ── 35.7 MOTION — every transition reads one of three durations ─────────── */
.card-hover:hover { transform: translateY(-1px); transition: transform var(--dur-2) var(--ease), border-color var(--dur-2); }
.navtab, .navfab, .seg-btn, .chip, .dest, .dtile, .input, input, textarea, select {
  transition-duration: var(--dur-2); transition-timing-function: var(--ease);
}
#app.boot-reveal .page-rise { animation-duration: var(--dur-3); }

/* ══════════════════════════════════════════════════════════════════════════
   36. DS6 — THE TOP NAVIGATOR (app.js topbar()). Supersedes §31 / §33.6 sizes.
   One composed bar: lockup (mark + kicker + page title) · ink glyphs · ONE
   lime primary · avatar. 56 px row, safe-area aware, both themes.
   ══════════════════════════════════════════════════════════════════════════ */
.glass { background: var(--ground); border-bottom: 1px solid var(--line); box-shadow: none; }
html[data-theme="light"] .glass { background: var(--card); }
.glass .tb-row { height: 56px; gap: var(--s1); padding-left: var(--s4); padding-right: 10px; }
/* identity + context lockup */
.glass .tb-lockup { gap: 9px; min-height: 44px; padding: 0; margin-right: 6px; min-width: 0; flex: 1 1 auto; justify-content: flex-start; text-align: left; border-radius: var(--r-inner); }
.glass .tb-brand .logo-mark { width: 28px; height: 28px; flex: 0 0 28px; }
.glass .tb-ctx { display: flex; flex-direction: column; min-width: 0; line-height: 1.1; }
/* §33.6 keyed `.glass .tb-brand span span` (the old wordmark accent + light
   lime dot); these restate at equal-or-higher specificity so the lockup is one
   quiet kicker line. The accent split stays the SPLASH's job. */
.glass .tb-brand span.tb-kicker { font-size: 10.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--txt-3); line-height: 1.1; }
.glass .tb-brand span.tb-kicker span, html[data-theme="light"] .glass .tb-brand span.tb-kicker span { color: var(--txt-3); font-size: inherit !important; font-weight: inherit !important; letter-spacing: inherit !important; }
html[data-theme="light"] .glass .tb-brand span.tb-kicker span::after, html[data-theme="light"] .glass .tb-brand span span::after { content: none !important; display: none !important; }
.glass .tb-brand span.tb-title, html[data-theme="light"] .glass .tb-brand span.tb-title { font-size: 16px; font-weight: 800; letter-spacing: -.02em; color: var(--txt-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-transform: none; }
.glass .tb-brand span.tb-ctx { font-size: 0; }   /* the wrapper inherits §33.6's 1.25rem; it must not size anything */
/* utilities: ink glyphs, no plate, 44 px targets */
.glass .tb-tools { gap: 0; margin-left: auto; }
.glass .tb-ico { width: 44px; height: 44px; border-radius: var(--r-ctl); color: var(--txt-2); background: transparent; }
.glass .tb-ico i { font-size: var(--ico-nav); }
.glass .tb-ico.active, .glass .tb-ico:hover { color: var(--txt-1); background: transparent; }
.glass .tb-ico .badge-dot { top: 7px; right: 7px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: var(--r-ctl); background: var(--txt-1); color: var(--ground); font-size: 10px; font-weight: 800; display: grid; place-items: center; border: 0; box-shadow: none; }
html[data-theme="light"] .glass .tb-ico .badge-dot { background: var(--txt-1); color: var(--card); }
/* the one lime object */
.glass .tb-cta { min-height: 44px; height: 44px; min-width: 44px; padding: 0 14px; margin: 0 4px; font-size: 13.5px; font-weight: 750; gap: 7px; letter-spacing: -.005em; }
.glass .tb-cta i { font-size: 13px; }
.glass .tb-cta.tb-cta-tight { padding: 0; width: 44px; min-width: 44px; }
.glass .tb-cta.tb-cta-tight .tb-cta-l { display: none; }
.glass .tb-cta.btn-ghost { min-width: 0; }
/* avatar: 34 px round with hairline, inside a 44 px target */
.glass .tb-avatar { width: 44px; height: 44px; margin: 0; padding: 0; }
.glass .tb-avatar img, .glass .tb-avatar > * { width: 34px !important; height: 34px !important; border-radius: var(--r-ctl) !important; border: 1px solid var(--line-2); }
/* desktop nav items: ink, active = ink on the lime tint, one pill radius */
.glass .nav-item:not(.tb-ico) { background: transparent !important; color: var(--txt-2); border-radius: var(--r-ctl); min-height: 40px; }
.glass .nav-item:not(.tb-ico):hover { color: var(--txt-1); }
.glass .nav-item.active:not(.tb-ico) { color: var(--txt-1); background: var(--accent-weak) !important; }
.glass .nav-item i { color: inherit; font-size: 13px; }
@media (max-width: 359px) { .glass .tb-cta .tb-cta-l { display: none; } .glass .tb-cta { padding: 0; width: 44px; min-width: 44px; } }

/* ══════════════════════════════════════════════════════════════════════════
   37. DS6 — PAGE PASSES. One block per page; each only APPLIES §35.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 37.1 DASHBOARD (views4.js VIEWS.dashboard, views5.js dailyWidget) ──── */
#rank-hero { padding: var(--card-pad); }
#rank-hero .hero-figure { font-size: clamp(2.75rem, 13vw, 3.5rem); font-weight: 800; letter-spacing: -.04em; line-height: .9; }
.hero-figure { color: var(--txt-1); }   /* light flips it to --txt-1 via the :is() list above (§33.x) */
#rank-hero .hero-unit { font-size: 1rem; color: var(--txt-3); }
#rank-hero .section-label { margin-bottom: 0; }
#rank-hero .ring-track { stroke: var(--line-2); }
#rank-hero .flex.gap-2\.5.mt-5 { gap: var(--s3); margin-top: var(--s5); }
/* stat row: figures on one type scale, labels are kickers */
.stat-row { gap: var(--card-gap); }
.stat-cell { min-width: 0; text-align: left; padding: var(--s4); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-inner); transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease); }
.stat-cell-v { font-size: 26px; font-weight: 800; letter-spacing: -.03em; line-height: 1; }
.stat-cell-suffix { font-size: 13px; }
.stat-cell-l { font-size: var(--t-kicker); letter-spacing: .09em; color: var(--txt-3); margin-top: var(--s2); }
/* recent rolls: list rows = inner geometry, thumb = one ink glyph */
.rr { margin-top: var(--section-gap); }
.rr-list { display: grid; gap: var(--s2); }
.rr-row { padding: var(--s3) var(--s4); border-radius: var(--r-inner); background: var(--card); border: 1px solid var(--line); transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease); }
.rr-thumb { width: 40px; height: 40px; border-radius: var(--r-inner); background: var(--raised); border: 0; color: var(--txt-2); }
.rr-thumb.is-done { color: var(--txt-1); }
.rr-thumb i { font-size: var(--ico-row); }
.rr-t { font-size: var(--t-card); font-weight: 700; }
.rr-s { font-size: 13px; color: var(--txt-2); }
.rr-all { color: var(--txt-1); font-weight: 700; font-size: 13px; min-height: 44px; display: inline-flex; align-items: center; gap: 6px; }
.rr-all i { color: var(--txt-2); }
html[data-theme="light"] .rr-all { color: var(--txt-1); }
/* daily objectives: one row geometry, done = surface step + good ink, no tinted plate */
.obj-row { display: flex; align-items: center; gap: var(--s3); width: 100%; min-width: 0; box-sizing: border-box; min-height: 60px; padding: var(--s3) var(--s4); text-align: left; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-inner); transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease); }
.obj-row:not(:disabled):hover { border-color: var(--line-2); }
.obj-row:not(:disabled):active { background: var(--raised); }
.obj-row.is-done { background: var(--raised); border-color: var(--line); cursor: default; }
.obj-ico { width: 36px; height: 36px; flex: none; display: grid; place-items: center; border-radius: var(--r-inner); background: var(--raised); color: var(--txt-2); }
.obj-row.is-done .obj-ico { background: var(--good-weak); color: var(--txt-1); }
.obj-ico i { font-size: var(--ico-row); }
.obj-main { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.obj-t { font-size: 14.5px; font-weight: 700; color: var(--txt-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.obj-row.is-done .obj-t { color: var(--txt-1); }
.obj-s { font-size: 12.5px; color: var(--txt-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.obj-xp { flex: none; font-size: 12px; font-weight: 800; color: var(--txt-2); background: var(--raised); border-color: var(--line); min-height: 28px; padding: 0 10px; }
.obj-row.is-done .obj-xp { background: var(--good-weak); border-color: transparent; color: var(--txt-1); }
html[data-theme="light"] .obj-row.is-done .obj-ico, html[data-theme="light"] .obj-row.is-done .obj-xp { background: var(--good-weak); color: var(--txt-1); }
html[data-theme="light"] .obj-row.is-done .obj-t { color: var(--txt-1); }
/* destination groups (Home) — tiles on the inner radius, glyph one size, label one weight */
.dest-group .section-label { margin-bottom: var(--label-gap); }
.dtile { gap: var(--s2); padding: var(--s4) var(--s3); }
.dtile-l { font-size: 13.5px; font-weight: 700; }
/* the ai / progress preview card's Open button is a secondary, not a third style */
.gm-open, .card .btn-ghost.btn-sm { min-height: var(--ctl-h-sm); }

/* ── 37.2 FILM ROOM — list (views2.js VIEWS['rolls-library']) + detail (rlDetail) ── */
.rl-list { gap: var(--s2); }
.rl-card { padding: var(--s3) var(--s4); border-radius: var(--r-inner); background: var(--card); border: 1px solid var(--line); gap: var(--s3); transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease); }
.rl-card:active { transform: scale(.985); background: var(--raised); }
.rl-thumb { width: 40px; height: 40px; border-radius: var(--r-inner); background: var(--raised); border: 0; color: var(--txt-2); }
.rl-thumb i { font-size: var(--ico-row); }
.rl-thumb.is-done { color: var(--txt-1); background: var(--raised); }            /* the lime tinted square was a second accent object per row */
.rl-t { font-size: var(--t-card); }
.rl-s { font-size: 13px; }
.rl-s.is-pending { color: var(--txt-2); }                                          /* pending is a state, not a call to action */
.rl-day { font-size: 12px; min-height: 28px; }
/* empty state + the analysis picker share one geometry: the lime disc is the page's ONE primary object only when there is no button under it */
.rl-empty { padding: var(--s6) var(--card-pad); }
.rl-empty .ra-drop-ico, .ra-drop-ico { width: 52px; height: 52px; font-size: 20px; margin-bottom: var(--s3); background: var(--raised); color: var(--txt-1); }
.rl-empty .ra-drop-t, .ra-drop-t { font-size: 18px; font-weight: 800; letter-spacing: -.02em; }
.rl-empty .ra-drop-s, .ra-drop-s { font-size: 14px; color: var(--txt-2); line-height: 1.45; }
.rl-empty-go { margin-top: var(--s5); }
.ra-drop { border-radius: var(--r-card); padding: var(--s6) var(--card-pad); border-style: solid; }
.ra-drop:focus-within, .ra-drop:hover { border-color: var(--line-2); }
.ra-steps { gap: var(--s2); }
.ra-step { min-height: 44px; border-radius: var(--r-ctl); font-size: 13px; font-weight: 700; color: var(--txt-3); border: 1px solid var(--line); background: transparent; }
.ra-step.is-now { color: var(--txt-1); border-color: var(--line-2); background: var(--raised); }
.ra-step.is-now .ra-step-n { background: var(--accent-fill); color: var(--accent-on); }
.ra-step.is-done .ra-step-n { color: var(--txt-1); border-color: var(--line-2); }
.ra-stage, .scan-stage { border-radius: var(--r-card); }
.rl-detail .card, .rl-detail .panel { border-radius: var(--r-card); }

/* ── 37.3 ME / SETTINGS (views2.js VIEWS.profile, meRows) ───────────────── */
.me-hero { padding: var(--card-pad); }
.me-hero .chip { min-height: 32px; font-size: 12.5px; }
.me-hero .btn-ghost { width: 44px; height: 44px; padding: 0; }
.me-kpis { gap: var(--card-gap); }
.me-kpi { padding: var(--s4); border-radius: var(--r-inner); }
.me-kpi i { font-size: var(--ico-row); color: var(--txt-3); }
.me-kpi .text-2xl { font-size: 26px; font-weight: 800; letter-spacing: -.03em; color: var(--txt-1); }
.me-kpi .section-label { margin-bottom: 0; }
.me-badge { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); }
.me-badge i { color: var(--txt-2); }
.acct-rows { gap: 0; }
.acct-row { min-height: 56px; padding: var(--s3) var(--s4); border-radius: var(--r-inner); }
.acct-row + .acct-row { margin-top: var(--s2); }
.acct-row i { color: var(--txt-2); font-size: var(--ico-row); }
.theme-seg { border-radius: var(--r-ctl); }
.theme-seg button { border-radius: var(--r-ctl); }

/* ── 37.4 PROGRESS (views3.js VIEWS.gamemap) ─────────────────────────────── */
.gm-seg { display: inline-flex; gap: 2px; padding: 3px; }
.gm-seg .seg-btn { min-height: 38px; padding: 0 var(--s3); font-size: 13px; }
.gm-seg .seg-btn.on { border: 0; }
.gm-rank { padding: var(--card-pad); }
.gm-rank .w-16 { width: 56px; height: 56px; border-radius: var(--r-inner) !important; border-width: 1px !important; }
.gm-rank .text-3xl { font-size: 28px; font-weight: 800; letter-spacing: -.03em; }
.gm-rank .text-\[10px\] { font-size: var(--t-kicker); letter-spacing: .09em; }
main .card h2.font-bold, main .card h2 { font-size: var(--t-card); font-weight: 700; letter-spacing: -.01em; }
/* the six-actions chips and the technique rows keep their axis colours (data), the containers take the system geometry */
.gm-drafts { border-radius: var(--r-inner); padding: var(--s4); }
.risk-chip, .gm-axis-chip { border-radius: var(--r-ctl); min-height: 32px; }

/* ── 37.5 LEADERBOARD (views5.js VIEWS.leaderboard) ──────────────────────── */
/* the board picker was a red tile and an orange tile (style.css :891-904) — two
   colours for a binary choice. Now: the selected board is the raised surface
   with a hairline, glyph + label ink, sub-line --txt-2; no colour carries state. */
.board-pick { padding: var(--s3) var(--s4); border-radius: var(--r-inner); background: var(--card); border: 1px solid var(--line); min-height: 64px; }
.board-pick i { font-size: var(--ico-row); color: var(--txt-3); }
.board-pick .bp-label { font-size: 14.5px; font-weight: 700; color: var(--txt-2); }
.board-pick .bp-sub { font-size: 12px; color: var(--txt-3); }
.board-pick.on, .board-pick.on.ranked { background: var(--raised); border-color: var(--line-2); }
.board-pick.on i, .board-pick.on .bp-label, .board-pick.on.ranked i { color: var(--txt-1); }
.board-pick.on .bp-sub, .board-pick.on.ranked .bp-sub { color: var(--txt-2); }
.seg .seg-btn { min-height: 40px; font-size: 12.5px; }
.podium { gap: var(--s2); }
.podium .card, .podium-slot { border-radius: var(--r-inner); }
.rk-row { border-radius: var(--r-inner); min-height: 64px; }

/* ── 37.6 LIBRARY (views4.js VIEWS.library) ──────────────────────────────── */
/* category chips: one chip geometry; the category colour is DATA and stays as
   the glyph ink on the selected chip only — the tinted plate + coloured ring per
   category (7 colours of surface) is gone. */
.lib-cat { min-height: 36px; background: var(--card); color: var(--txt-2); border: 1px solid var(--line); }
.lib-cat.on { background: var(--raised); color: var(--txt-1); border-color: var(--line-2); }
.lib-cat.on i { color: var(--cat, var(--txt-1)); }
.lib-hot, .lib-gap { border-radius: var(--r-inner); background: var(--card); border: 1px solid var(--line); transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease); }
.lib-hot:hover, .lib-gap:hover { border-color: var(--line-2); }
.lib-hot:active, .lib-gap:active { background: var(--raised); }
.lib-gaps { border-color: var(--line); }
.lib-gaps h2 ~ button { min-height: 44px; }
.lib-gap-s { color: var(--txt-2); }
.card h2.text-\[13px\] { font-size: var(--t-card); }
.card h2 + .text-\[10px\], .card h2 ~ .text-\[10px\].ml-auto { font-size: 12px; }
.tech-card { border-radius: var(--r-card); }
.tech-card .chip { min-height: 26px; }
.lib-gaps i, .card .fa-fire.text-xs { color: var(--txt-2); }
#lib-q { padding-left: 2.6rem; }
.lib-sort { display: inline-flex; gap: 2px; padding: 3px; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.lib-sort::-webkit-scrollbar { display: none; }
.lib-sort .seg-btn { min-height: 38px; flex: 0 0 auto; text-transform: none; letter-spacing: -.005em; font-size: 12.5px; padding: 0 12px; overflow: visible; text-overflow: clip; }

/* ── 37.7 COACH (views4.js VIEWS.coach, modeSwitch, coachBubble) ─────────── */
/* the lime tab + the lime coach mark + the lime send button + lime user bubbles
   were FOUR accent objects on one screen. Now: the mark and the active tab are
   surface steps with ink; the send button is the page's ONE primary; the
   athlete's own bubbles are the lime tint (--accent-weak), the coach's are cards. */
.coach-mark { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); border-radius: var(--r-inner); }
.coach-mark i { font-size: var(--ico-nav); }
.mode-switch { background: var(--sunken); border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 3px; gap: 2px; }
.mode-pill { border-radius: var(--r-ctl); min-height: 44px; font-size: 14px; font-weight: 700; color: var(--txt-3); }
.mode-pill.is-active { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); }
.mode-pill i { font-size: var(--ico-row); }
.mode-pill .mode-lock { color: var(--txt-3); }
.ac-mine { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line); }   /* 15 Oct: neutral, as on the Coach page (lime is for the ONE main button and data marks) */
html[data-theme="light"] .ac-mine { background: var(--raised); color: var(--txt-1); }
#chat-log .card { border-radius: var(--r-card); }
#chat-log .card.max-w-\[88\%\], #chat-log .ac-mine { border-radius: var(--r-card); }
.ac-suggest { border-radius: var(--r-inner); min-height: 48px; font-size: 13.5px; color: var(--txt-1); }
.ac-suggest:hover { border-color: var(--line-2); background: var(--raised); }
.chat-dock .input { min-height: var(--ctl-h); border-radius: var(--r-ctl); }
.chat-dock .btn-primary { min-width: var(--ctl-h); min-height: var(--ctl-h); width: var(--ctl-h); padding: 0; }
.chat-dock .btn-primary i { font-size: var(--ico-row); }
#round-bar > .flex.min-w-0 { flex: 1 1 auto; min-width: 0; overflow: hidden; }
#round-bar .flex.gap-1 { flex-wrap: nowrap; overflow: hidden; }
#round-bar .tabular-nums { flex: none; padding-left: 6px; }
.rnd-pip { flex: none; }

/* DS18 Coach: transcript and composer first; utilities remain explicit. */
#coach-ds18 { max-width: 680px; margin-inline: auto; color: var(--txt-1); }
#coach-ds18 .coach-header { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
#coach-ds18 .coach-header h1 { margin: 0; font-size: clamp(32px, 5vw, 40px); font-weight: 800; line-height: 1.1; letter-spacing: -.04em; }
#coach-ds18 .coach-header p { margin: 8px 0 0; font-size: 14px; line-height: 1.5; color: var(--txt-2); }
#coach-ds18 .coach-context { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
#coach-ds18 .mode-switch { flex: 1; min-width: 210px; max-width: 340px; margin: 0; border: 0; border-radius: 12px; }
#coach-ds18 .mode-pill { min-height: 44px; padding: 8px 10px; border-radius: 9px; font-size: 13px; font-weight: 600; color: var(--txt-2); }
#coach-ds18 .mode-pill.is-active { color: var(--txt-1); background: var(--card); border-color: transparent; box-shadow: var(--lift-1); }
#coach-ds18 .coach-library { min-height: 44px; padding: 8px; margin-left: auto; font-size: 14px; font-weight: 600; color: var(--txt-1); }
#coach-ds18 #round-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0 16px; padding-bottom: 8px; border-bottom: 1px solid var(--line); }
#coach-ds18 #rnd-meter { flex: 1 0 100%; font-size: 12px; line-height: 20px; color: var(--txt-2); }
#coach-ds18 #round-bar button { min-height: 44px; font-size: 13px; font-weight: 500; color: var(--txt-1); }
#coach-ds18 #past-count { color: var(--txt-2); font-variant-numeric: tabular-nums; }
#coach-ds18 #chat-log { max-height: clamp(180px, 38vh, 460px); max-height: clamp(180px, 38dvh, 460px); overflow-y: auto; padding: 24px 0 12px; overflow-wrap: anywhere; }
#coach-ds18 #chat-log .card { background: transparent; border: 0; box-shadow: none; padding-left: 0; padding-right: 0; border-radius: 0; }
#coach-ds18 #chat-log .ac-mine { background: var(--raised); border: 1px solid var(--line); }
#coach-ds18 #chat-empty { margin: 12px 0 0; color: var(--txt-2); font-size: 14px; line-height: 1.5; }
#coach-ds18 .coach-compose { margin-top: 12px; }
#coach-ds18 .coach-prompts { display: flex; flex-wrap: wrap; gap: 0 16px; margin-bottom: 8px; }
#coach-ds18 .coach-prompts button { min-height: 44px; text-align: left; font-size: 13px; line-height: 1.4; color: var(--txt-2); }
#coach-ds18 #chat-form { display: flex; gap: 8px; padding: 8px 0; border: 0; }
#coach-ds18 #chat-form .input { min-width: 0; flex: 1; min-height: 56px; font-size: 16px; border-radius: 18px; background: var(--card); }
#coach-ds18 #chat-form .btn-primary { flex: 0 0 56px; width: 56px; height: 56px; }
#coach-ds18 :is(.coach-library, .coach-prompts button, #round-bar button):hover { text-decoration: underline; }
#coach-ds18 .coach-quiet { margin: 12px 0 0; color: var(--txt-2); }

/* ── 37.8 REGISTER / LOGIN (views.js VIEWS.login / VIEWS.register, authStage) ── */
/* Both doors are one card on the system geometry: 20 radius, --card-pad, one
   type rhythm (title 20/800, sub 14 --txt-2), inputs 48 on the inner radius,
   consent rows 56 on the inner radius, Google button = secondary height. The
   mat grid / auth-mark / belt-sweep markup stays (test:design asserts it); the
   orbs are already display:none (§17.5). */
.auth-stage { padding: var(--card-pad); border-radius: var(--r-card); }
.auth-head { gap: var(--s4); padding-bottom: var(--s4); margin-bottom: var(--s4); border-bottom-color: var(--line); }
.auth-head .auth-mark { font-size: 1.5rem; letter-spacing: -.03em; }
.auth-head h1 { font-size: 20px; font-weight: 800; letter-spacing: -.02em; }
.auth-head p { font-size: 14px; color: var(--txt-2); margin-top: 2px; }
.auth-stage .input, .auth-stage input.input { min-height: var(--ctl-h); border-radius: var(--r-inner); font-size: 15px; }
/* 2026-09-08 (Reqwa, iPhone): iOS Safari zooms the page when a focused input is
   under 16px. style.css sets .input to 16px on phones, but this 15px rule is more
   specific and won, so the LOGIN form — the first thing anyone types into — still
   zoomed. The QA probe never measured it: it runs signed in, and /login redirects. */
@media (max-width: 767px) { .auth-stage .input, .auth-stage input.input, .comp-new .input, .ob-field .input { font-size: 16px; } }
.auth-stage .btn-google { min-height: var(--ctl-h); border-radius: var(--r-ctl); }
.auth-stage .or-split { margin: var(--s4) 0; font-size: 11px; letter-spacing: .09em; }
.auth-stage .field-help, .auth-stage .text-\[11px\] { font-size: 12.5px; color: var(--txt-3); }
.consent-row { min-height: 56px; padding: var(--s3) var(--s4); border-radius: var(--r-inner); background: var(--card); align-items: center; }
.consent-row:has(.consent-box:checked) { background: var(--raised); border-color: var(--line-2); }
.consent-box { width: 22px; height: 22px; border-radius: 7px; margin-top: 0; }
.consent-row .consent-text, .consent-row label, .consent-row span { font-size: 14px; }
.auth-alert { border-radius: var(--r-inner); }
.auth-stage .auth-alt, .auth-stage .text-center { font-size: 14px; }
.auth-stage .auth-alt b, .auth-stage a { color: var(--txt-1); }
html[data-theme="light"] .auth-head .auth-mark .text-op-400 { color: var(--txt-1); }

/* ── 37.9 ONBOARDING (views.js VIEWS.onboarding; §7 / §20) ───────────────── */
/* selection keeps its three channels (surface, border, filled radio) but the
   tinted lime plate goes: selected = raised surface + hairline, the lime lives
   only in the radio dot — one accent object per option, not a lime card. */
.ob-opt { border-radius: var(--r-inner); padding: var(--s4); min-height: 56px; gap: var(--s3); font-size: 15px; font-weight: 600; transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease); }
.ob-opt.on { background: var(--raised); border-color: var(--line-2); }
.ob-opt.on .ob-ico { color: var(--txt-1); }
.ob-ico { font-size: var(--ico-row); }
.ob-belt { border-radius: 6px; }
.ob-q { font-size: 22px; font-weight: 800; letter-spacing: -.02em; line-height: 1.15; }
.ob-step { font-size: var(--t-kicker); letter-spacing: .09em; text-transform: uppercase; }
.ob-bar { height: 3px; border-radius: 2px; background: var(--line); }
.ob-bar > span { border-radius: 2px; background: var(--accent-fill); transition: width var(--dur-3) var(--ease); }
.ob-back { width: 44px; height: 44px; border-radius: var(--r-ctl); color: var(--txt-2); border: 1px solid var(--line-2); }
.ob-drop-ico { width: 52px; height: 52px; border-radius: var(--r-ctl); background: var(--raised); color: var(--txt-1); font-size: 20px; }
.path-opt { border-radius: var(--r-card); padding: var(--card-pad); }
.path-opt.on, .path-opt[aria-pressed="true"] { background: var(--raised); border-color: var(--line-2); }
.ob-opts { gap: var(--s2); margin-top: var(--s5); }

/* ── 37.10 BILLING / PLANS (views11.js VIEWS.plans; §22 / §22b) ──────────── */
/* the hero tier carried a lime border + lime flag + lime ticks + lime CTA. One
   lime object per card: the CTA. The flag is ink-on-raised, ticks are --txt-2
   (DS4 item 7 rule), the hero border is the hairline-2 like every featured card. */
.plan-card.tier { border-radius: var(--r-card); padding: var(--card-pad); }
.plan-card.tier.is-hero { border-color: var(--line-2); }
.tier-flag { position: absolute; top: -.7rem; left: 1.1rem; display: inline-flex; align-items: center; gap: .4rem; padding: .28rem .7rem; white-space: nowrap; background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); min-height: 28px; border-radius: var(--r-ctl); font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.tier-flag i { color: var(--txt-2); font-size: 11px; }
.tier-flag.is-intro { color: var(--txt-1); border-color: var(--line-2); }
.tier-name { font-size: 20px; font-weight: 800; letter-spacing: -.02em; }
.tier-price .pp-amt { font-size: var(--t-figure); font-weight: 800; letter-spacing: -.035em; }
.tier-price .pp-per { font-size: 14px; }
.plan-feats.tier-feats li { font-size: 15px; color: var(--txt-1); }
.plan-feats.tier-feats li i { color: var(--txt-2); font-size: 12px; }
.plan-cta.tier-cta { min-height: var(--ctl-h); border-radius: var(--r-ctl); font-size: 15px; }
.plan-cta.is-current { background: var(--good-weak); color: var(--txt-1); }
.plan-card .panel, .plan-card .card { border-radius: var(--r-inner); }
.plan-card .panel .section-label i, .plan-card .panel h3 i { color: var(--txt-2); }
.tier-seg, .plans-seg { border-radius: var(--r-ctl); }
.tier-seg .seg-btn, .plans-seg .seg-btn { min-height: 44px; }
.plan-card .panel .section-label, .plan-card .panel .text-op-400, .plan-card .panel .text-op-450 { color: var(--txt-2); }

/* ── 37.11 LANDING (views.js VIEWS.home; §19) — rhythm + geometry only ──── */
/* MARKETING-WAVE2 §4 holds: no section removed, no copy changed, one h1, the
   two-phone perspective is the ONE 3D moment (untouched). This pass sets the
   spacing scale, puts tiles/lists on the system radii and takes the lime off
   every decorative glyph so the hero CTA is the page's one lime object above
   the fold; section kickers are ink like everywhere else in the app. */
.land-hero { padding-top: var(--s6); }
.land-h1 { font-weight: 800; letter-spacing: -.03em; line-height: 1.02; }
.land-sub { font-size: 17px; line-height: 1.5; color: var(--txt-2); margin-top: var(--s4); }
.land-cta { margin-top: var(--s5); gap: var(--s3); }
.land-eyebrow { min-height: 32px; border-radius: var(--r-ctl); background: var(--raised); border: 1px solid var(--line); color: var(--txt-2); }
.land-eyebrow i { color: var(--txt-2); }
.land-fine { font-size: 13px; }
.land-sec { padding-top: var(--s8); }
.land-sec-head .section-label { color: var(--txt-3); margin-bottom: var(--s3); }
.land-h2 { font-weight: 800; letter-spacing: -.025em; line-height: 1.1; text-wrap: balance; max-width: 24ch; }
.land-p { font-size: var(--t-body); margin-top: var(--s4); }
.land-tiles, .land-grid { gap: var(--card-gap); }
.land-tile { border-radius: var(--r-card); padding: var(--card-pad); }
.land-tile > i { display: grid; place-items: center; width: 44px; height: 44px; border-radius: var(--r-inner); background: var(--raised); color: var(--txt-1); font-size: var(--ico-tile); border: 1px solid var(--line); }
.land-tile h3 { margin-top: var(--s4); font-size: 17px; }
.land-tile p { margin-top: var(--s2); font-size: 14.5px; line-height: 1.6; text-wrap: pretty; }
.land-tile .tnum, .land-tile b { color: var(--txt-1); }
.land-list { gap: var(--s3); margin-top: var(--s5); }
.land-list li { font-size: var(--t-body); color: var(--txt-1); align-items: flex-start; }
.land-list li i { color: var(--txt-2); font-size: 13px; margin-top: 4px; }
.land-chat { border-radius: var(--r-card); padding: var(--card-pad); gap: var(--s2); }
.land-chat-row span { border-radius: var(--r-inner); font-size: 13.5px; min-height: 36px; }
/* DS7 (Reqwa, landing dark): the "you" bubble keeps §19's lime fill + --accent-on —
   --accent-weak is an 11% tint for selected rows ON a card surface and reads
   as khaki over the landing ground. Below the fold, so the hero CTA is still the
   one lime object above it. */
.land-chat-you span { background: var(--accent-fill); color: var(--accent-on); }
.land-shot { border-radius: var(--r-card); }
.land-shots-note { margin-top: var(--s5); font-size: 13px; }
.land-price, .price-card { border-radius: var(--r-card); }
@media (min-width: 640px) { .land-sec { padding-top: var(--s8); } }

/* ── 37.12 STAFF DASHBOARD (views6.js VIEWS.academy) + GYM PROFILE (views7.js VIEWS.gym) ── */
/* status chips are ONE chip geometry with ink; role/plan are facts, not accents
   (the owner chip was flame, the plan chip lime, the open chip emerald — three
   colours on one line). "Accepting members" keeps the good ink: it is a state. */
.role-chip, .plan-chip { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); }
.role-chip i, .plan-chip i { color: var(--txt-2); }
.chip.is-open { background: var(--good-weak); color: var(--txt-1); border-color: transparent; }
.kpi-strip { gap: var(--s2); }
.kpi-strip .panel { padding: var(--s3) var(--s3); border-radius: var(--r-inner); }
.kpi-strip .panel i { color: var(--txt-3); font-size: var(--ico-row); }
.kpi-v { font-size: 24px; font-weight: 800; letter-spacing: -.03em; line-height: 1; margin-top: var(--s2); }
.kpi-strip .section-label, .kpi-l { font-size: 10.5px; letter-spacing: .08em; margin-top: var(--s1); margin-bottom: 0; }
.rollcall-cta { border-radius: var(--r-card); padding: var(--s4); min-height: 72px; background: var(--card); border: 1px solid var(--line); }
.rollcall-cta .rc-ico { width: 44px; height: 44px; border-radius: var(--r-inner); background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); }
.rollcall-cta .rc-ico i { font-size: var(--ico-row); }
.rollcall-cta .font-black { font-size: var(--t-card); font-weight: 700; }
.staff-tabs .seg-btn, .acad-tabs .seg-btn { min-height: 44px; }
.staff-dock-k.is-live b { color: var(--txt-1); }
/* gym profile hero */
.gym-mark, .gym-avatar { border-radius: var(--r-inner); background: var(--raised); border: 1px solid var(--line-2); color: var(--txt-1); }
.gym-hero .btn-ghost { width: var(--ctl-h); height: var(--ctl-h); padding: 0; }
/* DS7: the cover band was removed from views7.js (it overprinted the name after
   staff login — Reqwa 20:52 UTC). DS8: `.gym-cover` / `.gym-hero-cover` had no render
   site left anywhere (grep), rules deleted; the mark is a plain raised tile in one row with the name. */
.gym-mark { background: var(--raised); border: 1px solid var(--line-2); border-radius: var(--r-inner); color: var(--txt-1); box-shadow: none; }
.gym-mark i { font-size: 20px; color: var(--txt-1); }
.gym-hero { min-height: 56px; }
.gym-city { color: var(--txt-3); }
.gym-city i { color: var(--txt-3); }

/* ── 37.13 FILM ROOM DETAIL (views2.js rlDetail) — CSS pass on the existing
   hooks. Screen-verified 2026-09-07 (DS7, fixture in HANDOFF §4); the fixes the
   blind pass missed are in §37.15 below. ── */
.rl-detail-head { gap: var(--s3); }
.rl-back { width: 44px; height: 44px; border-radius: var(--r-ctl); color: var(--txt-2); border: 1px solid var(--line-2); display: grid; place-items: center; margin: 0; }
.rl-title { font-size: 20px; font-weight: 800; letter-spacing: -.02em; }
.rl-stage { border-radius: var(--r-card); overflow: hidden; border: 1px solid var(--line); }
.rl-read, .rl-summary, .rl-sec, .rl-chat { border-radius: var(--r-card); padding: var(--card-pad); }
.rl-score { font-size: var(--t-figure); font-weight: 800; letter-spacing: -.035em; line-height: 1; color: var(--txt-1); }
.rl-score small { font-size: var(--t-kicker); letter-spacing: .09em; }
.rl-sec-k { color: var(--txt-3); font-size: var(--t-kicker); letter-spacing: .09em; }
.rl-sec-k i { color: var(--txt-2); font-size: 12px; }
.rl-sec-t { font-size: var(--t-card); font-weight: 700; }
.rl-bub { border-radius: var(--r-inner); font-size: var(--t-body); }
.rl-bub.is-you { background: var(--accent-weak); color: var(--txt-1); border-color: transparent; }
.rl-compose { gap: var(--s2); margin-top: var(--s4); }
.rl-compose .input { min-height: var(--ctl-h); border-radius: var(--r-ctl); }
.rl-compose .btn-primary { width: var(--ctl-h); min-width: var(--ctl-h); min-height: var(--ctl-h); padding: 0; }
.rl-nofootage, .rl-chat-empty { border-radius: var(--r-inner); color: var(--txt-2); font-size: 14px; }

/* ── 37.14 TAP TARGETS (QA finding 18:01 UTC): every .seg-btn ≥ 44 px, the
   Me "Log out" ghost 44, legacy 28 px pills that are buttons hit 44 via a
   transparent extension (drawing unchanged). ── */
.seg-btn, .gm-seg .seg-btn, .lib-sort .seg-btn, .seg .seg-btn, .tier-seg .seg-btn, .plans-seg .seg-btn { min-height: 44px; }
.me-hero .btn-ghost, .btn-ghost.\!py-2 { min-width: 44px; }
button.chip { position: relative; }
button.chip::before { content: ''; position: absolute; inset: -8px 0; }

/* ── 37.15 FILM ROOM DETAIL — what the screen showed (DS7, 2026-09-07). Fixture:
   demo_op roll 12 with axis_scores + phases + coverage_ok 0 (HANDOFF §4). Rules:
   §35 radii {20, 14, pill}, one glyph weight, lime only on the top axis bar
   (DS5 §34 keeps it — data, not chrome) and the share/send primaries. ── */
.rl-detail .rl-title { font-size: 22px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; margin-top: var(--s1); }
.rl-detail-head .section-label { color: var(--txt-3); }
/* timestamp chips: 6 px → inner radius, quiet ink, tabular */
.rl-detail .ra-demo-ts { border-radius: var(--r-inner); background: var(--raised); border-color: var(--line); color: var(--txt-3); padding: .22rem .5rem; }
/* phases + moments: rows on the 56 px rhythm, hairline dividers, one ink pair */
.rl-phases { margin-top: var(--s2); }
.rl-phase { padding: var(--s3) 0; min-height: 56px; }
.rl-phase-h { gap: var(--s2); flex-wrap: wrap; }
.rl-phase-t { font-size: var(--t-card); font-weight: 700; color: var(--txt-1); }
.rl-phase-p { color: var(--txt-2); font-size: var(--t-body); line-height: 1.5; margin-top: var(--s1); }
.rl-phases + .rl-moments { margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid var(--line); }
.rl-moment.ra-demo-row { padding: var(--s3) 0; min-height: 56px; gap: var(--s3); border-color: var(--line); }
.rl-moment-t { color: var(--txt-2); font-size: var(--t-body); }
.rl-moment-who { color: var(--txt-3); }
/* sections (root cause / drill / cue): inner panels, not nested cards */
.rl-read .rl-sec { border-radius: var(--r-inner); background: var(--raised); border: 1px solid var(--line); padding: var(--s4); margin-top: var(--s3); }
.rl-sec + .rl-sec { margin-top: var(--s3); }
.rl-sec-t { font-size: var(--t-card); font-weight: 700; line-height: 1.4; color: var(--txt-1); margin-top: var(--s2); }
/* cleared-footage notice: dashed → one hairline on the inner radius, ink not muted */
.rl-nofootage { border: 1px solid var(--line); border-radius: var(--r-inner); background: var(--raised); color: var(--txt-2); padding: var(--s4); margin: var(--s3) 0; }
.rl-nofootage i { color: var(--txt-2); font-size: var(--ico-row); }
/* scorecard: kicker/figure rhythm from §35, axis labels one weight */
.rl-scorecard .rl-sc-num { font-size: var(--t-figure); font-weight: 800; letter-spacing: -.035em; color: var(--txt-1); }
.rl-sc-sub { color: var(--txt-2); font-size: var(--t-body); }
.rl-sc-axes-h { color: var(--txt-3); font-size: var(--t-kicker); letter-spacing: .09em; text-transform: uppercase; }
.rl-sc-axis { min-height: 32px; }
.rl-sc-axis-l { font-size: 12px; font-weight: 700; letter-spacing: .06em; }
.rl-sc-coverage { color: var(--txt-2); font-size: 14px; display: flex; gap: var(--s2); align-items: flex-start; }
.rl-sc-coverage i { color: var(--txt-3); font-size: var(--ico-row); margin-top: 3px; }
/* chat: meter chip neutral, both bubbles on the inner radius, composer row 48 */
.rl-chat .comp-turns { background: var(--raised); border: 1px solid var(--line-2); color: var(--txt-1); border-radius: var(--r-ctl); }
.rl-bub { background: var(--raised); border: 1px solid var(--line); padding: var(--s3) var(--s4); }
.rl-bub.is-you { background: var(--accent-weak); border-color: transparent; }
.rl-chat-done { color: var(--txt-2); font-size: 14px; }

/* ── 37.16 LEGACY TAP TARGETS (QA probe on cp9-final, 8 cells; Tech Lead 19:16 /
   19:35 UTC). Rule: ≥ 44 px on the MEASURED box, not a transparent extension.
   Sites: views4.js Log out + "Details, stats & drills" + intensity range,
   views3.js Meta Lab belt/category pills (→ shared .seg), views.js /checkin
   rounds + intensity ranges. `.rng` is the one range-input geometry: a 44 px
   box with an 8 px track and a 28 px thumb (same drawing as DS5 .rc-scrub). ── */
.home-logout { min-height: 44px; padding: 0 var(--s3); font-size: 13px; font-weight: 600; color: var(--txt-3); }
.home-logout:hover { color: var(--txt-2); }
.home-logout i { font-size: 12px; }
.lib-more { min-height: 44px; width: 100%; justify-content: flex-start; padding: 0 var(--s2); margin-top: var(--s2); font-size: 12px; font-weight: 700; color: var(--txt-3); }
.tech-card .btn.lib-more { width: 100%; justify-content: flex-start; padding: 0 var(--s2); margin-top: var(--s2); }
.lib-more:hover { color: var(--txt-2); }
.lib-more i { font-size: 10px; margin-left: var(--s1); }
.meta-seg { max-width: 100%; }
.meta-seg .seg-btn { min-height: 44px; flex: 0 0 auto; }
.meta-seg .seg-btn.on { border: 0; }
.rng { height: 44px; margin: 0; background: transparent; -webkit-appearance: none; appearance: none; cursor: pointer; }
.rng::-webkit-slider-runnable-track { height: 8px; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line-2); }
.rng::-moz-range-track { height: 8px; border-radius: 999px; background: var(--sunken); border: 1px solid var(--line-2); }
.rng::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 28px; height: 28px; margin-top: -11px; border-radius: 50%; background: #FFFFFF; border: 2px solid var(--ground); box-shadow: var(--lift-1); }
.rng::-moz-range-thumb { width: 28px; height: 28px; border-radius: 50%; background: #FFFFFF; border: 2px solid var(--ground); box-shadow: var(--lift-1); }
.rng:focus-visible { outline: 2px solid var(--line-2); outline-offset: 2px; border-radius: 999px; }

/* ══════════════════════════════════════════════════════════════════════════
   36b. DS7 — THE COMPACT TOP BAR (Reqwa live test 19:59 UTC, approved by Tech
   Lead). Restates §36 at higher specificity; §36 stays as the base. 48 px row;
   ONE line of context (the page title, 15/700 — the "OP BJJ" kicker stays in the
   DOM for the splash-parity check but is not drawn: the mark already says it);
   the lime CTA is icon-only on inner pages (label on Home only, app.js
   `onHome`); glyphs and avatar drawn at 40 inside 44 px targets (QA tap rule
   wins over the 40 px drawing). Desktop nav-items row untouched.
   ══════════════════════════════════════════════════════════════════════════ */
header.glass .tb-row { height: 48px; gap: 0; padding-left: var(--s4); padding-right: 8px; }
header.glass .tb-lockup { gap: 10px; min-height: 44px; margin-right: 4px; }
header.glass .tb-brand .logo-mark { width: 26px; height: 26px; flex: 0 0 26px; }
header.glass .tb-ctx { flex-direction: row; align-items: center; }
header.glass .tb-brand span.tb-kicker { display: none; }
header.glass .tb-brand span.tb-title, html[data-theme="light"] header.glass .tb-brand span.tb-title { font-size: 15px; font-weight: 700; letter-spacing: -.01em; line-height: 1; }
/* logged-out front door: no title → the mark alone is the lockup */
header.glass .tb-ico { width: 44px; height: 44px; }
header.glass .tb-ico i { font-size: 17px; }
header.glass .tb-cta { height: 44px; min-height: 44px; min-width: 44px; padding: 0 14px; margin: 0 2px; font-size: 13px; }
header.glass .tb-cta i { font-size: 14px; }
header.glass .tb-cta.tb-cta-tight { width: 44px; min-width: 44px; padding: 0; }
header.glass .tb-cta.btn-ghost { padding: 0 12px; }
header.glass .tb-cta.btn-primary:not(.tb-cta-tight) { padding: 0 14px; }
header.glass .tb-avatar { width: 44px; height: 44px; }
header.glass .tb-avatar img, header.glass .tb-avatar > * { width: 36px !important; height: 36px !important; }
@media (min-width: 768px) { header.glass .tb-row { height: 56px; } header.glass .tb-brand span.tb-kicker { display: none; } }

/* ── 37.17 CHECK-IN FORM (views.js VIEWS.checkin) — first pass, DS7. Class-type
   tiles on the inner radius; selected = raised surface + hairline-2 + ink (the
   lime `Check in now` primary is the page's one lime object). Ranges are §37.16
   `.rng`. ── */
.ci-type { border-radius: var(--r-inner); min-height: 48px; display: flex; align-items: center; justify-content: center; gap: var(--s2); color: var(--txt-2); transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.ci-type i { font-size: var(--ico-row); color: var(--txt-3); margin: 0; }
.peer:checked ~ .ci-type { background: var(--raised); border-color: var(--line-2); color: var(--txt-1); }
.peer:checked ~ .ci-type i { color: var(--txt-1); }

/* ── 37.18 ANALYSIS STEPS 2–4 (views2.js trim / spotlight / queue; §21 base
   :2340-2420). Screen-verified DS7 with a staged trimmer (no upload —
   DS7-scratch/shoot-analysis-steps.mjs). Applies §35 only: radii {20, 14,
   pill}, ink states, danger via the token, 44 px targets. ── */
.ra .ra-stage { border-radius: var(--r-card); }
.ra .ra-swap { min-height: 40px; padding: 0 14px; background: var(--raised); border-color: var(--line-2); font-size: 13px; }
html[data-theme="dark"] .ra .ra-swap { background: rgba(10,10,12,.82); }
.ra .ra-trim-l { font-size: var(--t-card); font-weight: 700; }
.ra .ra-trim-sel { color: var(--txt-1); font-weight: 700; }
.ra .ra-filmstrip { border-radius: var(--r-inner) var(--r-inner) 0 0; }
.ra .ra-range { border-radius: 0 0 var(--r-inner) var(--r-inner); }
.ra .ra-window { border-radius: 6px; background: var(--accent-weak); border: 1px solid var(--accent-fill); }
.ra .ra-range input::-webkit-slider-thumb { border-radius: var(--r-ctl); width: 14px; }
.ra .ra-range input::-moz-range-thumb { border-radius: var(--r-ctl); width: 14px; }
.ra .ra-mark { min-height: 44px; padding: 0 var(--s4); border-radius: var(--r-ctl); background: var(--card); border: 1px solid var(--line); font-size: 13px; font-weight: 700; }
.ra .ra-mark:active { background: var(--raised); border-color: var(--line-2); }
.ra .ra-dur { font-size: 13px; margin-top: 0; }
.ra .ra-dur.is-ok { color: var(--txt-1); }
.ra .ra-dur.is-err, html[data-theme="light"] .ra .ra-dur.is-err { color: var(--danger-ink); }
/* step 3: name + queue */
.ra .ra-field-l { font-size: var(--t-kicker); letter-spacing: .09em; text-transform: uppercase; color: var(--txt-3); font-weight: 700; }
.ra .ra-title { height: var(--ctl-h); border-radius: var(--r-inner); font-size: 15px; }
.ra .ra-go { min-height: var(--ctl-h-lg); padding: 0 var(--s5); font-size: 16px; border-radius: var(--r-ctl); }
.ra .ra-status { border-radius: var(--r-inner); padding: var(--s4); font-size: 14px; }
.ra .ra-status.is-queued, .ra .ra-status.is-done { border-color: var(--line-2); color: var(--txt-1); }
.ra .ra-status.is-err, .ra .ra-status.is-failed, .ra .ra-status.is-running { border-color: var(--line-2); }
.ra .ra-status.is-err, .ra .ra-status.is-failed { color: var(--danger-ink); }
/* spotlight: chips one geometry, selected = raised + hairline-2 + ink dot; the
   Start button is the page's one lime object */
.ra .sl-h { font-size: 22px; letter-spacing: -.02em; }
.ra .sl-sub { font-size: var(--t-body); }
.ra .sl-label { font-size: var(--t-kicker); letter-spacing: .09em; text-transform: uppercase; color: var(--txt-3); }
.ra .sl-group.is-set .sl-label { color: var(--txt-2); }
.ra .sl-chip { min-height: 44px; padding: 0 var(--s4); border-radius: var(--r-ctl); font-size: 14px; }
.ra .sl-chip.on { background: var(--raised); border-color: var(--line-2); color: var(--txt-1); }
.ra .sl-chip.on::before { background: var(--txt-1); }
.ra .sl-chip .ob-belt { border-radius: 4px; }
.ra .sl-err, .ra .sl-err-all { color: var(--danger-ink); }
.ra .sl-group.is-open .sl-chip { border-color: var(--danger-ink); }

/* ── 37.19 ME — BILLING CARD (views2.js billingCard/billingAfter, §22b). Already
   on §35 geometry; this pass moves the danger row and the state row onto tokens
   and the §35 type rhythm (fixture: DS7-scratch/fixture-billing.sh). ── */
.billing .billing-state { border-radius: var(--r-inner); background: var(--raised); min-height: 56px; }
.billing .billing-state > span { font-size: var(--t-card); font-weight: 700; }
.billing .billing-renews { color: var(--txt-2); }
.billing .billing-route { color: var(--txt-3); }
.billing .billing-pastdue { color: var(--danger-ink); }
.billing .acct-row { border-radius: var(--r-inner); min-height: 56px; }
.billing .acct-row.is-danger, .billing .acct-row.is-danger i, html[data-theme="light"] .billing .acct-row.is-danger { color: var(--danger-ink); border-color: var(--line); }
.billing .acct-row.is-danger:hover { border-color: var(--line-2); }
.billing .billing-resume i { color: var(--txt-1); }

/* ── 37.20 STAFF — RETENTION TAB (views6.js retentionTab). Band colours
   (BAND[]) are DATA — risk severity — and stay on the figure, the label and
   the bar fill; everything else is chrome on §35: card --r-card, insight panel
   --r-inner on --raised, bar track --sunken, ink meta, 44 px buttons. ── */
.ret-card { border-radius: var(--r-card); }
.ret-handle { color: var(--txt-3); }
.ret-meta { color: var(--txt-3); }
.ret-bar { height: 6px; border-radius: var(--r-ctl); background: var(--sunken); overflow: hidden; border: 1px solid var(--line); }
.ret-bar > div { height: 100%; border-radius: var(--r-ctl); }
.ret-insight { padding: var(--s3) var(--s4); border-radius: var(--r-inner); background: var(--raised); border: 1px solid var(--line); font-size: 14px; color: var(--txt-2); }
.ret-go { width: 44px; min-width: 44px; padding: 0; }
.ret-out { border-top: 1px solid var(--line); }
.ret-count { background: var(--raised); border: 1px solid var(--line-2); color: var(--txt-1); }
.ret-intro { color: var(--txt-2); line-height: 1.5; }
.ret-intro b { color: var(--txt-1); font-weight: 700; }

/* ── 37.21 HELPER LINES (Reqwa 20:52 UTC: "these gray texts have a pattern").
   Every small quiet line that sits directly under a primary/large button gets
   one consistent --s3 (12 px) top gap; no helper line uses order:-1 or a
   negative margin any more (.tier-tag, .ra-dur, .ra-fine-c fixed in place).
   `.br-staff-note` is Designer's ds5.css rule — restated here at higher
   specificity for the gap only; her sheet is untouched (HANDOFF §2). ── */
.btn + .ra-fine, .btn + .tier-fine, .btn + .land-plan-tag, .btn + .sl-help, .btn + .ob-fine, .btn + .rl-chat-done,
.btn + p.text-\[11px\], .btn + p.text-xs, .ds5-card .btn + .br-staff-note, .ds5-card .br-staff-note { margin-top: var(--s3); margin-bottom: 0; }
.tier-fine, .land-plan-tag, .sl-help, .ob-fine, .ra-fine { color: var(--txt-3); }

/* ── 37.22 HOME — FEATURE TILES ABOVE THE FOLD + DESCRIPTORS + ONE GLYPH INK
   (Reqwa 20:52 UTC items 3 + 4; views4.js `destinations`). Tiles keep 3-up at
   390 (4-up ≥ 480 from style.css), the icon is no longer the only signal: a
   one-line descriptor sits under the label. Glyphs: ONE token for every tile
   glyph (--txt-2, key tiles --txt-1), quiet groups --txt-3, one size; the
   heavy/light FA outliers were swapped in views4.js (people-arrows → user-group). ── */
.dtile { align-items: flex-start; text-align: left; justify-content: flex-start; gap: var(--s1); padding: var(--s3) var(--s3) var(--s3); min-height: 104px; }
.dtile > i:not(.dtile-lock) { font-size: var(--ico-tile); width: auto; margin-bottom: var(--s1); color: var(--txt-2); }
.dtile.is-key > i:not(.dtile-lock), .dtile.is-locked.is-key > i:not(.dtile-lock) { color: var(--txt-1); }
.dtile.is-locked > i:not(.dtile-lock) { color: var(--txt-3); }
.dtile-l { font-size: 13px; font-weight: 700; line-height: 1.2; color: var(--txt-1); text-align: left; text-wrap: balance; }   /* style.css:556 centred it — visible only on a two-line label */
.dtile-d { font-size: 11px; line-height: 1.3; color: var(--txt-3); font-weight: 500; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.dtile-lock { top: var(--s2); right: var(--s2); }
.dest-group-quiet .dtile { background: var(--card); }
.dest-group-quiet .dtile > i:not(.dtile-lock) { color: var(--txt-3); }
.dest-group-quiet .dtile-l { color: var(--txt-2); }
.dest-group + .dest-group { margin-top: var(--section-gap); }
.dest-grid { gap: var(--s2); }
@media (max-width: 359px) { .dtile-d { display: none; } .dtile { min-height: 84px; } }

/* ── 37.23 BOTTOM CAPSULE — ACTIVE PILL + SWIPEABLE OVERFLOW (Reqwa 20:52 UTC
   item 5). The active tab gets a surface pill: --accent-weak fill + 1 px --line-2
   outline in BOTH themes (light already had the fill), ink glyph/label, the dot
   stays. The capsule scrolls horizontally when tabs overflow (5 items at 320 px):
   scroll-snap per tab, scrollbar hidden, tabs never shrink below their label.
   `.navdock` position/padding untouched (Tech Lead 19:59 UTC withdrawal). ── */
.navcapsule { overflow-x: auto; overflow-y: hidden; scroll-snap-type: x proximity; scrollbar-width: none; -ms-overflow-style: none; -webkit-overflow-scrolling: touch; }
.navcapsule::-webkit-scrollbar { display: none; }
.navtab { flex: 1 0 auto; min-width: 60px; scroll-snap-align: center; border-radius: var(--r-inner); transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease); }
.navfab { scroll-snap-align: end; flex: 0 0 auto; }
/* §37.23b (Reqwa 05:20 UTC): the active surface is ONE gliding element, not a
   per-tab background. .navpill sits under the tabs, measured + moved by app.js
   navPillSync (transform + width); tabs keep only the ink change. Drag scrubs
   it (.is-scrubbing = no transition while the finger owns it; .is-under = the
   tab the pill would snap to). Reduced motion: it still lands, no glide. */
.navcapsule { position: relative; touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.navpill { position: absolute; top: .34rem; left: 0; height: 50px; width: 0; opacity: 0; pointer-events: none; z-index: 0;
  border-radius: var(--r-inner); background: var(--accent-weak); box-shadow: inset 0 0 0 1px var(--line-2);
  transition: transform var(--dur-3) cubic-bezier(.22, 1.28, .36, 1), width var(--dur-3) cubic-bezier(.22, 1.28, .36, 1), opacity var(--dur-2) var(--ease);
  will-change: transform; }
.navcapsule.is-scrubbing .navpill { transition: none; }
@media (prefers-reduced-motion: reduce) { .navpill { transition: opacity var(--dur-2) var(--ease); } }
.navtab, .navfab { position: relative; z-index: 1; }
.navtab.active, html[data-theme="light"] .navtab.active { color: var(--txt-1); background: transparent; box-shadow: none; }
.navtab.active i, .navtab.is-under i { color: var(--txt-1); transform: none; }
.navtab.active span, .navtab.is-under span { font-weight: 800; color: var(--txt-1); }
.navtab:active { transform: none; }
@media (min-width: 400px) { .navtab { flex: 1 1 0; min-width: 0; } }

/* ── 37.24 NO iOS FOCUS-ZOOM (Reqwa 20:52 UTC item 6). Safari zooms the page
   when a focused text control is under 16 px. Rule: on phones every input,
   select and textarea renders at ≥ 16 px — one rule, last in the file, wins
   over every earlier 15px / .95rem / text-sm site (.auth-stage .input, .ra-title,
   .ob-field .input, .comp-new .input, Coach composer, Tailwind text-xs/sm).
   NOT done: `maximum-scale=1` on the viewport (accessibility). ── */
@media (max-width: 640px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="hidden"]),
  select, textarea, .input, input.input, .auth-stage .input, .ra .ra-title, .ob-field .input, .comp-new .input,
  .rl-compose .input, #coach-input, .coach-compose input, .coach-compose textarea,
  input.text-xs, input.text-sm, input.text-\[11px\], input.text-\[12px\], input.text-\[13px\], textarea.text-sm, select.text-xs, select.text-sm {
    font-size: 16px !important;
  }
}
.lib-sel { font-size: 13px; min-height: 44px; }   /* ≥16px on phones via §37.24 */
/* §37.17b check-in solo notice: inner panel on tokens; "Join an academy" is a 44 px quiet button (QA tap rule) */
.ci-solo { padding: var(--s3) var(--s4); border-radius: var(--r-inner); background: var(--raised); border: 1px solid var(--line); }
.ci-solo > i { color: var(--txt-3); font-size: var(--ico-row); }
.ci-solo-t { font-size: 13px; line-height: 1.5; color: var(--txt-2); }
.ci-solo-go { min-height: 44px; padding: 0 var(--s2); margin: var(--s1) 0 0 calc(-1 * var(--s2)); font-size: 13px; font-weight: 700; color: var(--txt-1); }
.ci-solo-go i { font-size: 11px; }

/* §37.25 HOME gym link (views4.js hero, "Demo Academy"): QA gate measured 100×17 — the
   anchor now stands 44 px tall and bleeds 8 px left so the glyph still sits on the text
   edge; type stays 11.5 px, visual rhythm unchanged (mt-3 12 px → 44−17 = 27 px of the
   height is the pad, so margin-top drops to 0 and the block below keeps its mt-5). */
.hm-gym { min-height: 44px; padding: 0 var(--s2); margin: 0 0 calc(-1 * var(--s3)) calc(-1 * var(--s2)); max-width: calc(100% + var(--s2)); border-radius: var(--r-inner); }
.hm-gym:active { background: var(--raised); }

/* ── 37.26 DESIGNER'S DS5 SURFACES ON THE DS7 SYSTEM (Round 2, Tech Lead 3789165;
   Second Designer HANDOFF-wave7 §2 item 3). Pattern = §37.21: RESTATE at equal
   or higher specificity here (ds5.css loads AFTER this sheet, so every rule
   whose subject ds5.css also declares carries an `html` prefix to win); §34 / §34.9 above and ds5.css are not edited.
   Applies §35 only — inner radius on every DS5 card and row, kickers on
   --t-kicker, glyphs on --ico-row, 4-based spacing, buttons via .btn variants,
   no new colour (band/state colours that ARE data stay as declared). ── */
/* a. shared DS5 card chrome (ds5.css §DS5-1) */
html .ds5-card { padding: var(--card-pad); margin-bottom: var(--card-gap); border-radius: var(--r-card); }
html .ds5-card .ds5-card-head { gap: var(--s2); margin-bottom: var(--s3); font-size: var(--t-kicker); font-weight: 700; letter-spacing: .09em; color: var(--txt-3); }
.ds5-card .ds5-card-head > i, html .ds5-card .ds5-lock-ico { font-size: 12px; color: var(--txt-3); }
html .ds5-card .ds5-card-title { color: var(--txt-3); }
html .ds5-card .ds5-sec-h, .ds5-card .wr-col-h, .bp-hist-h, .tvn-legend { font-size: var(--t-kicker); font-weight: 700; letter-spacing: .09em; color: var(--txt-3); margin-bottom: var(--s2); }
html .ds5-card .ds5-locked-row { gap: var(--s2); padding-top: var(--s3); margin-top: var(--s3); font-size: 13px; }
html .ds5-card .br-staff-note, html .ds5-card .kiosk-open-hint, html .ds5-card .nudge-empty-note, html .ds5-card .br-no-names, html .ds5-card .nudge-cooldown { font-size: 12.5px; line-height: 1.5; color: var(--txt-3); }
html .ds5-card .br-empty, html .ds5-card .br-read { font-size: var(--t-body); line-height: 1.5; color: var(--txt-2); }
html .ds5-card .br-week-label { font-size: var(--t-card); font-weight: 700; margin-bottom: var(--s2); }
.ds5-card .br-week-label small { font-size: 12.5px; font-weight: 500; }
/* rows inside the cards: 44–56 geometry, inner radius where they are surfaces */
html .ds5-card .br-finding { padding: var(--s3) 0; }
html .ds5-card .br-finding-head { min-height: 32px; gap: var(--s3); }
html .ds5-card .br-finding-t { font-size: 15px; font-weight: 700; }
.ds5-card .br-finding-t small, html .ds5-card .br-finding-sub { font-size: 12.5px; font-weight: 500; }
html .ds5-card .br-finding-v, html .ds5-card .br-axis-v { font-size: 15px; font-weight: 800; }
html .ds5-card .br-axis-row { min-height: 44px; padding: var(--s1) 0; font-size: 14.5px; }
html .ds5-card .br-member-row { min-height: 36px; align-items: center; font-size: 14px; }
html .ds5-card .br-members-sum { min-height: 44px; font-size: 13px; font-weight: 700; }
html .ds5-card .br-chat-wrap { padding-top: var(--s3); }
html .ds5-card .br-section { margin-bottom: var(--s4); }
html .ds5-card .br-staff-note + .br-section, html .ds5-card .br-section + .br-section, html .ds5-card .br-week-label + .br-section { margin-top: var(--s5); }
html .ds5-card .br-section > .ds5-sec-h { margin-bottom: var(--s3); }
html .ds5-card .br-finding:first-of-type { padding-top: 0; }
/* segmented controls in DS5 cards: DS7 seg (pill 44) */
html .ds5-card .seg.br-seg { gap: var(--s1); padding: var(--s1); }
.ds5-card .seg-btn { min-height: 44px; }
/* buttons: the three .btn variants only; sizes from the control scale */
.ds5-card .btn i { font-size: var(--ico-row); }
.ds5-card .t-locked-go, .t-locked .t-locked-go { margin-top: var(--s3); min-height: var(--ctl-h); }
/* b. nudge outbox (ds5.css §DS5-3) */
html .nudge-templates { gap: var(--s2); margin-bottom: var(--s3); }
html .nudge-tpl { padding: var(--s3) var(--s4); min-height: 44px; border-radius: var(--r-inner); font-size: 14px; line-height: 1.45; transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease); }
html .nudge-tpl.on { border-color: var(--line-2); background: var(--raised); }
html[data-theme="light"] .nudge-tpl.on { border-color: var(--line-2); }
html .nudge-ta { min-height: 96px; border-radius: var(--r-inner); font-size: 15px; }
html .nudge-row { padding: var(--s3) 0; }
html .nudge-row-meta { gap: var(--s2); margin-bottom: var(--s1); }
html .nudge-to { font-size: 15px; font-weight: 700; }
html .nudge-state { min-height: 24px; padding: 0 var(--s2); font-size: var(--t-kicker); font-weight: 700; letter-spacing: .04em; border-radius: var(--r-ctl); }
html .nudge-body { font-size: 14px; line-height: 1.5; }
html .nudge-reply { margin-top: var(--s2); padding: var(--s2) var(--s3); font-size: 13px; border-radius: 0 var(--r-inner) var(--r-inner) 0; }
/* c. kiosk (ds5.css §DS5-4) — wall screen keeps its big type; geometry only */
html .kiosk-member-btn { border-radius: var(--r-inner); padding: var(--s4) var(--s5); transition: background var(--dur-2) var(--ease); }
html .kiosk-roster { gap: var(--s3); }
html .kiosk-brand, html .kiosk-day { font-size: var(--t-kicker); font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--txt-3); }
html .kiosk-device-row { min-height: 48px; gap: var(--s3); padding: var(--s2) 0; }
html .kiosk-device-label { font-size: 15px; font-weight: 700; }
html .kiosk-device-meta { font-size: 12.5px; }
/* d. tier surfaces (theme-v2 §34.9 — views12.js / views3.js / views4.js) */
.t-locked { padding: var(--card-pad); margin-bottom: var(--card-gap); border-radius: var(--r-card); }
.t-locked-line { font-size: var(--t-body); line-height: 1.5; }
.tier-line { margin: 0 0 var(--s4); font-size: var(--t-body); }
.tier-doors { gap: var(--s2); margin-bottom: var(--section-gap); }
.tier-doors .tvn-entry, .tvn-entry { min-height: 64px; padding: var(--s3) var(--s4); gap: var(--s3); border-radius: var(--r-inner); font-size: var(--t-card); font-weight: 700; margin-bottom: 0; transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease); }
.tvn-entry:active { background: var(--raised); }
.tvn-entry > i:first-child, html[data-theme="light"] .tvn-entry > i:first-child { font-size: var(--ico-row); width: 20px; text-align: center; color: var(--txt-2); }
.tvn-entry.is-gated > i:first-child { color: var(--txt-3); }
.tvn-entry > i:last-child, .tvn-entry.is-gated > i:last-child, html[data-theme="light"] .tvn-entry.is-gated > i:last-child { font-size: 13px; color: var(--txt-3); }
.tier-doors .tvn-entry small { margin-top: 2px; font-size: 12.5px; line-height: 1.4; font-weight: 500; }
.tvn-window, .tvn-pair, .tvn-axes, .tvn-leaks, .tvn-read, .tvn-state, .wr-sec { padding: var(--card-pad); margin-top: var(--card-gap); margin-bottom: 0; border-radius: var(--r-card); }
.wr-sec + .wr-sec, .tvn-state + .tvn-window { margin-top: var(--card-gap); }
.wr-sec .section-label { margin-bottom: var(--label-gap); }
.wr-empty, .wr-drill p, .wr-drill-t, .tvn-pair-line { font-size: var(--t-body); line-height: 1.5; }
.wr-card { margin-bottom: var(--card-gap); border-radius: var(--r-card); }
.wr-head { min-height: 64px; padding: var(--s3) var(--card-pad); gap: var(--s3); }
.wr-week { font-size: var(--t-card); font-weight: 700; }
.wr-go { font-size: 13px; font-weight: 700; min-height: 44px; }
.wr-go i { font-size: 12px; }
.wr-body { padding: 0 var(--card-pad) var(--card-pad); }
.wr-card.is-open .wr-body { padding-top: var(--s4); }
.wr-cols { gap: var(--s4); }
.wr-row { min-height: 44px; padding: var(--s2) 0; gap: var(--s3); }
.wr-row-t { font-size: 15px; font-weight: 700; }
.wr-row-v { font-size: 14px; font-weight: 700; }
.wr-drill { margin-top: var(--s4); padding-top: var(--s4); }
.wr-src { margin-top: var(--s2); font-size: var(--t-kicker); letter-spacing: .09em; text-transform: uppercase; font-weight: 700; }
.cl-chip { min-height: 24px; padding: 0 var(--s2); font-size: var(--t-kicker); font-weight: 700; letter-spacing: .04em; }
.cl-track { padding: var(--s3) 0; }
.cl-track-top { min-height: 32px; gap: var(--s3); }
.cl-track-t { font-size: 15px; font-weight: 700; }
.cl-track-t small, .cl-note, .pl-note { font-size: 12.5px; line-height: 1.45; }
.cl-line { margin-top: var(--s1); font-size: 14px; }
.pl-list { gap: var(--s2); margin-bottom: var(--section-gap); }
.pl-row { min-height: 64px; padding: var(--s3) var(--s4); gap: var(--s3); border-radius: var(--r-inner); transition: background var(--dur-2) var(--ease); }
.pl-row:not(.is-static):active { background: var(--raised); }
.pl-av-anon { width: 40px; height: 40px; border-radius: var(--r-ctl); font-size: var(--ico-row); }
.pl-t { font-size: 15px; font-weight: 700; }
.pl-s, .pl-delta, .pl-recent-d, .pl-recent-m, .pl-split { font-size: 12.5px; }
.pl-summary { padding-bottom: var(--s4); }
.pl-big { gap: var(--s2); }
.pl-big-v { font-size: var(--t-figure); font-weight: 800; letter-spacing: -.03em; }
.pl-big-s { font-size: 14px; }
.pl-method { min-height: 36px; padding: 0 var(--s3); font-size: 13px; gap: var(--s2); }
.pl-methods { gap: var(--s2); }
.pl-recent { min-height: 44px; padding: var(--s1) 0; gap: var(--s3); }
.pl-recent-r { font-size: 14.5px; font-weight: 700; }
/* e. Progress allowance strip + Belt Progress row + story hero (§34.9 / style.css §Progress story) */
.allow-strip { padding: var(--card-pad); margin-bottom: var(--card-gap); border-radius: var(--r-card); }
.allow-strip.is-compact { padding: var(--s4) var(--card-pad); margin-top: var(--card-gap); }
.allow-row { min-height: 44px; padding: var(--s2) 0; gap: var(--s1) var(--s3); }
.allow-l, .allow-v { font-size: 14.5px; font-weight: 700; }
.allow-v { font-weight: 800; }
.allow-r, .allow-note { font-size: 12.5px; }
.allow-note { margin-top: var(--s3); line-height: 1.5; }
.bp-card { margin-bottom: var(--card-gap); border-radius: var(--r-card); }
.bp-card.is-row .bp-row { min-height: 64px; padding: var(--s3) var(--card-pad); gap: var(--s3); }
.bp-card.is-row .bp-more { padding: 0 var(--card-pad) var(--card-pad); }
.bp-row-s { font-size: 14px; line-height: 1.45; }
.bp-row-c { font-size: 13px; }
.bp-frame { font-size: var(--t-body); font-weight: 600; line-height: 1.5; }
.bp-sig { min-height: 44px; padding: var(--s2) 0; }
.bp-sig-l { font-size: 14.5px; } .bp-sig-v { font-size: 15px; font-weight: 800; }
.bp-sig-w, .bp-note { font-size: 12.5px; }
.bp-hist-row { min-height: 44px; gap: var(--s3); }
.story-hero { padding: var(--card-pad); margin-bottom: var(--card-gap); border-radius: var(--r-card); }
.story-iq-when { font-size: 12.5px; }
.story-iq-num { font-size: clamp(2.75rem, 13vw, 3.5rem); font-weight: 800; letter-spacing: -.04em; }
.story-iq-trend { font-size: 15px; font-weight: 700; }
.story-iq-trend small { font-size: 12.5px; }
.story-iq-bar { margin-top: var(--s3); gap: 3px; height: 10px; }
.story-cells { gap: var(--card-gap); margin-top: var(--s4); }
.story-cell { padding: var(--s4); min-height: 72px; }
.story-cell .stat-cell-v { font-size: 22px; font-weight: 800; letter-spacing: -.03em; }
.story-cell .stat-cell-l { font-size: var(--t-kicker); letter-spacing: .09em; margin-top: var(--s2); }
/* f. Roll IQ score card + share sheet (§34.8 / style.css §Roll IQ) */
.rl-scorecard { padding: var(--card-pad); margin-bottom: var(--card-gap); border-radius: var(--r-card); }
.rl-sc-num { font-size: clamp(2.75rem, 13vw, 3.5rem); font-weight: 800; letter-spacing: -.04em; }
.rl-sc-sub { font-size: 14px; line-height: 1.45; }
.rl-sc-seg { margin-top: var(--s3); height: 12px; gap: 3px; }
.rl-sc-axes { margin-top: var(--s4); padding-top: var(--s4); }
.rl-sc-axes.is-grid { gap: var(--s3) var(--s4); }
.rl-sc-axes-h { font-size: var(--t-kicker); font-weight: 700; letter-spacing: .09em; }
.rl-sc-axes.is-grid .rl-sc-axis-l { font-size: var(--t-kicker); letter-spacing: .06em; }
.rl-sc-axes.is-grid .rl-sc-axis-v { font-size: 17px; font-weight: 800; }
.rl-sc-pre, .rl-sc-coverage { margin-top: var(--s3); font-size: 14px; }
.rc-preview { border-radius: var(--r-inner); }
.rc-scrub { margin-top: var(--s3); }
/* g. onboarding prep (style.css §onboarding prep) — geometry only */
.scan-strip { gap: var(--s2); margin-top: var(--s3); }
.scan-frame { border-radius: var(--r-inner); }
.scan-chips { gap: var(--s2); margin-top: var(--s3); }
.scan-chip { min-height: 32px; padding: 0 var(--s3); font-size: 12.5px; gap: var(--s2); }
.scan-chip small { font-size: 10px; }
.scan-facts span { font-size: 11px; }
/* h. 2FA code step (views.js loginCodeStep) — one question on the card */
.auth-stage #login-code-form .input[name="code"] { min-height: var(--ctl-h-lg); font-size: 26px; letter-spacing: .4em; }
.auth-stage #login-code-form .field-help { margin: var(--s2) 0 0; font-size: 12.5px; color: var(--txt-3); }
.auth-stage #login-code-form .btn-primary { margin-top: var(--s3); }
.auth-code-alt { display: flex; flex-direction: column; align-items: center; gap: 0; }
.auth-code-q { display: inline-flex; align-items: center; gap: var(--s1); white-space: nowrap; }
.auth-code-alt .auth-alt { min-height: 44px; display: inline-flex; align-items: center; padding: 0 var(--s1); }
.auth-code-alt .auth-alt-quiet, html[data-theme="light"] .auth-code-alt .auth-alt-quiet { color: var(--txt-3); }

/* ── 37.27 LANDING #pricing = ONE SYSTEM WITH /plans (§37.10) AND THE PAYWALL
   (style.css §paywall) — HANDOFF-Designer-DS5 §2 item 1, CSS-only (views.js
   markup untouched; MARKETING-WAVE2 §4: no section/copy change). The landing
   tier still carried the pre-DS7 set — lime border, lime flag, lime ticks AND
   a lime CTA. Rule from §37.10: one lime object per card, the CTA; flag is
   ink-on-raised; ticks --txt-2; hero border = hairline-2; the system geometry
   and type scale. ── */
.land-plans { gap: var(--card-gap); margin-top: var(--s5); }
.land-plan { padding: var(--card-pad); border-radius: var(--r-card); }
.land-plan.is-hi { border-color: var(--line-2); background: var(--raised); box-shadow: var(--lift-2); }
.land-plan-flag { top: -14px; left: var(--card-pad); min-height: 28px; display: inline-flex; align-items: center; padding: 0 var(--s3); background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); font-size: var(--t-kicker); letter-spacing: .08em; border-radius: var(--r-ctl); }
.land-plan-name { font-size: 20px; font-weight: 800; letter-spacing: -.02em; }
.land-plan-tag { margin-top: var(--s1); font-size: 14px; line-height: 1.45; min-height: 0; }
.land-plan-price { margin-top: var(--s4); gap: var(--s1); }
.land-plan-fig { font-size: var(--t-figure); font-weight: 800; letter-spacing: -.035em; }
.land-plan-per { font-size: 14px; }
.land-plan-year { margin-top: var(--s1); font-size: 12.5px; }
.land-plan-feats { margin-top: var(--s4); padding-top: var(--s4); gap: var(--s2); }
.land-plan-feats li { font-size: 15px; color: var(--txt-1); gap: var(--s3); }
.land-plan-feats li i { color: var(--txt-2); font-size: 12px; margin-top: 5px; }
.land-plan-excl { margin-top: var(--s3); gap: var(--s1); }
.land-plan-excl li { font-size: 12.5px; padding-left: 22px; }
.land-plan-btn { margin-top: var(--s4); min-height: var(--ctl-h); padding: 0 var(--s4); border-radius: var(--r-ctl); font-size: 15px; font-weight: 700; }
.land-fine.land-fine-c { margin-top: var(--s4); font-size: 12.5px; color: var(--txt-3); }
/* 37.27b — THE RAIL + DOTS (Designer, Round 3; was the joint Designer/Second
   Designer item in HANDOVER-e §8, now Designer-owned). Below 900px `.land-plans`
   stops being a 3-tall stack (three full screens before the top tier at 390)
   and becomes the snap rail /plans (§22b) and the paywall (§22c) already use:
   82% cards, centre snap, the next card peeking. Then the dots say "there are
   three": ink, not lime — the CTA stays the card's one lime object — the
   current dot a 20px pill on --txt-1, the rest 6px on --line-2, each inside a
   44px button. The nav is hidden until landingRail() (views.js) fills it AND
   the rail can actually scroll, so the desktop grid never shows dots.
   Left/right bleed: the rail runs edge to edge through the page gutter so a
   card can be half-visible at the edge (the swipe affordance), padding puts
   the first card back on the gutter. */
@media (max-width: 899.98px) {
  .land-plans {
    display: grid; grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 82%; gap: var(--s3);
    overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
    margin-inline: calc(-1 * var(--gutter)); padding: var(--s4) var(--gutter) var(--s2);
    scroll-padding-inline: var(--gutter); scrollbar-width: none; align-items: stretch;
  }
  .land-plans::-webkit-scrollbar { display: none; }
  .land-plan { scroll-snap-align: center; height: auto; }
}
.land-rail-dots { display: flex; justify-content: center; gap: 0; margin-top: var(--s1); }
.land-rail-dots[hidden] { display: none; }
.land-rail-dot { display: grid; place-items: center; width: 44px; height: 44px; padding: 0; background: none; border: 0; cursor: pointer; }
.land-rail-dot i { display: block; width: 6px; height: 6px; border-radius: 999px; background: var(--line-2); transition: width var(--dur-2) var(--ease), background var(--dur-2) var(--ease); }
.land-rail-dot.on i { width: 20px; background: var(--txt-1); }
.land-rail-dot:focus-visible { outline: 2px solid var(--k-focus); outline-offset: -8px; border-radius: 999px; }
@media (prefers-reduced-motion: reduce) { .land-rail-dot i { transition: none; } }

/* ── 37.28 SMALL-PAGES SWEEP (DS8, HANDOFF §2 item 4): Log a roll · Daily ·
   Milestones · Lockers · People · Verify · Roll verification · Roll call ·
   Admin · Insights · Clips. Every page head is `.section-label` + `.page-title`
   (§35.5, 24/800); card headings are `.card-title`; the flame/op accents on
   these pages were decoration, not state — they take the neutral inks so the
   ONE lime object per screen rule holds; rows ≥ 56 on --r-inner. `sw-` =
   sweep hooks shared across the small pages; `lk-` = Lockers grid. ── */
.sw-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.sw-head-go { min-height: 44px; padding: 0 var(--s3); margin-right: calc(-1 * var(--s3)); font-size: 13px; font-weight: 700; color: var(--txt-2); }
.sw-head-go i { font-size: var(--ico-row); margin-right: var(--s2); color: var(--txt-3); }
.sw-row { display: flex; align-items: center; gap: var(--s3); min-height: 56px; padding: var(--s3) var(--s4); }
.sw-check-row { display: flex; align-items: center; gap: var(--s3); min-height: 44px; padding: 0 var(--s1); font-size: 14px; color: var(--txt-2); cursor: pointer; }
.sw-check { width: 20px; height: 20px; flex: 0 0 auto; margin: 0; accent-color: var(--accent-fill); border-radius: 6px; }
.chip.is-muted { background: var(--raised); color: var(--txt-3); }
.chip.is-draw { background: var(--raised); color: var(--txt-2); }
.sw-bar-empty { background: var(--raised); }
.sw-glyph-well { background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-inner); color: var(--txt-1); }
.sw-glyph-well i { color: var(--txt-1) !important; }
/* Lockers: held key card + the key grid. Free keys are the only interactive cells; the
   one you hold reads as selected (accent-weak tint), maintenance and taken recede. */
.lk-mine { border-color: var(--line-2); }
.lk-mine-num { width: 56px; height: 56px; flex: 0 0 auto; display: grid; place-items: center; border-radius: var(--r-inner); background: var(--accent-weak); color: var(--txt-1); font-size: var(--t-card); font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.lk-cell { aspect-ratio: 1; min-height: 56px; display: grid; place-items: center; border-radius: var(--r-inner); border: 1px solid var(--line); background: var(--card); color: var(--txt-2); font-size: 17px; font-weight: 800; font-variant-numeric: tabular-nums; transition: background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease); }
.lk-cell.is-free:not(:disabled):active { transform: scale(.96); background: var(--raised); }
@media (hover: hover) { .lk-cell.is-free:not(:disabled):hover { border-color: var(--line-2); background: var(--raised); } }
.lk-cell.is-mine { background: var(--accent-weak); border-color: color-mix(in srgb, var(--accent-fill) 45%, transparent); color: var(--txt-1); }
.lk-cell.is-taken { color: var(--txt-3); background: transparent; }
.lk-cell.is-maint { color: var(--txt-3); background: transparent; border-style: dashed; }
.lk-legend { display: flex; gap: var(--s4); margin-top: var(--s5); font-size: 12px; color: var(--txt-3); }
.lk-legend span { display: inline-flex; align-items: center; gap: var(--s2); }
.lk-sw { width: 12px; height: 12px; border-radius: 4px; border: 1px solid var(--line-2); background: var(--card); }
.lk-sw.is-taken { background: transparent; border-color: var(--line); }
.lk-sw.is-mine { background: var(--accent-weak); border-color: color-mix(in srgb, var(--accent-fill) 45%, transparent); }
/* People + Roll call rows: 56 floor, inner radius, theme surfaces (style.css:1869 painted rgba literals) */
.ps-row, .rc-row:not(.rc-block .rc-row) { min-height: 56px; border-radius: var(--r-inner); }
.rc-row[id^="rc-"] { padding: var(--s2) var(--s3); background: var(--card); border: 1px solid var(--line); border-radius: var(--r-inner); min-height: 56px; }
.rc-row[id^="rc-"].is-here { background: var(--good-weak); border-color: color-mix(in srgb, var(--good) 30%, transparent); opacity: .72; }
.rc-tick { border-radius: var(--r-inner); background: var(--raised); border-color: var(--line); }
/* §37.29 PROGRESS — axis cards cannot widen the page. The technique rows are
   `.flex > .min-w-0.flex-1 > .truncate`, but a grid track sized `auto` takes the
   card's min-content, and a long technique name (seed: "North-South External
   Shoulder Lock (Trab Lock / Scorpion Lock)") pushed the single column to 442 px
   at 390 → horizontal scroll on Progress. Grid items get an explicit min-width
   floor so the truncate can bite. DS8 320/390 audit. */
main .grid > * { min-width: 0; }   /* every grid item (cards, panels, the space-y wrappers on Progress) */
/* At 320 the Strongest / Leaking pair (views3.js:454, 2 × card p-5) cannot hold a
   one-word axis label at 20 px — the pair stacks below 360 and long labels may break. */
.grid > .card .text-xl.font-black { overflow-wrap: anywhere; }
@media (max-width: 359px) { main .grid.grid-cols-2.gap-3 { grid-template-columns: minmax(0, 1fr); } }

/* ── 37.30 ATHLETE JOURNEY AT THE CEILING (Round 2, Tech Lead 3794940 — Reqwa's
   "design ceiling" order). demo_pro walked at 390, both themes, landing →
   register → onboarding → first analysis → Progress → Roll IQ → Me → paywall
   (probe scripts/probes/journey.mjs). Nineteen stops, five fixes, each one a
   place where the walk stopped feeling like one product. Same pattern as
   §37.26: restate here, never edit §34 / style.css legacy blocks in place. ── */

/* a. ONBOARDING Q2 — the selected belt card was the LAST coral in the funnel.
   style.css `.belt-pick.on` still paints rgba(198,43,36) (the pre-lime accent)
   as tint + border + inset ring, so the one screen where a new athlete makes a
   choice answered in a colour no other screen uses. Every other .ob-opt.on is
   raised + hairline-2 (§37.9); this joins it. Rank colour stays on the swatch. */
.belt-pick.on, .ob-opt.belt-pick.on { background: var(--raised); border-color: var(--line-2); box-shadow: none; }

/* b. ROLL IQ — "The read" paragraph was DOUBLE-PADDED. §37.9 gives --card-pad
   to .rl-read AND to .rl-summary, and the summary is nested inside the read
   card, so the text sat a full card-pad inside the kicker (see the 390 board:
   kicker at the card edge, prose indented 20px). The inner paragraph is prose,
   not a card: no pad, no radius, --s3 under the kicker. The .rl-sec panels
   keep their inner pad — they ARE inner cards (raised, hairline). */
.rl-read .rl-summary { padding: 0; margin-top: var(--s3); border-radius: 0; font-size: var(--t-body); line-height: 1.55; }

/* c. PROGRESS — the Game Map RANK BANNER carried the rank hue as a fill bar
   gradient AND a large 28px title AND a glyph AND a 2px progress line, i.e.
   the only page block on Progress that shouted in a second colour (cyan on
   "Grinder I"). Rank colour is data (§37.9 keeps it on the glyph); the TITLE
   is a title and takes primary ink like every other card title on the page,
   and the progress line is the accent, like the streak ring and the Roll IQ
   ticks above it. Inline styles need the !important. */
.gm-rank .text-3xl[style] { color: var(--txt-1) !important; }
.gm-rank .h-1\.5 > div[style] { background: var(--accent-fill) !important; }
html[data-theme="light"] .gm-rank .h-1\.5 { background: var(--sunken); }

/* d. ME — four KPI cards read at three sizes: glyph 12px on --txt-3, figure
   26px, label 10px. The "0 tournament wins" and "100% visit rate" figures sat
   on the same weight as the streak, so a zero shouted. Figures on --t-figure
   family sizing with the label on --t-kicker (the same kicker every other card
   uses — 10px was below the type floor on a phone). Row rhythm --s1/--s2. */
.me-kpis { gap: var(--s2); }
.me-kpi i { margin-bottom: var(--s1); }
.me-kpi .text-2xl { margin-top: var(--s1); }
.me-kpi .section-label { font-size: var(--t-kicker) !important; margin-top: var(--s1); letter-spacing: .09em; }
/* An empty Badges panel is a full card of one grey sentence; give the sentence
   the empty-state ink and size the rest of the app uses (§37.9 .br-empty). */
.me-badges-empty, .card > p.text-sm.text-slate-600 { font-size: var(--t-body); color: var(--txt-3); }

/* e. TAP TARGETS the walk measured under 44px on athlete stops: the register
   card's "Log in" alternate (49×31) and the onboarding "Not now — take me to
   my dashboard" skip (353×43). Two measured-small controls are NOT touched
   because their hit box is already ≥44 via ::before: the consent links (§34)
   and the .btn-sm ghost pills (--ctl-h-sm 40 + 4px inset each side = 48;
   §37.5 sets that on purpose so a small button stays visually small). */
.auth-stage .auth-alt { min-height: 44px; display: inline-flex; align-items: center; padding: 0 var(--s2); margin: 0; }
.ob-skip { min-height: 44px; }

/* ── 37.31 FILM ROOM + ANALYSIS STATUS (Round 3, Tech Lead 3803483 — the pass
   for Reqwa's first real phone clip, prepared on fixture rows for every state).
   a. ONE strip per non-done state (views2.js RL_STRIP): sentence + optional
      action, the state class from §21 colours it. The running spinner used to
      sit on the sentence's first letter — the strip is a column now, spinner
      in the gutter, text starts after it.
   b. Failed = danger ink + "Try again" (ghost, 44). awaiting_upload = quiet
      info + "Back to Analysis". Actions are ghosts: the lime stays with the
      read card's Share.
   c. Player frame takes the clip's own aspect via --rl-ar (set from metadata;
      default 16/9). Portrait clamps at 62dvh so a 9:16 clip is tall but the
      title and the read stay reachable; landscape keeps the 40dvh cap.
   d. List rows: pending state on --txt-2 (was accent — a state is not a CTA),
      failed on --danger-ink. ── */
.rl-strip { display: grid; gap: var(--s3); padding: var(--s4); border-radius: var(--r-inner); font-size: var(--t-body); line-height: 1.5; }
.rl-strip p { margin: 0; }
.rl-strip.is-running { padding-left: calc(var(--s4) + 24px); }
.rl-strip.is-running::before { left: var(--s4); top: calc(var(--s4) + 4px); margin-top: 0; }
.rl-strip.is-info { color: var(--txt-2); border-color: var(--line-2); }
.rl-strip.is-queued { color: var(--txt-1); border-color: var(--line-2); }
.rl-strip.is-failed { color: var(--danger-ink); border-color: color-mix(in srgb, var(--danger-ink) 40%, transparent); }
.rl-strip.is-failed p { color: var(--txt-1); }
.rl-strip.is-failed p::first-line { color: var(--danger-ink); }
.rl-strip-act { justify-self: start; min-height: 44px; padding: 0 var(--s4); border-radius: var(--r-ctl); font-size: 14px; font-weight: 700; color: var(--txt-1); border: 1px solid var(--line-2); }
.rl-strip-act i { font-size: var(--ico-row); margin-right: var(--s2); color: var(--txt-2); }
.rl-stage { --rl-ar: 16 / 9; }
.rl-stage video { aspect-ratio: var(--rl-ar); max-height: 40dvh; width: 100%; object-fit: contain; }
.rl-stage.is-portrait video { max-height: 62dvh; }
.rl-s.is-pending { color: var(--txt-2); }
.rl-s.is-failed { color: var(--danger-ink); }
html[data-theme="light"] .rl-s.is-pending { color: var(--txt-2); }

/* ── 37.32 LANDING PHONE FRAMES (Round 3, Reqwa 05:40 via Tech Lead 3806775).
   The two hero screens were raw captures with no device around them. They now
   sit inside a CSS iPhone: the JPG stays a pure 1179×2556 screen capture (so
   DS7-scratch/shoot-landshots.mjs keeps working and Reqwa's own device shots
   still drop in), and .land-shot IS the device — a dark titanium-style body
   (bezel from --frame-* below), the screen corner radius inside it, a Dynamic
   Island cutout as ::before, and a soft elevation shadow. Only the DEVICE
   TREATMENT is taken from the reference; layout, copy and colours are ours.
   THEME OF THE SCREENS: the captures are shot in the app's DARK theme on both
   page themes (Tech Lead ruling): dark screen inside a dark body is one object
   on either page, the lime CTA reads strongest on dark, and the two frames
   never flip mid-scroll. .land-shots-note says so on the light page.
   The body reads on BOTH page themes because it is a fixed near-black with a
   1px lighter rim (titanium edge highlight) — on the dark page the rim is what
   separates device from ground, on the light page the body itself does.
   Composition: front frame (the second slot) slightly larger and overlapping,
   as the reference does — via transform scale only, no layout shift, and the
   3D scroll script's inline transforms still win once .is-3d is on. */
:root {
  --frame-body: #1A1B1F;                 /* titanium-dark body, both themes */
  --frame-rim: rgba(255,255,255,.14);    /* the machined edge highlight */
  --frame-bezel: 9px;                    /* 8–10 px brief */
  --frame-r: 48px;                       /* outer corner */
  --frame-r-in: 40px;                    /* screen corner */
}
.land-shot {
  padding: var(--frame-bezel);
  background: var(--frame-body);
  border: 1px solid var(--frame-rim);
  border-radius: var(--frame-r);
  box-shadow: var(--lift-3), inset 0 0 0 1px rgba(0,0,0,.6);
  aspect-ratio: auto;
}
.land-shot img { border-radius: var(--frame-r-in); aspect-ratio: 1179 / 2556; height: auto; background: var(--frame-body); }
/* Dynamic Island: a pill over the top of the screen, same ink as the body. */
.land-shot::before {
  content: ''; position: absolute; z-index: 2; left: 50%; top: calc(var(--frame-bezel) + 2.8%);
  width: 26%; height: 3.1%; transform: translateX(-50%);
  border-radius: 999px; background: var(--frame-body);
}
/* Side buttons: two thin ridges on the left edge, one on the right — read as
   device without adding a colour. Hidden below 480 where they are sub-pixel. */
.land-shot::after {
  content: ''; position: absolute; left: -2px; top: 18%; width: 2px; height: 7%;
  background: var(--frame-rim); border-radius: 2px 0 0 2px;
  box-shadow: 0 10.5% 0 var(--frame-rim), 0 21% 0 var(--frame-rim);
}
.land-shot + .land-shot::after { left: auto; right: -2px; top: 22%; height: 11%; border-radius: 0 2px 2px 0; box-shadow: none; }
/* Front-frame emphasis: the second slot is the "front" phone — a touch larger,
   overlapping. Applied on the fanned rest pose and the flat pose alike; the
   3D script's inline transforms replace it while the scroll is live. */
.land-shot + .land-shot { transform: rotate(3.5deg) translateY(1.6rem) scale(1.04); z-index: 1; margin-left: -1.5rem; }
.land-shots:hover .land-shot + .land-shot { transform: rotate(1.5deg) translateY(1.2rem) scale(1.04); }
.land-shots.is-flat .land-shot + .land-shot, .land-shots.is-flat:hover .land-shot + .land-shot { transform: scale(1.04); }
html[data-theme="light"] .land-shot { box-shadow: 0 24px 60px -20px rgba(20,21,26,.38), inset 0 0 0 1px rgba(0,0,0,.6); border-color: rgba(0,0,0,.35); }
html[data-theme="light"] .land-shots-note { color: var(--txt-3); }
@media (max-width: 479px) {
  .land-shot { --frame-bezel: 6px; --frame-r: 34px; --frame-r-in: 28px; }
  .land-shot::after { display: none; }
  .land-shot + .land-shot { margin-left: -1rem; }
}

/* ── 37.33 ROOT GESTURE LOCK OPT-INS (Tech Lead, 2026-09-08). style.css sets
   html/body touch-action: pan-y so the page can neither drift sideways nor pinch
   out (Reqwa: "user can freely slide right/left, zoom out"). Anything that
   legitimately scrolls on the x axis re-enables x-pan on itself. ── */
.land-plans, .tiers-list, .pw-plans, .swipe-row, .lib-sort, .legal-tabs, .legal-toc ol, .legal-table, .seg-scroll, .br-seg { touch-action: pan-x pan-y; }
/* .navcapsule keeps its own touch-action: pan-y (§37.23b) — the pill drag handles x itself. */

/* ── 37.33 DS10 LANDING HERO RESTYLE (Round 4, Tech Lead 3809871; Reqwa's
   direction from his other product's hero). Dark full-bleed stage with a
   dimmed real mat behind it; three fanned iPhone frames centre-forward that
   bleed off the bottom of the hero into the next section; heavier, tighter
   headline; one quiet sub line; lime CTA; desktop section bar.
   DARK IN BOTH PAGE THEMES — same ruling as the frames (§37.32): the hero is
   one object, photo + phones + type, and it does not invert. So the type
   inside .has-stage is pinned to the dark inks by value, not by --txt-*.
   The photo is CC0 (img/hero/LICENSE.md), graded dark in the file, dimmed
   again here to ~30% with a gradient into the page ground so the frames land
   on solid colour. No layout shift: the stage is absolutely positioned inside
   a section whose height comes from its content; the <img> is cover-fitted. */
.land-hero.has-stage {
  padding-top: var(--s7);
  position: relative; isolation: isolate; overflow: visible;   /* the frames bleed OUT of the hero; the photo clips itself */
  /* full-bleed: break out of <main>'s gutter and max-width */
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  padding: var(--s6) var(--gutter) 0;
  background: #0A0A0C;
  color: #F4F4F5;
  text-align: center;
}
.land-stage { position: absolute; inset: 0; z-index: -1; display: block; margin: 0; pointer-events: none; overflow: hidden; }
.land-stage img {
  display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%;
  filter: brightness(.42) saturate(.8);
}
/* the fade into the ground: photo above, page below, the phones straddle it */
.land-stage::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(10,10,12,.55) 0%, rgba(10,10,12,.15) 28%, rgba(10,10,12,.5) 66%, #0A0A0C 92%);
}
html[data-theme="light"] .land-hero.has-stage { background: #0A0A0C; color: #F4F4F5; }
/* hero type pinned to the dark set */
.has-stage .land-eyebrow { background: rgba(255,255,255,.08); color: #B4B7BE; border: 1px solid rgba(255,255,255,.14); }
.has-stage .land-eyebrow i { color: var(--txt-1); }
.has-stage .land-h1 { color: #F4F4F5; line-height: .95; letter-spacing: -.045em; font-weight: 900; max-width: 15ch; }
@media (min-width: 1024px) { .has-stage .land-h1 { max-width: 14ch; font-size: clamp(3rem, 5.4vw, 4.8rem); } }
.has-stage .land-sub { color: #B4B7BE; max-width: 30rem; font-size: clamp(1rem, 2.2vw, 1.15rem); }
.has-stage .land-link { color: #B4B7BE; min-height: 44px; display: inline-flex; align-items: center; }
.has-stage .land-link:hover { color: #F4F4F5; }
.has-stage .land-fine { color: #8A8F98; }
/* CTA stays lime (brief: NOT white); the light-page btn-primary rule already is */

/* THE TRIO. Left · centre · right; the centre one forward and ~1.15× —
   composed as a 3-column grid so the sides can slide behind. The whole group
   is pushed DOWN so the frames bleed off the hero's bottom edge into the next
   section (negative margin below the section, positive z so they ride over
   the page ground). Pose = a function of --land-depth (0 = leaning back and
   dim, 1 = the rest fan); reduced-motion and no-JS never set it → 1. */
.land-shots.is-trio {
  --land-depth: 1;
  display: grid; grid-template-columns: 1fr 1fr 1fr; align-items: end; justify-items: center;
  gap: 0; max-width: 58rem; margin: var(--s6) auto 0; padding: 0;
  perspective: 1200px; perspective-origin: 50% 20%;
  /* the bleed: the group is taller than the space left for it, and the
     section clips nothing at the bottom because the frames are what the eye
     follows into the next section */
  margin-bottom: 0; transform: translateY(var(--land-bleed, 5.5rem));
  position: relative; z-index: 2;
}
.land-hero.has-stage { --land-bleed: 5.5rem; }
.land-shots.is-trio .land-shot {
  width: 100%; max-width: 15rem; margin: 0; flex: none;
  transition: transform .18s linear, opacity .18s linear;
  transform-style: preserve-3d; backface-visibility: hidden;
  opacity: calc(.6 + .4 * var(--land-depth));
}
.land-shots.is-trio .land-shot-left {
  z-index: 1; justify-self: end; margin-right: -14%;
  transform: rotateX(calc(22deg * (1 - var(--land-depth)))) rotate(calc(-4deg * var(--land-depth) - 6deg * (1 - var(--land-depth)))) translateY(calc(9% + 8% * (1 - var(--land-depth)))) scale(calc(.92 + .04 * var(--land-depth)));
}
.land-shots.is-trio .land-shot-right {
  z-index: 1; justify-self: start; margin-left: -14%;
  transform: rotateX(calc(22deg * (1 - var(--land-depth)))) rotate(calc(4deg * var(--land-depth) + 6deg * (1 - var(--land-depth)))) translateY(calc(9% + 8% * (1 - var(--land-depth)))) scale(calc(.92 + .04 * var(--land-depth)));
}
.land-shots.is-trio .land-shot-centre {
  z-index: 3;
  transform: rotateX(calc(22deg * (1 - var(--land-depth)))) translateY(calc(6% * (1 - var(--land-depth)))) scale(calc(1.05 + .10 * var(--land-depth)));
  box-shadow: 0 30px 70px -20px rgba(0,0,0,.85), inset 0 0 0 1px rgba(0,0,0,.6);
}
/* the §37.32 two-frame rules must not touch the trio */
.land-shots.is-trio .land-shot + .land-shot { margin-left: 0; }
.land-shots.is-trio .land-shot-right { margin-left: -14%; }
/* The fan keeps its pose on hover; do not flatten the individual devices. */
.land-shots.is-trio.is-flat .land-shot, .land-shots.is-trio.is-flat:hover .land-shot { opacity: 1; }
.land-shots.is-trio.is-3d .land-shot { box-shadow: 0 24px 60px -20px rgba(0,0,0,.8), inset 0 0 0 1px rgba(0,0,0,.6); }
@media (prefers-reduced-motion: reduce) { .land-shots.is-trio .land-shot { transition: none; } }
/* the section after the hero must clear the bleed */
.land-hero.has-stage + .land-shots-note { position: relative; z-index: 1; margin-top: calc(var(--land-bleed, 5.5rem) + var(--s6) + 1rem); text-align: center; }
@media (min-width: 640px) { .land-hero.has-stage { --land-bleed: 8rem; } }
@media (min-width: 1024px) { .land-hero.has-stage { --land-bleed: 9rem; } .land-shots.is-trio { max-width: 60rem; margin-top: var(--s5); } .land-shots.is-trio .land-shot { max-width: 16rem; } }
/* the note sits in the page; it must inherit the bleed variable from the hero, which is its previous sibling, so declare it on both */
.land-shots-note { --land-bleed: 5.5rem; }
@media (min-width: 640px) { .land-shots-note { --land-bleed: 8rem; } }
@media (min-width: 1024px) { .land-shots-note { --land-bleed: 9rem; } }
@media (max-width: 479px) {
  .land-shots.is-trio { margin-top: var(--s6); }
  .land-shots.is-trio .land-shot { --frame-bezel: 5px; --frame-r: 30px; --frame-r-in: 25px; }
  .land-shots.is-trio .land-shot-left { margin-right: -30%; }
  .land-shots.is-trio .land-shot-right { margin-left: -30%; }
}

/* DESKTOP SECTION BAR (≥1024): a row above the eyebrow, inside the hero, that
   links the sections this page already has. Not the app's topbar (Second
   Designer owns .navcapsule / .glass this round) — it lives in the landing
   markup only. Below 1024 it is not rendered visible; the sticky topbar's
   Log in / Join free already cover the two actions on a phone. */
.land-nav { display: none; }
@media (min-width: 1024px) {
  .land-nav {
    display: flex; align-items: center; justify-content: center; gap: var(--s2);
    margin: 0 auto var(--s6); padding: var(--s1); max-width: 46rem;
    border-radius: 999px; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.12);
    backdrop-filter: blur(10px);
  }
  .land-nav a, .land-nav .land-nav-login {
    min-height: 44px; display: inline-flex; align-items: center; padding: 0 var(--s4);
    border-radius: 999px; font-size: 14px; font-weight: 650; color: #B4B7BE; text-decoration: none; background: none; border: 0; cursor: pointer;
  }
  .land-nav a:hover, .land-nav .land-nav-login:hover { color: #F4F4F5; background: rgba(255,255,255,.06); }
  .land-nav .land-nav-login { margin-left: auto; }
  .land-nav .land-nav-cta { min-height: 44px; padding: 0 var(--s5); border-radius: 999px; font-size: 14px; font-weight: 750; }

  /* ONE sign-in entry per viewport (Tech Lead 3815074). At ≥1024 the section
     bar above carries Log in · Get started, so the sticky topbar's logged-out
     pair (Log in · Join free) would sit one line above it — two ways in, two
     labels. Rule: on the landing route at ≥1024 the topbar keeps the brand
     only; the hero bar owns the auth links. Below 1024 .land-nav is
     display:none and the topbar pair stays exactly as today.
     Scope = the landing route, read from the DOM: .land-hero is rendered by
     VIEWS.home and nowhere else, so #app:has(.land-hero) IS "the landing
     route" without a body class or a JS branch. The pair is picked by shape,
     not by label: the logged-out .tb-cta buttons are the only ones in
     .tb-tools with no aria-label (Check in carries one), so a logged-in
     visitor who lands on / via "Back to base" keeps Check in + avatar.
     Same :has() mechanism as §37.x #app:has(.navdock); where :has() is
     unsupported the bar simply shows both pairs, which is today's state. */
  #app.pg-app-land-hero-9fd1 header.glass .tb-tools > .tb-cta:not([aria-label]) { display: none; }
}
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
/* ── 37.34 DOCK LOWERED + 54 PX CAPSULE (DS11 round 4, Reqwa 06:08 UTC "lower the
   navigation bar a bit along with its overhaul"; 05:48 "sometimes too high" — the
   zoom lock in §37.33 removed the pinch cause, this is the resting position).
   One token, --dock-gap, is the space under the capsule: .2rem above the home
   indicator where there is one, .45rem where safe-area-inset-bottom is 0 (older
   Android, desktop emulation). No UA sniff — max() picks the branch from env()
   itself; the @supports guard keeps a plain calc() fallback for engines without
   max(). --dock-h is the capsule's border-box height (46 px tabs + 3 px padding
   × 2 + 1 px border × 2 = 54, Reqwa's iOS 26/27 reference is a slimmer bar; the
   tab hit area stays ≥ 44). Everything anchored above the dock (a2hs, consumer
   notice, toast, install banner, ladder "you" dock, coach composer, footer) is
   re-expressed against the two tokens so it moves WITH the dock and the gap
   between them stays what it was. QA check 6 (rows ≥ 56) does not fire on the
   tabs: a tab is ~63 px wide, a "row" is ≥ 80 % of the viewport. ── */
:root { --dock-gap: calc(.45rem + env(safe-area-inset-bottom, 0px)); --dock-h: 54px; }
@supports (padding-bottom: max(0px, 1px)) {
  :root { --dock-gap: max(.45rem, calc(.2rem + env(safe-area-inset-bottom, 0px))); }
}
.navdock { padding-bottom: var(--dock-gap); }
.navtab { height: 46px; }
.navfab { flex: 0 0 46px; width: 46px; height: 46px; }
.navcapsule { padding: 3px .34rem; }
.navpill { top: 4px; height: 44px; }
@media (max-width: 767px) {
  .a2hs { bottom: calc(var(--dock-gap) + var(--dock-h) + 1.4rem); }
  .consumer-notice { bottom: calc(var(--dock-gap) + var(--dock-h) + 1.2rem); }
  .toast-root, .install-banner { bottom: calc(var(--dock-gap) + var(--dock-h) + .9rem); }
  .rk-me-dock { bottom: calc(var(--dock-gap) + var(--dock-h) + 1rem); }
  .chat-dock { bottom: calc(var(--dock-gap) + var(--dock-h) + .1rem); }
  #app.pg-app-navdock-0aa8 > .app-footer { padding-bottom: calc(var(--dock-gap) + var(--dock-h) + 2rem); }
  .pb-safe, main.page-rise { padding-bottom: calc(var(--dock-gap) + var(--dock-h) + 2.7rem); }
}

/* ── 37.35 DS12 ROLL IQ READ v2 (numbered .35: DS11 took .34 the same night) (Round 5, Tech Lead 3818899 / 3819863 — Reqwa's
   verdict on his first real read). The rating is a LESSON: six axes always,
   evidence under each, technique names and timestamps as ACCENT ANCHORS into
   the library and the clip, a control graph, and the lesson as three cards.
   "Why isn't the text lime": the accent goes on anchors and technique names;
   body copy stays ink. In light mode the §29.4 rule holds — lime is a fill, so
   chips keep a lime plate with dark ink and bare timestamps fall back to the
   page ink with the accent underline. Tokens only; 8-pt rhythm; 44 px targets
   on every anchor via the ::before hit box (same trick as .btn-sm §37.5). ── */

/* six axes, ONE column (style.css .is-grid was 2 cols of l/v/bar cells — an
   evidence line under each row needs the width; the 2-col shape stays on the
   share card). Row = label · value · bar, then the evidence line spanning. */
.rl-sc-axes.is-grid.is-v2 { grid-template-columns: minmax(0, 1fr); gap: var(--s2); }
.rl-sc-axes.is-grid.is-v2 .rl-sc-axis { grid-template-columns: 7.2rem minmax(0, 1fr) 2.6rem; grid-template-areas: "l bar v" "ev ev ev"; gap: 0 var(--s3); min-height: 32px; align-content: center; }
.rl-sc-axes.is-grid.is-v2 .rl-sc-axis-l { grid-area: l; }
.rl-sc-axes.is-grid.is-v2 .rl-sc-axis-v { grid-area: v; font-size: 15px; }
.rl-sc-axes.is-grid.is-v2 .rl-sc-bar { grid-area: bar; height: 6px; align-self: center; }
.rl-sc-axes.is-grid.is-v2 .rl-sc-ev { grid-area: ev; }
.rl-sc-axes.is-grid.is-v2 .rl-sc-axis.is-null { grid-template-columns: 7.2rem minmax(0, 1fr); grid-template-areas: "l v"; min-height: 32px; opacity: .72; }
.rl-sc-axis-none { font-size: 12px; font-weight: 600; letter-spacing: 0; text-transform: none; text-align: right; color: var(--txt-3); font-variant-numeric: normal; }
.rl-sc-axes.is-grid.is-v2 .rl-sc-axis.is-null .rl-sc-axis-l, .rl-sc-axes.is-grid.is-v2 .rl-sc-axis.is-null .rl-sc-axis-v { color: var(--txt-3); }
/* evidence — one line collapsed, tap to expand; spans the full row */
.rl-sc-ev {
  grid-column: 1 / -1; display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s2); width: 100%;
  margin: 2px 0 var(--s1); padding: 0; min-height: 28px; border: 0; background: none; text-align: left; cursor: pointer;
  color: var(--txt-2); font: inherit; font-size: 13px; line-height: 1.45; position: relative;
}
.rl-sc-ev::before { content: ''; position: absolute; inset: -8px 0; }
.rl-sc-ev-t { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1 1 auto; line-height: 24px; }  /* collapsed = one line ellipsised (nowrap, not -webkit-box: the clamp broke inline chips into box items) */
.rl-sc-ev-i { display: inline; }
.rl-sc-ev-t .rl-tech, .rl-sc-ev-t .rl-ts { font-size: 12px; min-height: 20px; padding-top: 0; padding-bottom: 0; }
.rl-sc-ev i { flex: 0 0 auto; }
.rl-sc-ev.is-open .rl-sc-ev-t { white-space: normal; line-height: 1.45; }
.rl-sc-ev i { font-size: 10px; margin-top: 5px; color: var(--txt-3); transition: transform .18s ease; }
.rl-sc-ev.is-open i { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .rl-sc-ev i { transition: none; } }

/* anchors: technique chips + timestamps */
.rl-tech {
  display: inline-flex; align-items: center; gap: 5px; vertical-align: baseline; position: relative;
  margin: 0 1px; padding: 1px 9px 1px 7px; min-height: 24px; border-radius: var(--r-ctl);
  background: var(--accent-weak); border: 1px solid transparent; color: var(--txt-1);
  font: inherit; font-size: .92em; font-weight: 750; line-height: 1.35; cursor: pointer; text-decoration: none;
}
.rl-tech::before { content: ''; position: absolute; inset: -10px -4px; }
.rl-tech i { font-size: 10px; opacity: .85; }
.rl-tech:hover { background: var(--accent-fill); color: var(--accent-on); }
.rl-ts {
  display: inline-flex; align-items: center; gap: 4px; vertical-align: baseline; position: relative;
  padding: 0 2px; border: 0; background: none; font: inherit; font-weight: 750; color: var(--txt-1);
  text-decoration: underline; text-decoration-color: var(--accent-ink); text-decoration-thickness: 1.5px; text-underline-offset: 3px; cursor: pointer;
}
.rl-ts::before { content: ''; position: absolute; inset: -10px -6px; }
.rl-ts.is-static { cursor: default; text-decoration: none; }
.rl-ts i { font-size: 9px; }
/* the phase / moment timestamps keep their pill look, now in the accent */
.rl-detail .rl-phase-ts, .rl-detail .rl-moment-ts {
  border-radius: var(--r-inner); background: var(--raised); border: 1px solid var(--line); padding: .22rem .55rem; text-decoration: none;
  font-size: 12px; min-height: 28px;
}
.rl-detail .rl-phase-ts.is-static, .rl-detail .rl-moment-ts.is-static { color: var(--txt-3); }
.rl-moment .rl-moment-ts { align-self: start; }
/* light: lime is a fill, never type (§29.4) */
html[data-theme="light"] .rl-tech { background: var(--accent-fill); color: var(--accent-on); border-color: transparent; }
html[data-theme="light"] .rl-tech:hover { background: var(--txt-1); color: var(--card); }
html[data-theme="light"] .rl-ts { color: var(--txt-1); text-decoration-color: var(--accent-fill); text-decoration-thickness: 2px; }
html[data-theme="light"] .rl-detail .rl-phase-ts:not(.is-static), html[data-theme="light"] .rl-detail .rl-moment-ts:not(.is-static) { border-color: var(--accent-fill); box-shadow: inset 0 -2px 0 var(--accent-fill); }

/* control graph */
.rl-ctl { margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid var(--line); position: relative; }
.rl-ctl-h { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s2); }
.rl-ctl-legend { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; color: var(--txt-3); }
.rl-ctl-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; }
.rl-ctl-legend i.is-you { background: var(--accent-fill); }
.rl-ctl-legend i.is-them { background: var(--txt-3); margin-left: var(--s2); }
.rl-ctl-svg { display: block; width: 100%; height: 84px; border-radius: var(--r-inner); background: var(--sunken); border: 1px solid var(--line); }
.rl-ctl-fill { fill: var(--accent-weak); }
.rl-ctl-zero { stroke: var(--line-2); stroke-width: 1; stroke-dasharray: 3 4; }
.rl-ctl-tick { stroke: var(--line); stroke-width: 1; }
.rl-ctl-line { fill: none; stroke: var(--accent-fill); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.rl-ctl-dot { fill: var(--accent-fill); stroke: var(--card); stroke-width: 2; }
.rl-ctl-dot.is-low { fill: var(--card); stroke: var(--accent-fill); stroke-dasharray: 2 2; }
.rl-ctl-hits { position: absolute; left: 0; right: 0; top: calc(var(--s4) + 1px + 24px + var(--s2)); height: 84px; }
.rl-ctl-hit { position: absolute; top: 0; height: 100%; margin: 0; padding: 0; border: 0; background: transparent; cursor: pointer; border-radius: 0; }
.rl-ctl-hit:hover { background: var(--accent-weak); }
.rl-ctl-note { margin: var(--s2) 0 0; font-size: 12px; line-height: 1.45; color: var(--txt-3); display: flex; gap: 6px; align-items: baseline; }
.rl-ctl-note i { font-size: 9px; color: var(--txt-1); }
html[data-theme="light"] .rl-ctl-note i { color: var(--txt-2); }
html[data-theme="light"] .rl-ctl-line { stroke: var(--txt-1); }
html[data-theme="light"] .rl-ctl-dot { fill: var(--txt-1); }
html[data-theme="light"] .rl-ctl-dot.is-low { fill: var(--card); stroke: var(--txt-1); }
html[data-theme="light"] .rl-ctl-legend i.is-you { background: var(--txt-1); }

/* the read: phases first, then the lesson as three cards */
.rl-phases.is-v2 .rl-phase-h { align-items: center; }
.rl-phase-low { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; font-size: 11px; font-weight: 600; color: var(--txt-3); white-space: nowrap; }
.rl-phase-low i { font-size: 8px; color: var(--txt-1); }
html[data-theme="light"] .rl-phase-low i { color: var(--txt-2); }
.rl-phase.is-low .rl-phase-t { color: var(--txt-2); }
.rl-lesson { display: grid; gap: var(--s3); margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid var(--line); }
.rl-read .rl-lesson .rl-sec { margin-top: 0; display: grid; grid-template-columns: 1fr; gap: var(--s2); }
.rl-lesson .rl-sec-k { display: inline-flex; align-items: center; gap: var(--s2); color: var(--txt-2); }
.rl-sec-ico { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-inner); background: var(--accent-weak); color: var(--txt-1); }
.rl-sec-ico i { font-size: 12px; color: inherit; }
.rl-lesson .rl-sec.is-root_cause .rl-sec-ico { background: var(--accent-fill); color: var(--accent-on); }
html[data-theme="light"] .rl-sec-ico { background: var(--sunken); color: var(--txt-1); }
html[data-theme="light"] .rl-lesson .rl-sec.is-root_cause .rl-sec-ico { background: var(--accent-fill); color: var(--accent-on); }
.rl-lesson .rl-sec-t { margin: 0; font-weight: 600; font-size: var(--t-body); line-height: 1.5; color: var(--txt-1); }
.rl-lesson .rl-sec.is-cue .rl-sec-t { font-size: var(--t-card); font-weight: 800; letter-spacing: -.01em; }

/* share sheet: the square card at full width (5e), not a phone mock */
.rc-preview { height: auto; aspect-ratio: 1 / 1; width: 100%; max-width: 100%; border-radius: var(--r-inner); border: 0; background: transparent; object-fit: contain; }
.rc-frame .rc-stage { margin-top: var(--s3); }

@media (max-width: 359px) {
  .rl-sc-axes.is-grid.is-v2 .rl-sc-axis { grid-template-columns: 6rem minmax(0, 1fr) 2.4rem; }
  .rl-sc-axes.is-grid.is-v2 .rl-sc-axis.is-null { grid-template-columns: 6rem minmax(0, 1fr); }
  .rl-phase-low { margin-left: 0; flex-basis: 100%; }
}

/* ── 37.36 DS13 (Round 6, Tech Lead 3823319). Two light passes, tokens only. ── */
/* a. Plan feature lists — the caps now read "24 minutes a day, up to 5 minutes a
   clip"; at 390 the rail card wrapped that as "24 minutes a / day". Balanced
   wrapping keeps the figure with its unit. No copy, no widths changed. */
.land-plan-feats li, .tier-feats li, .pw-feats li, .ob-offer-feats li { text-wrap: pretty; }
/* b. The Corner (Competitive) transcript — four-part findings. Part markers are
   small numbered plates; scoreboard arithmetic, clocks and clause references
   are tabular so "2 for the sweep, 3 for the pass = 5–0" and "Art. 4.2.1" line
   up and read as figures, not prose. Ink stays --txt-*; the plate is the
   accent tint (a fill, so light mode needs no override). */
.corner-bub { color: var(--txt-1); }
.corner-part {
  display: inline-grid; place-items: center; width: 20px; height: 20px; margin: 0 4px 0 0; vertical-align: -4px;
  border-radius: 6px; background: var(--accent-weak); color: var(--txt-1); font-size: 11px; font-weight: 800; line-height: 1;
}
.corner-fig { font-weight: 750; color: var(--txt-1); letter-spacing: -.005em; white-space: nowrap; }
.corner-bub b { color: var(--txt-1); }
.corner-bub br + .corner-part { margin-top: var(--s2); }

/* DS14 / 4 — app hierarchy follows the same DS6 geometry, not a parallel kit.
   Do not alter DS11 capsule height/drag/hit geometry or semantic inks. */
.ra.rl .page-title, .tiers .page-title { font-size: var(--t-title); line-height: 1.15; }
.me-hero, .story-hero { border-color: var(--line-2); }
.me-kpis, .story-cells { gap: var(--s2); }
.tiers-controls { gap: var(--s3); margin-bottom: var(--s5); }
.rl-detail .rl-read { line-height: 1.6; }
.rl-detail-head { margin-bottom: var(--s4); }
.billing .acct-row { padding-block: var(--s3); }

/* ── 37.37 DS14 / 1 — one photographic stage, one machined device family.
   Geometry scales with the device, not viewport breakpoints: the old fixed
   30px corner swallowed the 110px phone. Real 3× UI captures remain intact.
   Fixed dark material values inherit the DS10 stage, not a new theme palette. */
.land-hero.has-stage { --land-bleed: 2rem; padding-top: var(--s7); }
.land-stage img { filter: brightness(.32) saturate(.8); }
.land-stage::before {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: url('/static/img/hero/grain.svg') repeat; opacity: .14;
}
.land-stage::after {
  background: radial-gradient(ellipse at 50% 83%, rgba(255,255,255,.09), transparent 55%),
    linear-gradient(180deg, rgba(10,10,12,.72), rgba(10,10,12,.3) 55%, #0A0A0C 100%);
}
.has-stage .land-h1 { text-wrap: balance; }
.has-stage .land-sub { text-wrap: pretty; }
.land-shots.is-trio {
  display: flex; align-items: center; justify-content: center;
  max-width: 48rem; padding: 0; margin: var(--s7) auto 0;
  transform: translateY(var(--land-bleed)); perspective: 1400px;
}
html .land-shots.is-trio .land-shot {
  --device-width: clamp(8rem, 41vw, 18rem);
  width: var(--device-width); max-width: none; flex: 0 0 var(--device-width);
  /* One physical inset/radius pair: concentric glass and chassis at every size. */
  --device-inset: calc(var(--device-width) * .022);
  --device-radius: calc(var(--device-width) * .155);
  aspect-ratio: 1 / 2.13; padding: 0; border-radius: var(--device-radius);
  position: relative; overflow: visible; margin: 0; opacity: 1;
  background: linear-gradient(125deg, #8A8F98 0%, #1A1B1F 13%, #0A0A0C 54%, #55585E 100%);
  border: .6px solid rgba(255,255,255,.32);
  box-shadow: 0 32px 38px -14px rgba(0,0,0,.8), 0 8px 10px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.12);
  transition: none; transform-style: flat;
}
.land-device-screen {
  position: absolute; inset: var(--device-inset); overflow: hidden;
  border: 0; border-radius: calc(var(--device-radius) - var(--device-inset));
  background: linear-gradient(#1A1B1F, #0A0A0C 9%); display: block;
}
.land-device-screen img {
  display: block; position: absolute; top: 8%; left: 0;
  width: 100%; height: 88%; object-fit: fill; object-position: top;
  border-radius: 0; aspect-ratio: auto; background: transparent;
}
html .land-shots.is-trio .land-shot::before {
  content: none;
}
.land-device-island {
  position: absolute; top: 1.8%; left: 50%; transform: translateX(-50%);
  width: 29%; height: 3.5%; border-radius: 999px; background: #000;
  box-shadow: 0 0 0 .5px rgba(255,255,255,.08); z-index: 4;
}
.land-device-island::after {
  content: ''; position: absolute; right: 10%; top: 25%; height: 50%;
  aspect-ratio: 1; border-radius: 50%; background: #11151E;
  box-shadow: inset 0 0 0 .5px rgba(255,255,255,.06);
}
.land-device-screen::after {
  content: ''; position: absolute; bottom: 1.2%; left: 34%; width: 32%;
  height: .55%; border-radius: 999px; background: rgba(255,255,255,.7);
}
html .land-shots.is-trio .land-shot::after {
  content: ''; display: block; position: absolute; top: 24%; right: -2px; left: auto;
  width: 2px; height: 13%; border-radius: 0 2px 2px 0;
  background: linear-gradient(#8A8F98, #1A1B1F); box-shadow: none;
}
.land-device-keys { position: absolute; left: -2px; top: 18%; width: 2px; height: 5%; background: var(--frame-rim); border-radius: 2px 0 0 2px; }
.land-device-keys::before, .land-device-keys::after { content: ''; position: absolute; left: 0; width: 2px; height: 150%; background: var(--frame-rim); border-radius: inherit; }
.land-device-keys::before { top: 155%; }
.land-device-keys::after { top: 345%; }
html .land-shots.is-trio .land-shot-left { margin-right: -24%; transform: perspective(1000px) translateY(7%) rotateY(18deg) rotate(-8deg) scale(.88); z-index: 1; }
html .land-shots.is-trio .land-shot.land-shot-right { margin-left: -24%; transform: perspective(1000px) translateY(7%) rotateY(-18deg) rotate(8deg) scale(.88); z-index: 1; }
html .land-shots.is-trio .land-shot-centre { transform: perspective(1000px) translateY(-2%) rotateX(3deg); z-index: 3; }
.land-shots.is-trio .land-shot-left .land-device-screen,
.land-shots.is-trio .land-shot-right .land-device-screen { filter: brightness(.8); }
html .land-hero.has-stage + .land-shots-note { --land-bleed: 2rem; margin-top: calc(var(--land-bleed) + var(--s7)); }
@media (min-width: 768px) {
  .land-shots.is-trio { margin-top: var(--s5); }
  html .land-shots.is-trio .land-shot-left { margin-right: -8%; }
  html .land-shots.is-trio .land-shot.land-shot-right { margin-left: -8%; }
}
/* One short compositor-only entrance on desktop and mobile; never loop.
   Reduced motion shows the final fan. */
@keyframes land-fan-arrive {
  from { opacity: 0; transform: translateY(calc(var(--land-bleed) + 1rem)); }
  to { opacity: 1; transform: translateY(var(--land-bleed)); }
}
@media (prefers-reduced-motion: no-preference) {
  .land-shots.is-trio { animation: land-fan-arrive 1s cubic-bezier(.2,.7,.2,1) both; }
  html .land-shots.is-trio .land-shot-left { animation: land-device-left 1.3s cubic-bezier(.16,1,.3,1) both; }
  html .land-shots.is-trio .land-shot-right { animation: land-device-right 1.3s cubic-bezier(.16,1,.3,1) both; }
  html .land-shots.is-trio .land-shot-centre { animation: land-device-centre 1.1s cubic-bezier(.16,1,.3,1) both; }
}
@keyframes land-device-left { from { transform: perspective(1000px) translate(12%,20%) rotateY(40deg) rotate(-14deg) scale(.82); } }
@keyframes land-device-right { from { transform: perspective(1000px) translate(-12%,20%) rotateY(-40deg) rotate(14deg) scale(.82); } }
@keyframes land-device-centre { from { transform: perspective(1000px) translateY(12%) rotateX(24deg) scale(.94); } }
/* Review corrections: keep the evidence in the first viewport. */
main.pg-main-land-hero-8a3f { padding-top: 0; }
.land-hero.has-stage { padding-top: var(--s5); --land-bleed: 1rem; }
.has-stage .land-h1 { margin-top: var(--s3); }
.has-stage .land-sub { margin-top: var(--s3); }
.has-stage .land-cta { margin-top: var(--s4); gap: var(--s2); }
.has-stage .land-fine { margin-top: var(--s2); }
.land-shots.is-trio { margin-top: var(--s5); }
.land-shots.is-trio .land-shot-left .land-device-screen,
.land-shots.is-trio .land-shot-right .land-device-screen { filter: brightness(.86); }
html .land-shots.is-trio .land-shot-left,
html .land-shots.is-trio .land-shot-right { border-color: rgba(255,255,255,.42); }
/* Only landing chrome adopts the fixed DS10 dark stage, not app chrome. */
html #app.pg-app-land-hero-9fd1 header.glass { background: #0A0A0C; border-bottom-color: rgba(255,255,255,.1); color: #F4F4F5; }
html #app.pg-app-land-hero-9fd1 header.glass .brand-name,
html #app.pg-app-land-hero-9fd1 header.glass .tb-cta:not(.btn-primary) { color: #F4F4F5; }
@media (min-width: 1024px) {
  .land-nav { margin-bottom: var(--s4); }
  .has-stage .land-h1 { max-width: 20ch; font-size: clamp(3rem,4.5vw,4rem); }
  .has-stage .land-sub { max-width: 38rem; }
  html .land-shots.is-trio .land-shot { --device-width: 14rem; }
}

/* Reqwa review: floating navigation, not an edge-to-edge rectangular band.
   Theme selection is untouched. The landing alone shares DS10's dark chrome. */
html header.glass {
  top: var(--s2); margin: var(--s2) var(--gutter) 0;
  width: calc(100% - 2 * var(--gutter)); max-width: 72rem;
  border: 1px solid var(--line-2); border-radius: var(--r-card);
  box-shadow: var(--lift-1); background: var(--card);
}
html header.glass .tb-row { padding-inline: var(--s3); }
html #app.pg-app-land-hero-9fd1 header.glass { border-color: rgba(255,255,255,.16); }
html #app.pg-app-land-hero-9fd1 header.glass .tb-title,
html #app.pg-app-land-hero-9fd1 header.glass .tb-kicker { color: #F4F4F5; }
html #app.pg-app-land-hero-9fd1 { background: #0A0A0C; }
html #app.pg-app-land-hero-9fd1 main { background: var(--ground); }
/* Replace the photographic seam with a continuous, textured studio ground.
   The existing photo stays available; no new image payload or external asset. */
.land-stage img { opacity: .18; filter: grayscale(1) brightness(.45); }
.land-stage::after { background: radial-gradient(ellipse at 50% 78%,rgba(255,255,255,.07),transparent 62%),linear-gradient(180deg,#0A0A0C 0%,rgba(10,10,12,.5) 42%,#0A0A0C 88%); }
.land-hero.has-stage { padding-bottom: var(--s7); --land-bleed: 0rem; border-radius: 0 0 var(--s6) var(--s6); overflow: hidden; }
html .land-hero.has-stage + .land-shots-note { margin-top: var(--s5); }
/* Utility glyphs are ink; status is communicated by text and shape as well.
   Keep --good itself unchanged for real success states elsewhere. */
main.pg-main-rank-hero-f587 .obj-ico,
main.pg-main-rank-hero-f587 .obj-ico i,
main.pg-main-rank-hero-f587 .fa-lightbulb,
main.pg-main-rank-hero-f587 .dtile > i:not(.dtile-lock) { color: var(--txt-2); }
main.pg-main-rank-hero-f587 .obj-ico { background: var(--raised); }
@media(min-width:1200px) { html header.glass { margin-inline: auto; } }
html #app.pg-app-land-hero-9fd1 header.glass .logo-mark { filter: none; }
@media(min-width:1024px) { html #app.pg-app-land-hero-9fd1 header.glass { display: none; } }
/* No landing navigation. DS16 owns signed-in header geometry; retired
   Home-only 44px circle rules must not compete with its 56px header row. */
html #app.pg-app-land-hero-9fd1 header.glass, .land-nav { display: none; }

/* DS14 1c: stock WithFrame iPhone 15 Pro artwork, not drawn hardware.
   Keep the established layout box and motion; the source's native aspect is
   centred inside it without stretching. One portrait asset serves all poses. */
html .land-shots.is-trio .land-shot {
  background: transparent; border: 0; box-shadow: none;
}
html .land-shots.is-trio .land-shot::before,
html .land-shots.is-trio .land-shot::after { content: none; display: none; }
.land-device-hardware {
  display: block; position: absolute; width: 100%; aspect-ratio: 1293 / 2656;
  left: 0; top: 50%; transform: translateY(-50%);
  filter: drop-shadow(0 18px 16px rgba(0,0,0,.6));
}
/* Source screen: x58..1236, y50..2605 of 1293×2656, corner radius 164px.
   Inset under the opaque glass edge to avoid a bright seam at fractional DPR. */
.land-device-hardware .land-device-screen {
  inset: 1.883% 4.409%; border: 0; border-radius: 13.91% / 6.42%;
}
html .land-shot img.land-device-frame {
  position: absolute; inset: 0; display: block; width: 100%; height: 100%;
  aspect-ratio: 1293 / 2656; object-fit: contain; border-radius: 0;
  background: transparent; z-index: 5; pointer-events: none;
}

/* §38 DS15 / 1 — the paid read as a field notebook. Existing data, order and
   anchors; stronger section rhythm without turning prose into accent ink. */
.rl-detail { max-width: 52rem; }
.rl-detail .rl-scorecard { border-color: var(--line-2); box-shadow: var(--lift-1); }
.rl-scorecard .rl-sc-top { grid-template-columns: auto minmax(0, 1fr); gap: var(--s5); align-items: center; }
.rl-scorecard .rl-sc-num { font-size: calc(var(--t-figure) + var(--s5)); line-height: 1; }
.rl-scorecard .rl-sc-sub { font-size: 14px; line-height: 1.55; max-width: 32ch; }
.rl-scorecard .rl-sc-seg { margin-block: var(--s5); gap: var(--s1); }
.rl-scorecard .rl-sc-axes.is-grid.is-v2 { gap: 0; padding-top: var(--s4); }
.rl-scorecard .rl-sc-axes-h { margin-bottom: var(--s3); }
.rl-scorecard .rl-sc-axes.is-grid.is-v2 .rl-sc-axis { padding-block: var(--s3); border-top: 1px solid var(--line); min-height: var(--ctl-h); }
.rl-scorecard .rl-sc-axes.is-grid.is-v2 .rl-sc-axis.is-null { opacity: 1; }
.rl-scorecard .rl-sc-axis-l { letter-spacing: .025em; }
.rl-scorecard .rl-sc-axis-v { font-weight: 800; }
.rl-scorecard .rl-sc-axis-none { font-weight: 500; }
.rl-scorecard .rl-sc-ev { margin: var(--s2) 0 0; min-height: var(--ctl-h-sm); align-items: center; }
.rl-scorecard .rl-sc-ev::before { content: none; }
.rl-scorecard .rl-sc-ev-t { line-height: 1.6; }
.rl-scorecard .rl-sc-ev.is-open { padding: var(--s3); border-radius: var(--r-inner); background: var(--sunken); }
.rl-scorecard .rl-sc-ev i { margin-top: 0; }
.rl-detail .rl-read { margin-top: var(--s5); }
.rl-detail .rl-read-head { margin-bottom: var(--s4); }
.rl-detail .rl-phases.is-v2 { gap: var(--s3); }
.rl-detail .rl-phases.is-v2 .rl-phase { padding: var(--s4); border: 1px solid var(--line); border-radius: var(--r-inner); background: var(--sunken); }
.rl-detail .rl-phase-h { gap: var(--s2) var(--s3); }
.rl-detail .rl-phase-p { margin-top: var(--s3); line-height: 1.7; }
.rl-detail .rl-phase.is-low { border-inline-start: var(--s1) solid var(--line-2); }
.rl-detail .rl-phase-low { margin-left: 0; padding: var(--s1) var(--s2); border: 1px dashed var(--line-2); border-radius: var(--r-inner); color: var(--txt-2); }
.rl-detail .rl-phase-low i { color: var(--txt-2); }
.rl-detail .rl-moments { margin-block: var(--s5); padding-block: var(--s4); border-bottom: 1px solid var(--line); }
.rl-detail .rl-moment.ra-demo-row { position: relative; padding: var(--s3) 0; align-items: start; }
.rl-detail .rl-moment-t { line-height: 1.7; }
.rl-detail .rl-moment:not(:last-child)::after { content: ''; position: absolute; top: calc(var(--ctl-h-sm) + var(--s3)); bottom: 0; left: var(--s5); border-left: 1px solid var(--line-2); }
.rl-detail .rl-lesson { gap: var(--s3); padding-top: 0; border-top: 0; }
.rl-detail .rl-lesson .rl-sec { padding: var(--s5); background: var(--sunken); border-color: var(--line); }
.rl-detail .rl-lesson .rl-sec-k { color: var(--txt-2); }
.rl-detail .rl-lesson .rl-sec-ico { background: transparent; color: var(--txt-2); width: auto; height: auto; }
.rl-detail .rl-lesson .rl-sec-t { font-weight: 500; line-height: 1.7; }
.rl-detail .rl-lesson .rl-sec.is-cue { background: var(--raised); border-color: var(--line-2); }
.rl-detail .rl-lesson .rl-sec.is-cue .rl-sec-t { font-size: var(--t-title); line-height: 1.35; font-weight: 800; text-wrap: balance; }
.rl-detail .rl-nofootage { margin-block: var(--s4); background: transparent; }
@media (min-width: 1024px) {
  .rl-detail .rl-scorecard, .rl-detail .rl-read, .rl-detail .rl-chat { padding: var(--s6); }
  .rl-detail .rl-phase-p, .rl-detail .rl-sec-t { max-width: 66ch; }
  .rl-detail .rl-phase-low { margin-left: auto; }
}

/* §38.2 DS15 / 2 — Film Room is a shelf, not a pile of status badges.
   Status hooks only mirror server state. Shape + existing text carry meaning. */
.rl .rl-list { gap: var(--s3); }
.rl .rl-card { padding: var(--s4); gap: var(--s4); border-radius: var(--r-card); background: var(--card); border: 1px solid var(--line); box-shadow: var(--lift-1); align-items: center; }
.rl .rl-thumb { width: var(--ctl-h); height: var(--ctl-h); flex: 0 0 var(--ctl-h); border-radius: var(--r-inner); background: var(--sunken); color: var(--txt-2); border: 1px solid var(--line-2); }
.rl .rl-main { gap: var(--s2); }
.rl .rl-t { white-space: normal; line-height: 1.45; font-size: var(--t-card); text-wrap: pretty; }
.rl .rl-t .tnum { white-space: nowrap; font-size: 13px; font-weight: 500; color: var(--txt-3); }
.rl .rl-s { display: block; line-height: 1.65; font-size: 12px; }
.rl .rl-day { background: transparent; border: 0; padding: 0; align-self: start; color: var(--txt-3); font-size: var(--t-kicker); }
.rl-card[data-status="queued"] { border-inline-start: var(--s1) solid var(--line-2); }
.rl-card[data-status="queued"] .rl-thumb { border-style: dashed; }
.rl-card[data-status="running"] { border-inline-start: var(--s1) solid var(--txt-1); background: var(--raised); }
.rl-card[data-status="running"] .rl-thumb { border: 2px solid var(--txt-2); border-inline-end-style: dotted; }
.rl-card[data-status="running"] .rl-s { color: var(--txt-1); font-weight: 750; }
.rl-card[data-status="done"] .rl-thumb { background: var(--txt-1); color: var(--card); border-color: var(--txt-1); }
.rl-card[data-status="done"] .rl-s .tnum { font-weight: 800; font-size: var(--t-card); color: var(--txt-1); }
.rl-card[data-status="failed"] { border-inline-start: var(--s1) solid var(--danger-ink); }
.rl-card[data-status="failed"] .rl-thumb { color: var(--danger-ink); background: var(--sunken); }
.rl-card[data-cleared="true"] .rl-thumb { background: var(--sunken); color: var(--txt-3); border: 1px dashed var(--line-2); }
.rl-card[data-cleared="true"] .rl-cleared { display: inline-block; color: var(--txt-3); }
.rl .rl-empty { padding: var(--s6) var(--s5); text-align: left; align-items: start; border-color: var(--line-2); }
.rl .rl-empty .ra-drop-ico { margin: 0 0 var(--s5); color: var(--txt-2); }
.rl .rl-empty .ra-drop-t { font-size: var(--t-title); max-width: 20ch; line-height: 1.2; }
.rl .rl-empty .ra-drop-s { margin: var(--s3) 0 var(--s5); line-height: 1.7; max-width: 40ch; }
.rl .rl-empty-go { width: 100%; }
.ra-form .ra-steps { padding: var(--s3); border: 1px solid var(--line); border-radius: var(--r-card); background: var(--sunken); }
.ra-form .ra-step { padding-block: var(--s2); color: var(--txt-3); }
.ra-form .ra-step.is-now { color: var(--txt-1); font-weight: 800; }
.ra-form .ra-drop { padding: var(--s6) var(--s5); border-radius: var(--r-card); border-color: var(--line-2); background: var(--card); box-shadow: var(--lift-1); }
.ra-form .ra-drop-t { font-size: var(--t-title); line-height: 1.2; }
.ra-form .ra-drop-s { margin-top: var(--s3); line-height: 1.65; }
.ra-form .ra-trim { padding: var(--s4); border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); }
.ra-form .ra-trim-head { margin-bottom: var(--s4); }
.ra-form .ra-trim-foot { gap: var(--s2); margin-block: var(--s4); }
.ra-form .ra-prequeue { padding-top: var(--s5); margin-top: var(--s5); border-top: 1px solid var(--line); }
.ra-form .sl-group { padding: var(--s4); border: 1px solid var(--line); border-radius: var(--r-inner); background: var(--sunken); }
.ra .ra-status { line-height: 1.65; }
.ra .ra-status.is-queued { color: var(--txt-2); border-inline-start: var(--s1) solid var(--line-2); }
.ra .ra-status.is-running { color: var(--txt-1); border-inline-start: var(--s1) solid var(--txt-1); background: var(--raised); }
.ra .ra-status.is-failed, .ra .ra-status.is-err { border-inline-start: var(--s1) solid var(--danger-ink); }
.ra .ra-status.is-done { border-inline-start: var(--s1) solid var(--good); }

/* §38.3 DS15 / 3 — Home and Progress use the same outer card / inset cell.
   Figures stay paired with their existing units; no data or belt recoloring. */
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .card { border-color: var(--line); box-shadow: var(--lift-1); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) :is(#rank-hero, .story-hero) { padding: var(--s5); border: 1px solid var(--line-2); background: var(--card); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) :is(.stat-row, .story-cells) { gap: 0; border-radius: var(--r-inner); border: 1px solid var(--line); background: var(--sunken); overflow: hidden; }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .stat-cell { border: 0; border-radius: 0; background: transparent; padding: var(--s4) var(--s3); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .stat-cell + .stat-cell { border-inline-start: 1px solid var(--line); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) :is(.stat-cell-v, .story-iq-num) { font-variant-numeric: tabular-nums; letter-spacing: -.035em; color: var(--txt-1); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) :is(.stat-cell-suffix, .hero-unit) { margin-left: var(--s1); white-space: nowrap; font-size: 13px; color: var(--txt-2); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .stat-cell-l { letter-spacing: .04em; line-height: 1.5; }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .dest-grid { gap: var(--s3); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .dtile { padding: var(--s5) var(--s4); border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); align-items: start; text-align: left; box-shadow: var(--lift-1); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .dtile.is-key { border-color: var(--line-2); background: var(--raised); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .dtile > i:not(.dtile-lock) { color: var(--txt-2); margin-bottom: var(--s2); }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .dtile-l { font-size: var(--t-card); line-height: 1.25; }
main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) .dtile-d { font-size: 13px; line-height: 1.55; color: var(--txt-2); }
main.pg-main-rank-hero-f587 .rr-row { padding: var(--s4); border-radius: var(--r-card); box-shadow: var(--lift-1); }
main.pg-main-rank-hero-f587 .rr-thumb { width: var(--ctl-h); height: var(--ctl-h); flex-basis: var(--ctl-h); background: var(--sunken); border: 1px solid var(--line); }
main.pg-main-rank-hero-f587 .rr-t { white-space: normal; line-height: 1.45; }
main.pg-main-rank-hero-f587 .rr-s { line-height: 1.65; }
main.pg-main-gm-map-6af2 .gm-head { padding-bottom: var(--s4); border-bottom: 1px solid var(--line); margin-bottom: var(--s5); }
main.pg-main-gm-map-6af2 .gm-seg { padding: var(--s1); background: var(--sunken); border: 1px solid var(--line); }
main.pg-main-gm-map-6af2 .gm-seg .seg-btn.on { background: var(--card); box-shadow: var(--lift-1); color: var(--txt-1); }
main.pg-main-gm-map-6af2 svg[aria-label^="Game map:"] { background: var(--sunken); border: 1px solid var(--line); border-radius: var(--r-inner); }
main.pg-main-gm-map-6af2 :is(.bp-card, .tvn-entry, .gm-rank) { border-radius: var(--r-card); border-color: var(--line); box-shadow: var(--lift-1); }
main.pg-main-gm-map-6af2 .story-iq { padding-bottom: var(--s5); }
main.pg-main-gm-map-6af2 .story-iq-bar { margin-block: var(--s4); }

/* §38.4 DS15 / 4 — pricing family. The selected story is elevated by material,
   never a larger footprint. Renewal and exclusions remain in reading order. */
.tiers .tiers-head { margin-bottom: var(--s5); }
.tiers .tiers-controls { padding: var(--s3); background: var(--sunken); border: 1px solid var(--line); border-radius: var(--r-card); }
.tiers .tiers-seg { background: transparent; }
.tiers .tiers-list { gap: var(--s4); align-items: stretch; }
.tiers .plan-card.tier { padding: var(--s5); border-radius: var(--r-card); border: 1px solid var(--line); background: var(--card); box-shadow: var(--lift-1); transform: none; }
.tiers .plan-card.tier.is-hero { padding: var(--s5); border-color: var(--line-2); background: var(--raised); box-shadow: var(--lift-2); transform: none; }
.tiers .tier-head { padding-bottom: var(--s4); border-bottom: 1px solid var(--line); }
.tiers .tier-name { font-size: var(--t-card); letter-spacing: -.01em; gap: var(--s2); }
.tiers .tier-price { margin-top: var(--s4); align-items: baseline; gap: var(--s1); }
.tiers .tier-price .pp-amt { font-size: var(--t-figure); font-weight: 800; letter-spacing: -.035em; line-height: 1.1; }
.tiers .tier-price .pp-per { font-size: 14px; color: var(--txt-2); white-space: nowrap; }
.tiers .tier-tag { font-size: var(--t-card); line-height: 1.5; margin-block: var(--s4); color: var(--txt-1); }
.tiers .tier-flag { position: static; align-self: start; margin: 0 0 var(--s4); border-radius: var(--r-ctl); }
.tiers .tier-headline { padding: var(--s4); border-radius: var(--r-inner); background: var(--sunken); border: 1px solid var(--line); }
.tiers .tier-headline-t { line-height: 1.6; }
.tiers .tier-feats { gap: 0; margin-block: var(--s4); }
.tiers .tier-feats li { padding-block: var(--s3); align-items: baseline; gap: var(--s3); line-height: 1.6; }
.tiers .tier-feats li + li { border-top: 1px solid var(--line); }
.tiers .tier-feats li i { color: var(--txt-3); font-size: 12px; flex: 0 0 var(--s4); }
.tiers .tier-excl { padding-top: var(--s4); border-top: 1px solid var(--line); line-height: 1.6; }
.tiers .plan-fine { line-height: 1.6; color: var(--txt-2); }
.tiers .tier-go, .tiers .tier-cta { margin-top: auto; min-height: var(--ctl-h-lg); }
@media (min-width: 1024px) {
  .tiers .plan-card.tier, .tiers .plan-card.tier.is-hero { position: relative; padding: var(--s8) var(--s5) var(--s5); }
  .tiers .tier-flag { position: absolute; top: var(--s5); left: var(--s5); margin: 0; }
  .tiers .tier-head { min-height: 112px; }
}

/* §38.5 DS15 / 5 — inner-product motion: 120ms press / 180ms state / 200ms
   reveal. Landing/stock fan is locked and explicitly outside this scope. */
#app:not(.pg-app-land-hero-9fd1) { --dur-2: 180ms; --dur-3: 200ms; }
#app:not(.pg-app-land-hero-9fd1) main.page-rise { animation-duration: var(--dur-3); }
#app:not(.pg-app-land-hero-9fd1) :is(button, a, [role="button"], input, select, textarea) { transition-duration: var(--dur-1); transition-timing-function: var(--ease); }
#app:not(.pg-app-land-hero-9fd1) :is(button, a, [role="button"], input, select, textarea):focus-visible { outline: 2px solid var(--txt-1); outline-offset: var(--s1); }
#app:not(.pg-app-land-hero-9fd1) .input:focus-visible { border-color: var(--txt-2); box-shadow: 0 0 0 2px var(--card); }
.rl-detail .rl-tech, .rl-detail button.rl-ts, .rl-detail .rl-sc-ev-t .rl-tech, .rl-detail .rl-sc-ev-t button.rl-ts { min-height: var(--ctl-h-sm); min-width: var(--ctl-h-sm); align-items: center; }
.rl-detail .rl-tech::before, .rl-detail button.rl-ts::before { content: none; }
.rl-detail .rl-sc-ev-t { overflow-wrap: anywhere; }
.rl-detail .rl-sc-ev:not(.is-open) .rl-sc-ev-t { line-height: var(--ctl-h-sm); }
.ra .ra-swap { min-height: var(--ctl-h-sm); }
.break-all { word-break: break-all; }
/* Cascade parity with §29 light-mode neutralisation; no new palette. */
html[data-theme] .rl-card .rl-thumb { border-radius: var(--r-inner); }
html[data-theme] .rl-card[data-status="done"] .rl-thumb { background: var(--txt-1); color: var(--card); border: 1px solid var(--txt-1); }
html[data-theme] .rl-card[data-cleared="true"] .rl-thumb { background: var(--sunken); color: var(--txt-3); border: 1px dashed var(--line-2); }
html[data-theme] .rl-card[data-status="failed"] .rl-thumb { color: var(--danger-ink); }
.rl-detail .rl-phases.is-v2 .rl-phase.is-low { border-inline-start: var(--s1) solid var(--line-2); }
.tiers .plan-card.tier.current:not(.is-hero) { border-color: var(--line-2); }
html[data-theme] .tiers .tier-feats li i { color: var(--txt-3); }
@media (hover: hover) {
  main:is(.pg-main-rank-hero-f587, .pg-main-gm-map-6af2) :is(.dtile, button.stat-cell):hover { border-color: var(--line-2); background: var(--raised); }
}
@media (prefers-reduced-motion: reduce) {
  #app:not(.pg-app-land-hero-9fd1), #app:not(.pg-app-land-hero-9fd1) *, #app:not(.pg-app-land-hero-9fd1) *::before, #app:not(.pg-app-land-hero-9fd1) *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}

/* DS18 public landing only. Existing app, onboarding and pricing surfaces keep
   their own rules; this wrapper is rendered exclusively by VIEWS.home. */
.land-simple { min-width: 0; color: var(--txt-1); }
.land-simple .land-hero.has-stage { margin-inline: 0; width: 100%; padding: 1rem clamp(1rem, 4vw, 3rem) 3rem; border-radius: var(--radius-lg); }
.land-simple .land-simple-nav { position: relative; z-index: 1; display: flex; align-items: center; gap: 1rem; margin-bottom: clamp(2rem, 6vw, 4rem); text-align: left; }
.land-simple .land-wordmark { margin-right: auto; font-size: 15px; font-weight: 850; letter-spacing: -.03em; color: #f4f4f5; }
.land-simple .land-simple-nav a,
.land-simple .land-simple-nav .land-link { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; padding: .25rem; font-size: 14px; color: #e4e4e7; }
.land-simple .land-h1 { max-width: 19ch; font-size: clamp(2.1rem, 7vw, 4.25rem); line-height: 1.05; }
.land-simple .land-sub { max-width: 40rem; font-size: clamp(1rem, 2vw, 1.15rem); line-height: 1.6; }
.land-simple .land-cta { margin-top: 1.5rem; }
.land-simple .land-btn { min-height: 52px; max-width: 100%; }
.land-simple .land-hero .land-fine { max-width: 36rem; color: #c4c4cc; font-size: 14px; }
.land-simple .land-proof { margin: 1.5rem auto 0; max-width: 44rem; text-align: center; color: var(--txt-2); font-size: 14px; line-height: 1.6; }
.land-simple .land-proof strong { color: var(--txt-1); }
.land-simple .land-sec { padding-top: clamp(2.75rem, 6vw, 4.5rem); scroll-margin-top: 1.5rem; }
.land-simple .land-h2 { font-size: clamp(1.6rem, 4vw, 2.35rem); line-height: 1.15; }
.land-simple .land-process { list-style: none; counter-reset: land-step; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.5rem; padding: 0; margin: 1.5rem 0 0; }
.land-simple .land-process li { counter-increment: land-step; min-width: 0; border-top: 1px solid var(--line-2); padding-top: 1rem; }
.land-simple .land-process li::before { content: counter(land-step, decimal-leading-zero); display: block; margin-bottom: 1rem; color: var(--txt-2); font-size: 14px; font-variant-numeric: tabular-nums; }
.land-simple .land-process h3,
.land-simple .land-benefits dt { margin: 0; color: var(--txt-1); font-size: 18px; font-weight: 750; line-height: 1.35; }
.land-simple .land-process p,
.land-simple .land-benefits dd { margin: .65rem 0 0; color: var(--txt-2); font-size: 16px; line-height: 1.6; }
.land-simple .land-benefits { margin: 0; display: grid; gap: 1.5rem; }
.land-simple .land-benefits > div { padding-left: 1.25rem; border-left: 2px solid var(--line-2); }
.land-simple .land-plans { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); align-items: stretch; }
.land-simple .land-plan { min-width: 0; }
.land-simple .land-plan-price { white-space: normal; flex-wrap: wrap; }
.land-simple .land-plan-fig { overflow-wrap: anywhere; }
.land-simple .land-plan-feats li > span { min-width: 0; overflow-wrap: anywhere; }
.land-simple .land-plan-btn { margin-top: auto; min-height: 48px; }
.land-simple .land-plan-feats,
.land-simple .land-plan-excl { margin-bottom: 1.25rem; }
.land-simple .land-plan-tag,
.land-simple .land-plan-year,
.land-simple .land-plan-excl li,
.land-simple .land-fine-c { color: var(--txt-2); font-size: 14px; line-height: 1.6; }
.land-simple .land-plan-name,
.land-simple .land-plan-tag,
.land-simple .land-plan-excl li { overflow-wrap: anywhere; }
.land-simple .land-plan-unavailable { margin-top: 1.5rem; padding: 1.25rem; border: 1px solid var(--line-2); border-radius: var(--radius); color: var(--txt-2); }
.land-simple .land-plan-unavailable p { margin: 0 0 1rem; line-height: 1.6; }
.land-simple .land-plan-unavailable button { min-height: 44px; }
.land-simple .land-faq { margin-top: 1.5rem; border-bottom: 1px solid var(--line-2); }
.land-simple .land-faq details { border-top: 1px solid var(--line-2); }
.land-simple .land-faq summary { padding: 1.1rem .25rem; min-height: 56px; cursor: pointer; font-size: 16px; line-height: 1.5; font-weight: 650; color: var(--txt-1); }
.land-simple .land-faq p { max-width: 48rem; margin: 0; padding: 0 .25rem 1.25rem; font-size: 16px; line-height: 1.6; color: var(--txt-2); }
.land-simple .land-close { margin-top: clamp(2.75rem, 6vw, 4.5rem); padding: 2rem 1rem; border-top: 1px solid var(--line-2); }
.land-simple :is(a, button, summary):focus-visible { outline: 2px solid var(--txt-1); outline-offset: 4px; }
.land-simple .land-hero :is(a, button):focus-visible { outline-color: #f4f4f5; }
@media (max-width: 767px) {
  .land-simple .land-process { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
  .land-simple .land-process li { display: grid; grid-template-columns: 2rem minmax(0, 1fr); column-gap: .5rem; }
  .land-simple .land-process li::before { grid-row: span 2; margin: .2rem 0 0; }
  .land-simple .land-process p { grid-column: 2; }
}
@media (max-width: 899px) {
  .land-simple .land-plans { display: flex; align-items: stretch; gap: 1rem; }
  .land-simple .land-plan { flex: 0 0 min(88%, 22rem); padding: 1.25rem; }
  .land-simple .land-plans > .land-plan:only-child { flex-basis: 100%; }
}

/* DS23 visual geometry. Opt in at real page wrappers, never at :root or the
   auth/boot shell: the transparent DS20 loader and onboarding are independent. */
:is(#home-ds16, .film-ds17, .rl-detail, .progress-ds17, #coach-ds18, .me-ds17, .lk-simple, .land-simple) {
  --r-card: 22px; --r-inner: 16px; --r-ctl: 16px;
  --radius: 22px; --radius-sm: 16px; --radius-lg: 24px;
  --card-gap: 16px;
}
#app main :is(.rl-detail, .me-ds17, .lk-simple, .land-simple) :is(.card, .panel) { border-radius: 22px; }
#app main :is(#home-ds16, .film-ds17, .rl-detail, .progress-ds17, #coach-ds18, .me-ds17, .lk-simple, .land-simple) .btn { white-space: normal;
}
#app main :is(.rl-detail, #coach-ds18, .me-ds17, .lk-simple) :is(input:not([type="checkbox"]):not([type="radio"]):not([type="file"]), select, textarea) {
  font-size: 16px; border-radius: 16px;
}
#app main :is(.rl-detail, #coach-ds18, .me-ds17, .lk-simple, .land-simple) :is(button, a, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--txt-1); outline-offset: 3px;
}

/* Coach: rounded choice controls and draft chips, not unstructured text links. */
#coach-ds18 .coach-header { margin-bottom: 24px; }
#coach-ds18 .coach-context { gap: 8px; margin-bottom: 16px; }
#coach-ds18 .mode-switch { padding: 4px; gap: 4px; border-radius: 18px; }
#coach-ds18 .mode-pill { border-radius: 14px; }
#coach-ds18 .mode-pill.is-active { background: #232527; color: var(--txt-1); box-shadow: none; }
#coach-ds18 .mode-pill.is-active :is(i,.mode-lock) { color: inherit; }
#coach-ds18 .coach-library { padding-inline: 16px; border: 1px solid var(--line-2); border-radius: 14px; }
#coach-ds18 #chat-log .card { padding: 16px; border: 1px solid var(--line); border-radius: 22px; background: var(--card); }
#coach-ds18 #chat-log .ac-mine { background: var(--raised); }
#coach-ds18 .coach-prompts { gap: 8px; margin-bottom: 8px; }
#coach-ds18 .coach-prompts button { padding: 8px 16px; border: 1px solid var(--line-2); border-radius: 16px; background: var(--card); color: var(--txt-1); }
#coach-ds18 .coach-prompts button:is(:hover,:focus-visible) { background: #232527; color: var(--txt-1); }
#coach-ds18 #chat-form { gap: 8px; }
#coach-ds18 #chat-form .input { border-color: var(--line-2); }

/* Profile: one identity card and a grouped list, not a card for every row. */
#app .me-ds17 .me-identity { gap: 16px; padding: 16px; margin-bottom: 16px; border: 1px solid var(--line); border-radius: 24px; background: var(--card); }
#app .me-ds17 .me-list { border-radius: 22px; }
#app .me-ds17 .me-cap { padding-block: 16px; font-size: 12px; font-weight: 650; background: var(--sunken); }
#app .me-ds17 .me-list .me-row { gap: 16px; }
#app .me-ds17 .me-camera { background: #232527; color: var(--txt-1); border-color: var(--card); }
#app .me-ds17 .me-avatar:focus-within { outline-color: var(--txt-1); }
#app .me-ds17 .me-row:focus-visible { outline-offset: -3px; }
#app .me-ds17 .theme-seg { padding: 4px; gap: 4px; border-radius: 18px; }
#app .me-ds17 .theme-seg button { border-radius: 14px; }
#app .me-ds17 .theme-seg button.on { background: #232527; color: var(--txt-1); box-shadow: none; }
#app .me-ds17 .theme-seg button.on i { color: inherit; }
#app .me-ds17 .me-detail-note { line-height: 1.6; }

/* Lockers: ownership is a solid marker, unavailable states remain labelled. */
.lk-simple .lk-heading .page-title { font-size: clamp(32px, 5vw, 40px); line-height: 1.1; letter-spacing: -.04em; }
.lk-simple .lk-mine { padding: 24px; }
.lk-simple .lk-mine-num, .lk-simple .lk-cell.is-mine { background: #232527; color: var(--txt-1); border-color: #232527; }
.lk-simple .lk-cell.is-mine .lk-state { color: var(--ink-on-dark); }
.lk-simple .lk-cell { border-radius: 18px; }
.lk-simple .lk-cell.is-free:not(:disabled):is(:hover,:focus-visible) { background: #232527; color: var(--txt-1); }
.lk-simple .lk-cell.is-free:not(:disabled):is(:hover,:focus-visible) .lk-state { color: var(--ink-on-dark); }
.lk-simple .lk-mine > .btn { margin-top: 16px; }
.lk-simple .lk-other { border-radius: 18px; padding-inline: 16px; background: var(--card); border: 1px solid var(--line); }
.lk-simple .lk-other[open] { padding-bottom: 16px; }

/* Keep the landing's dark hero, give process and pricing the same card family. */
.land-simple .land-hero.has-stage { border-radius: 24px; }
.land-simple .land-process { gap: 16px; }
.land-simple .land-process li { padding: 24px; border: 1px solid var(--line); border-radius: 22px; background: var(--card); }
.land-simple .land-process li::before { color: var(--txt-1); font-weight: 650; }
.land-simple .land-benefits { gap: 24px; }
.land-simple .land-benefits > div { padding-left: 16px; }
.land-simple .land-plan { border-radius: 24px; }
.land-simple .land-close { padding: 32px 24px; border: 1px solid var(--line); border-radius: 24px; background: var(--card); }
.land-simple .land-hero :is(a,button):focus-visible { outline-color: var(--ink-on-dark); }

/* Detail sheets retain their media/data geometry; soften only prose surfaces. */
.rl-detail .rl-phases.is-v2 .rl-phase, .rl-detail .rl-lesson .rl-sec { border-radius: 18px; }
.rl-detail .rl-read-head { gap: 16px; }
.rl-detail .rl-chat .input { border-color: var(--line-2); }
@media (max-width: 359px) {
  .lk-simple .lk-mine { padding: 16px; }
  .land-simple .land-process li { padding: 16px; }
  #app .me-ds17 .me-list .me-row { gap: 8px; }
}

/* DS23 overlays and secondary surfaces. Append-only; no route, modal lifecycle,
   stacking or existing DS23 page geometry changes. Panels stay opaque: only
   the scrim blurs, and unsupported browsers retain the same readable surface. */
html .sheet-wrap, html .intro-wrap {
  padding: max(12px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right)) max(12px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
}
html .sheet-wrap > .sheet, html .intro-wrap > .intro-card {
  --r-card: 22px; --r-inner: 16px; --r-ctl: 16px;
  border: 1px solid var(--line-2); border-radius: 24px;
  background: var(--raised); color: var(--txt-1);
  max-height: calc(100vh - 32px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  max-height: calc(100dvh - 32px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  overflow-y: auto; overscroll-behavior-y: contain; scrollbar-gutter: stable;
  scrollbar-width: thin; scrollbar-color: var(--txt-3) transparent;
  scroll-padding-block: 24px; overflow-wrap: anywhere;
  box-shadow: 0 16px 48px rgb(0 0 0 / .24);
}
html .sheet-back, html .intro-back {
  background: rgb(9 10 12 / .72);
}
@media (prefers-reduced-transparency: reduce) {
  html .sheet-back, html .intro-back {
    background: rgb(9 10 12 / .8);
  }
}
html .sheet .sheet-grab {
  width: 36px; height: 4px; margin: 8px auto 20px; border-radius: 8px;
  background: var(--txt-3); opacity: .5; pointer-events: none;
}
html .sheet .cf-in, html .acct-sheet .ob-sheet-in { padding: 0 20px 20px; }
html .sheet.ck-sheet { padding: 8px 20px 20px; }
html .intro-wrap .intro-card { padding: 24px 20px; }
html .sheet :is(h1,h2), html .intro-card .intro-title {
  color: var(--txt-1); font-size: 24px; font-weight: 750;
  line-height: 1.18; letter-spacing: -.03em; text-wrap: balance;
}
html .sheet :is(.cf-body,.ob-sheet-sub,.ck-facts,.pw-line), html .intro-card :is(.intro-sub,.path-line) {
  color: var(--txt-2); font-size: 16px; line-height: 1.6;
}
html .sheet .cf-actions { gap: 8px; margin-top: 24px; }
html :is(.sheet,.intro-card) :is(button,.btn) {
  min-width: 44px;
  white-space: normal; overflow-wrap: anywhere;
}
html :is(.sheet,.intro-card) :is(.btn-primary,.btn-danger,.btn-good,.cf-cancel,.acct-go,.ck-go) { padding: 12px 16px;
}
html :is(.sheet,.intro-card) :is(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),select,textarea) {
  font-size: 16px; min-height: 48px; max-width: 100%; border-radius: 16px;
}
html .sheet :is(.consent-row,.ra-field) { margin-top: 16px; }
html .sheet :is(.consent-text,.consent-aside) { font-size: 14px; line-height: 1.6; color: var(--txt-2); }
html .sheet .consent-row { padding: 16px; border: 1px solid var(--line-2); border-radius: 16px; background: var(--card); }
html .sheet .consent-box { flex-shrink: 0; }
html .sheet :is(.field-err,.ra-err,.sl-err) { color: var(--danger-ink); line-height: 1.5; }
html .sheet :is(.card,.pw-card), html .intro-card :is(.path-opt,.intro-tier) { border-radius: 20px; }
html .sheet .pw-head { padding-inline: 20px; }
html .sheet .pw-close { top: 8px; right: 8px; }
html .sheet .pw-foot { background: var(--raised); padding: 8px 20px 12px; }
html .sheet .pw-foot-row { gap: 8px; }
html .sheet .pw-scroll { scrollbar-gutter: stable; overscroll-behavior-y: contain; }
html .sheet .pw-seg { overflow-x: auto; }
html .sheet .pw-seg-btn { min-width: 80px; }
html .sheet .pw-legal { flex-wrap: wrap; }
html .sheet .pw-card { padding: 16px; }
html .sheet .pw-card-slot, html .sheet .pw-next { padding-inline: 20px; }
html .sheet :is(#pr-belts,#bc-belts) { grid-template-columns: repeat(auto-fit,minmax(64px,1fr)); }
html .sheet .pr-belt { padding: 8px 4px; }
html .sheet .nudge-tpl { padding: 12px; text-align: left; border: 1px solid var(--line-2); }
html .sheet .nudge-tpl.on { background: var(--sunken); color: var(--txt-1); border-color: var(--txt-1); }
html :is(.sheet,.intro-card,.toast) :is(button,a,input,select,textarea):focus-visible {
  outline: 2px solid var(--txt-1); outline-offset: 2px;
}
html .toast-root {
  max-height: calc(100vh - 140px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  max-height: calc(100dvh - 140px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  overflow-y: auto; overscroll-behavior-y: contain; padding-inline: max(12px,env(safe-area-inset-left),env(safe-area-inset-right));
}
html .toast { border-radius: 20px; flex-shrink: 0; padding: 12px; gap: 12px; background: var(--raised); color: var(--txt-1); font-size: 16px; line-height: 1.5; }
html .toast .toast-x { margin: 0; color: var(--txt-2); border-radius: 12px; }
html .toast .toast-act { font-size: 16px; min-height: 44px; color: var(--txt-1); text-decoration: underline; text-underline-offset: 3px; }

/* Existing main-screen geometry is excluded as a group. The remaining routes
   share these base controls, including unlabeled admin/academy wrappers. */
#app main:not(.pg-main-is-home-ds16-film-ds17-bf54) {
  --r-card: 22px; --r-inner: 16px; --r-ctl: 16px;
  --radius: 22px; --radius-sm: 16px; --radius-lg: 24px;
}
#app main:not(.pg-main-is-home-ds16-film-ds17-bf54) :is(.card,.panel,.lock-card,.plan-card) {
  border-radius: 22px;
}
#app main:not(.pg-main-is-home-ds16-film-ds17-bf54) :is(.btn,.seg-btn) { min-width: 44px; white-space: normal;
}
#app main:not(.pg-main-is-home-ds16-film-ds17-bf54) .input {
  min-height: 48px; min-width: 0; max-width: 100%; border-radius: 16px; font-size: 16px;
}
#app main:not(.pg-main-is-home-ds16-film-ds17-bf54) :is(button,a,input,select,textarea,summary):focus-visible {
  outline: 2px solid var(--txt-1); outline-offset: 2px;
}
#app :is(.tiers,.billing,.acct) { overflow-wrap: anywhere; }
#app .tiers :is(.plan-card,.tiers-fair) { border-radius: 24px; }
#app .tiers .tier-cta { min-height: 56px; }
#app :is(.br-empty,.br-staff-note,.nudge-empty-note,.ra-refusal) { border: 1px solid var(--line); border-radius: 20px; background: var(--card); color: var(--txt-2); padding: 16px; line-height: 1.6; }
#app .ra-refusal .ra-refusal-t { color: var(--txt-1); }
#app :is(.billing-pastdue,.ra-status.is-failed) { color: var(--danger-ink); }
/* These two legacy fields carry Tailwind's explicit important 12px utility. */
#app #inv-role.input, #app #inv-label.input { font-size: 16px !important; }
/* The location and legacy retention popups have no dedicated class. Match
   their existing body-level overlay, not every fixed element in the app. */
html body > .fixed.z-\[90\] {
  padding: max(16px,env(safe-area-inset-top)) max(16px,env(safe-area-inset-right)) max(16px,env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left));
  background: rgb(9 10 12 / .72);
}
html body > .fixed.z-\[90\] > .card {
  background: var(--raised); border: 1px solid var(--line-2); border-radius: 24px; margin-block: 0; padding: 24px;
  max-height: calc(100vh - 40px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  max-height: calc(100dvh - 40px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  overflow-y: auto; overscroll-behavior-y: contain; scrollbar-gutter: stable; overflow-wrap: anywhere;
}
html body > .fixed.z-\[90\] :is(button,.input) { min-width: 44px; min-height: 48px; font-size: 16px; border-radius: 16px; }
html body > .fixed.z-\[90\] h2 { font-size: 24px; line-height: 1.2; }
html body > .fixed.z-\[90\] :is(button,input):focus-visible { outline: 2px solid var(--txt-1); outline-offset: 2px; }
@media (prefers-reduced-transparency: reduce) {
  html body > .fixed.z-\[90\] { background: rgb(9 10 12 / .8); }
}
html .install-banner { border-radius: 24px; background: var(--raised); color: var(--txt-1); }
html .consumer-notice { background: var(--raised); color: var(--txt-1); border: 1px solid var(--line-2); border-radius: 20px; font-size: 14px; line-height: 1.6; }
/* Full-screen kiosk feedback stays full-screen, not a floating phone sheet. */
html .kiosk-flash { background: var(--ground); padding: max(24px,env(safe-area-inset-top)) max(24px,env(safe-area-inset-right)) max(24px,env(safe-area-inset-bottom)) max(24px,env(safe-area-inset-left)); overflow-wrap: anywhere; }
@media (max-width: 359px) {
  html .sheet :is(.cf-in,.ob-sheet-in,.pw-card-slot,.pw-next) { padding-inline: 16px; }
  html .sheet .pw-foot-row { grid-template-columns: 1fr; }
  html .sheet .pw-bill { grid-template-columns: 1fr; }
  #app main.pg-main-admin-q-d876 #admin-q { flex-basis: 100%; }
  #app main.pg-main-admin-q-d876 #admin-q + select { width: 100%; }
}

/* DS24 light surfaces. Decorative boundaries become surface depth, not input
   boundaries. Keep every border width (and therefore all DS23 geometry).
   Landing and auth have separate owners; chart strokes and DS20 are untouched. */
html[data-theme="light"] #app main:not(.pg-main-is-land-simple-auth-she-5017) :is(.card,.panel,.home-latest,.home-practice,.film-group,.rl-empty,.me-identity,.me-list,.progress-rows,.lk-mine,.lk-other,.ds16-secondary,.plan-card):not(.home-attention .card):not(#home-coach .card):not(.is-selected,.on,[aria-selected="true"],[role="alert"]) {
  border-color: transparent;
  box-shadow: 0 6px 24px -12px rgb(42 48 43 / .13), 0 1px 3px rgb(42 48 43 / .025);
}
html[data-theme="light"] #app :is(.progress-ds17 .gm-seg,#coach-ds18 .mode-switch,.me-ds17 .theme-seg) {
  border-color: transparent;
  background: #EEF0EC;
}
html #app :is(.progress-ds17 .gm-seg .seg-btn.on,#coach-ds18 .mode-pill.is-active,.me-ds17 .theme-seg button.on) {
  border-color: transparent;
  background: var(--accent-fill);
  color: var(--accent-on);
  box-shadow: none;
}
html #app :is(.progress-ds17 .gm-seg .seg-btn.on,#coach-ds18 .mode-pill.is-active,.me-ds17 .theme-seg button.on) i {
  color: inherit;
}
html[data-theme="light"] #home-ds16 .home-day-dot.is-on {
  border-color: transparent;
  background: #E3E7DE;
  color: var(--txt-1);
}
html[data-theme="light"] #home-ds16 .home-day.is-today .home-day-dot {
  border-color: transparent;
  background: var(--accent-fill);
  color: var(--accent-on);
}
html[data-theme="light"] #app .me-ds17 .me-camera {
  background: #E3E7DE;
  color: var(--txt-1);
}
html[data-theme="light"] #app #coach-ds18 .coach-prompts button:is(:hover,:focus-visible) {
  background: #EEF0EC;
  color: var(--txt-1);
}
html[data-theme="light"] :is(.sheet-wrap > .sheet,.intro-wrap > .intro-card,body > .fixed.z-\[90\] > .card,.toast,.install-banner,.consumer-notice) {
  border-color: transparent;
  box-shadow: 0 16px 48px -16px rgb(42 48 43 / .18), 0 2px 8px rgb(42 48 43 / .04);
}
html[data-theme="light"] :is(.sheet,.intro-card) :is(.card,.pw-card,.consent-row,.path-opt,.intro-tier):not(.on,.is-selected,[aria-selected="true"]) {
  border-color: rgb(42 48 43 / .06);
  box-shadow: none;
}
/* Form outlines convey affordance, unlike the decorative card borders above.
   Neutral field boundaries exceed 3:1 on white; errors retain semantic red. */
html[data-theme="light"] #app main:not(.pg-main-is-land-simple-auth-she-5017) :is(.input,select,textarea),
html[data-theme="light"] :is(.sheet,.intro-card,body > .fixed.z-\[90\]) :is(.input,select,textarea) {
  border-color: #7B817B;
}
html[data-theme="light"] #app main:not(.pg-main-is-land-simple-auth-she-5017) :is(.input,select,textarea):is([aria-invalid="true"],.is-invalid,.is-error),
html[data-theme="light"] :is(.sheet,.intro-card,body > .fixed.z-\[90\]) :is(.input,select,textarea):is([aria-invalid="true"],.is-invalid,.is-error) {
  border-color: var(--danger-ink);
}
html[data-theme="light"] #app main:not(.pg-main-is-land-simple-auth-she-5017) :is(button,a,input,select,textarea,summary):focus-visible,
html[data-theme="light"] :is(.sheet,.intro-card,.toast,body > .fixed.z-\[90\]) :is(button,a,input,select,textarea):focus-visible {
  outline-color: #59645A;
}
html[data-theme="light"] #app .me-ds17 .me-avatar:focus-within {
  outline-color: #59645A;
}
html[data-theme="light"] #app main :is(#home-ds16,.film-ds17,.rl-detail,.progress-ds17,#coach-ds18,.me-ds17,.lk-simple) :is(button,a,input,select,textarea,summary):focus-visible {
  outline-color: #59645A;
}
/* END DS24 light surfaces. */

/* DS27: original 6d39601 lime for action roles in both themes. Hero geometry
   and the separate boot animation keep their existing styles. */
:root { --brand-action: #CEFF56; }
html #home-ds16 .home-review {
  background-color: var(--brand-action);
  color: var(--accent-on);
}
/* END DS27 original action color. */

/* DS24 landing visuals. Current-source demo capture, isolated from app/auth. */
.land-simple .land-product-hero { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; column-gap: clamp(1rem, 3vw, 3rem); padding: 1rem clamp(1rem, 3vw, 2.5rem) 2rem; text-align: left; background: var(--sunken); border-radius: 28px; overflow: hidden; }
.land-simple .land-product-hero .land-simple-nav { grid-column: 1 / -1; margin-bottom: 1.5rem; }
.land-simple .land-product-hero :is(.land-wordmark, .land-simple-nav a, .land-link) { color: var(--txt-1); }
.land-simple .land-product-copy { min-width: 0; padding-bottom: 1.5rem; }
.land-simple .land-product-hero .land-eyebrow { background: var(--raised); border: 0; color: var(--txt-2); font-weight: 650; }
.land-simple .land-product-hero .land-h1 { margin: 1rem 0 0; max-width: 15ch; font-size: clamp(2.1rem, 4.6vw, 3.75rem); color: var(--txt-1); letter-spacing: -.045em; line-height: 1.06; text-wrap: balance; }
.land-simple .land-product-hero .land-sub { margin: 1.25rem 0 0; max-width: 36ch; color: var(--txt-2); line-height: 1.55; }
.land-simple .land-product-hero .land-cta { align-items: flex-start; justify-content: flex-start; }
.land-simple .land-product-hero .land-btn { min-height: 56px; }
.land-simple .land-product-hero .land-fine { margin: .85rem 0 0; color: var(--txt-2); font-size: 13px; max-width: 39ch; }
.land-simple .land-product-hero :is(a, button):focus-visible { outline-color: var(--txt-1); }
.land-simple .land-product-art { min-width: 0; margin: 0; position: relative; }
.land-simple .land-product-art img { display: block; width: 100%; height: auto; object-fit: contain; }
.land-simple .land-product-art .land-product-light { display: none; }
html[data-theme="light"] .land-simple .land-product-art .land-product-light { display: block; }
html[data-theme="light"] .land-simple .land-product-art .land-product-dark { display: none; }
.land-simple .land-product-art figcaption { padding-top: .25rem; text-align: center; color: var(--txt-2); font-size: 12px; line-height: 1.5; }
@media (max-width: 767px) {
  .land-simple .land-product-hero { grid-template-columns: minmax(0, 1fr); padding: .65rem 1rem 1.5rem; border-radius: 24px; }
  .land-simple .land-product-hero .land-simple-nav { margin-bottom: 1.1rem; gap: .75rem; }
  .land-simple .land-product-copy { padding-bottom: .5rem; }
  .land-simple .land-product-hero .land-h1 { font-size: clamp(2rem, 8.5vw, 3rem); max-width: 19ch; margin-top: .8rem; }
  .land-simple .land-product-hero .land-sub { margin-top: 1rem; font-size: 16px; }
  .land-simple .land-product-hero .land-cta { margin-top: 1.1rem; }
  .land-simple .land-product-hero .land-btn { width: 100%; min-height: 56px; }
  .land-simple .land-product-art { margin: .75rem -1rem 0; }
  .land-simple .land-product-art figcaption { padding-inline: 1rem; }
}
/* END DS24 landing visuals. */

/* DS32 original hero back (B. Tech Lead, Reqwa 2026-09-23 msgs 4656626/4656702):
   the DS10-DS14 stage hero -- eyebrow chip, heavy centred headline, lime pill
   "Start free", quiet "I already train here", three real screens in stock
   iPhone frames with the land-fan-arrive / land-device-* entrance animation.
   Markup is back in VIEWS.home; the rules for it never left this file (37.33,
   37.37, DS14 1c). This block only undoes the DS18/DS24 flattening on top of
   them and makes the stage pitch black (#000) instead of #0A0A0C. */
.land-simple .land-hero.has-stage { width: auto; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); padding: 1rem var(--gutter, 1rem) var(--s7, 3rem); border-radius: 0 0 var(--s6, 32px) var(--s6, 32px); background: #0F0F11; text-align: center; overflow: hidden; }
/* Light theme = white + lime (Reqwa 4655946). Phone screens stay dark (37.32 ruling). */
html[data-theme="light"] .land-simple .land-hero.has-stage { background: #fff; color: #0A0A0C; }
html[data-theme="light"] .land-simple .land-hero.has-stage .land-h1 { color: #000; }
html[data-theme="light"] .land-simple .land-hero.has-stage .land-sub { color: #3F4148; }
html[data-theme="light"] .land-simple .land-hero.has-stage .land-fine { color: #6B6E76; }
html[data-theme="light"] .land-simple .land-hero.has-stage .land-link-alt,
html[data-theme="light"] .land-simple .land-hero.has-stage .land-simple-nav :is(a, .land-link),
html[data-theme="light"] .land-simple .land-hero.has-stage .land-wordmark { color: #0A0A0C; }
html[data-theme="light"] .land-simple .land-hero.has-stage .land-eyebrow { background: #F4F4F6; color: #3F4148; border: 1px solid rgba(0,0,0,.1); }
html[data-theme="light"] .land-simple .land-hero.has-stage .land-btn { box-shadow: 0 0 0 1px rgba(0,0,0,.08); }
.land-simple .land-hero.has-stage .land-stage::after { background: radial-gradient(ellipse at 50% 78%, rgba(255,255,255,.05), transparent 62%), linear-gradient(180deg, #0F0F11 0%, rgba(15,15,17,.6) 42%, #0F0F11 88%); }
.land-simple .land-hero.has-stage .land-simple-nav { max-width: 72rem; margin-inline: auto; margin-bottom: clamp(1.5rem, 5vw, 3rem); }
.land-simple .land-hero.has-stage .land-eyebrow { border-radius: 999px; padding: .5rem 1rem; font-size: 14px; min-height: 36px; }
.land-simple .land-hero.has-stage .land-h1 { max-width: 14ch; margin-inline: auto; font-size: clamp(2.6rem, 9vw, 4.8rem); font-weight: 900; letter-spacing: -.05em; line-height: .95; color: #fff; }
.land-simple .land-hero.has-stage .land-sub { max-width: 34rem; margin-inline: auto; color: #B4B7BE; }
.land-simple .land-hero.has-stage .land-cta { flex-direction: column; align-items: center; gap: .75rem; }
.land-simple .land-hero.has-stage .land-btn { min-width: min(100%, 18rem); min-height: 64px; border-radius: 999px; font-size: 20px; font-weight: 800; }
.land-simple .land-hero.has-stage .land-link-alt { font-size: 17px; font-weight: 700; color: #D4D4D8; }
.land-simple .land-hero.has-stage .land-fine { max-width: 30rem; margin-inline: auto; color: #8A8F98; }
.land-simple .land-hero.has-stage .land-shots.is-trio { margin-top: var(--s6, 2rem); }
html .land-simple .land-shots.is-trio .land-shot { --device-width: clamp(8.5rem, 40vw, 16rem); }
.land-simple + .land-shots-note, .land-simple .land-shots-note { margin: var(--s4, 1rem) auto 0; text-align: center; color: var(--txt-3); }
/* Page behind the landing: the original near-black ground (#0A0A0C, the hero stage one step lighter at #0F0F11 like Reqwa's screenshot); pure white in light. */
/* (page surface: see DS32b below) */
main.pg-main-land-simple-8d77 { padding-top: 0 !important; }
@media (min-width: 1024px) {
  .land-simple .land-hero.has-stage .land-cta { flex-direction: row; justify-content: center; gap: 1.5rem; }
  html .land-simple .land-shots.is-trio .land-shot { --device-width: 15rem; }
}  /* beats the DS18 16px :is(#id) rule */
.land-simple .land-hero.has-stage .land-stage img { opacity: .14; }
html[data-theme="light"] .land-simple .land-hero.has-stage .land-stage { display: none; }
/* Scroll-driven trio (views.js landingTrioScroll): JS owns every transform, so
   the DS14 keyframe entrance is off; the group only fades/rises in once the
   screens are decoded. The fan is visible (rest pose) if JS never runs. */
.land-shots.is-trio.is-scroll, .land-shots.is-trio.is-scroll .land-shot { animation: none !important; }
.land-shots.is-trio.is-scroll { opacity: 0; transform: translateY(calc(var(--land-bleed, 0rem) + 14px)); transition: opacity .55s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.16,1,.3,1); }
.land-shots.is-trio.is-scroll.is-ready { opacity: 1; transform: translateY(var(--land-bleed, 0rem)); }
.land-shots.is-trio.is-scroll .land-shot { transition: none; will-change: transform, opacity; }
@media (prefers-reduced-motion: reduce) { .land-shots.is-trio.is-scroll { transition: none; transform: none; } }
/* No app-shell flash before the landing paints (app.js dismissSplash adds .boot-painted). */
html[data-boot="off"]:not(.boot-painted) #app { visibility: hidden; }
/* DS32b ONE TEXTURED PAGE (Reqwa 4658242: "different background on the hero
   and the rest is bad, it has to be sleek, TEXTURED background the whole
   landing like AscendMax"). The hero is no longer a block: it is transparent
   and sits on the same surface as every section. The surface is one fixed
   layer behind the whole landing -- near-black ground, a soft light pool at the
   top, and fine monochrome film grain -- so it never seams or restarts as you
   scroll. Cards sit on it as one tone step with the same grain showing through.
   Light theme: warm white with a faint dark grain. No photo, no glow. */
.land-simple .land-hero.has-stage { background: transparent !important; border-radius: 0; margin-left: auto; margin-right: auto; width: 100%; overflow: visible; }
html[data-theme="light"] .land-simple .land-hero.has-stage { background: transparent !important; }
.land-simple .land-hero.has-stage .land-stage { display: none !important; }
html.pg-html-land-simple-64ca body, html #app.pg-app-land-simple-ee9c, html main.pg-main-land-simple-8d77 { background: transparent !important; }
html[data-theme="light"].pg-html-land-simple-64ca body, html[data-theme="light"] #app.pg-app-land-simple-ee9c, html[data-theme="light"] main.pg-main-land-simple-8d77 { background: transparent !important; }
/* The surface lives on <html> itself (grain tile + one top light pool, both
   scroll with the document): no fixed layer, so no seam at any viewport or in
   iOS Safari's collapsing toolbar, and it continues under every section. */
html:not([data-theme="light"]).pg-html-land-simple-64ca { background: url('/static/img/hero/grain-dark.svg') repeat top left / 200px, radial-gradient(ellipse 120% 900px at 50% -120px, rgba(255,255,255,.07), transparent 75%) no-repeat, #0B0B0D !important; }
html[data-theme="light"].pg-html-land-simple-64ca { background: url('/static/img/hero/grain-light.svg') repeat top left / 200px, radial-gradient(ellipse 120% 900px at 50% -120px, rgba(0,0,0,.03), transparent 75%) no-repeat, #FAFAF8 !important; }
/* Cards: one tone step, translucent so the grain reads through; no outlines. */
.land-simple :is(.land-process li, .land-plan, .land-close, .land-plan-unavailable) { background: rgba(255,255,255,.035) !important; border: 1px solid rgba(255,255,255,.06) !important; box-shadow: none !important; }
html[data-theme="light"] .land-simple :is(.land-process li, .land-plan, .land-close, .land-plan-unavailable) { background: rgba(255,255,255,.72) !important; border: 1px solid rgba(0,0,0,.06) !important; box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.04) !important; }
#app.pg-app-land-simple-ee9c .app-footer { background: transparent !important; border-top-color: rgba(255,255,255,.06); }
html[data-theme="light"] #app.pg-app-land-simple-ee9c .app-footer { border-top-color: rgba(0,0,0,.06); }
/* END DS32 original hero back. */

/* ══════════════════════════════════════════════════════════════════════════
   DS34 LANDING BELOW THE HERO (B. Designer; copy = LANDING-COPY-v2, Marketing
   4658231 + Copywriter 4658303; brief Tech Lead 4658631/4658668). Sits on the
   DS32b textured surface. Rhythm: split → split-reversed → tile grid →
   centred pricing → full-width academy panel → centred close. No glow, no
   pure black, lime only for the one action per section and the Pro tier.
   ══════════════════════════════════════════════════════════════════════════ */
.land-simple .land-v2 { padding-block: clamp(3.5rem, 9vw, 6.5rem) 0; }
.land-simple .land-v2 .land-h2 { font-size: clamp(2rem, 5.4vw, 3.25rem); font-weight: 850; letter-spacing: -.045em; line-height: 1.02; max-width: 16ch; margin: 0; }
.land-simple .land-v2 .land-sec-head-c .land-h2 { margin-inline: auto; }
.land-simple .land-v2 .section-label { display: block; margin: 0 0 .9rem; font-size: 13px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--txt-2); }
.land-simple .land-v2 .land-p { margin: 1.1rem 0 0; max-width: 44ch; font-size: clamp(16px, 1.6vw, 18px); line-height: 1.55; color: var(--txt-2); }
.land-simple .land-v2 .land-note { margin: 1rem 0 0; font-size: 15px; font-weight: 600; color: var(--txt-1); }
.land-simple .land-v2 .land-honest { margin: 1.25rem 0 0; font-size: 15px; line-height: 1.5; color: var(--txt-2); max-width: 44ch; }
.land-simple .land-split-rev > :first-child { order: 2; }
@media (max-width: 899px) { .land-simple .land-split-rev > :first-child { order: 0; } }

/* roll analysis */
.land-simple .land-gets { list-style: none; margin: 1.6rem 0 0; padding: 0; display: grid; gap: 0; counter-reset: g; }
.land-simple .land-gets li { counter-increment: g; display: grid; grid-template-columns: 2rem 1fr; gap: 2px 12px; padding: 14px 0; border-top: 1px solid rgba(255,255,255,.07); }
.land-simple .land-gets li::before { content: counter(g, decimal-leading-zero); grid-row: span 2; font-size: 13px; font-weight: 700; color: var(--txt-3); padding-top: 3px; font-variant-numeric: tabular-nums; }
.land-simple .land-gets strong { font-size: 17px; font-weight: 700; color: var(--txt-1); }
.land-simple .land-gets span { font-size: 15px; color: var(--txt-2); }
.land-simple .land-screen { margin: 0 auto; width: min(100%, 300px); border-radius: 36px; overflow: hidden; background: rgba(255,255,255,.035); padding: 10px; }
.land-simple .land-screen img { display: block; width: 100%; height: auto; border-radius: 28px; }

/* coach: centred statement, no mock UI (Tech Lead 4693625: no placeholder bars) */
.land-simple .land-coach2 { max-width: 46rem; margin: 0 auto; text-align: center; }
.land-simple .land-coach2 .land-p { margin-inline: auto; }
.land-simple .land-coach2 .land-note { text-align: center; }
/* sub-products */
.land-simple .land-tiles { display: grid; gap: 12px; margin-top: 2.2rem; grid-template-columns: 1fr; }
@media (min-width: 760px) { .land-simple .land-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; } }
.land-simple .land-tile2 { position: relative; display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px 12px; padding: 20px; border-radius: 24px; background: rgba(255,255,255,.035); text-align: left; }
.land-simple .land-tile2 > i { width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center; background: rgba(255,255,255,.06); color: var(--txt-1); font-size: 15px; }
.land-simple .land-tile2 h3 { margin: 0; font-size: 18px; font-weight: 750; letter-spacing: -.02em; color: var(--txt-1); }
.land-simple .land-tile2 p { grid-column: 1 / -1; margin: 6px 0 0; font-size: 15px; line-height: 1.5; color: var(--txt-2); }
.land-simple .land-chip { justify-self: end; padding: 4px 10px; border-radius: 99px; font-size: 12px; font-weight: 700; background: rgba(255,255,255,.07); color: var(--txt-1); white-space: nowrap; }

/* pricing: limits, legal, CTA per tier */
.land-simple .land-plan-limits { list-style: none; margin: 1rem 0 0; padding: 12px 14px; border-radius: 14px; background: rgba(255,255,255,.04); display: grid; gap: 4px; }
.land-simple .land-plan-limits li { font-size: 13px; line-height: 1.45; color: var(--txt-1); font-variant-numeric: tabular-nums; }
.land-simple .land-legal { max-width: 46rem; margin: 1.8rem auto 0; display: grid; gap: .45rem; text-align: center; }
.land-simple .land-legal p { margin: 0; font-size: 14px; line-height: 1.5; color: var(--txt-2); }
.land-simple .land-plan-btn { min-height: 52px; border-radius: 999px !important; font-weight: 700; }

/* TIER COLOURS — one identity across landing, /plans and the paywall.
   Free = neutral, Pro = lime (the recommended tier), Overpowered = ink
   (white in dark, black in light): a 4px tier bar on the card top plus the
   tier's own CTA, flag and dot. Lime stays "do this" — it only marks Pro. */
.land-simple .land-plan[data-tier], .plan-card.tier[data-plan] { position: relative; overflow: hidden; }
.land-simple .land-plan[data-tier]::before, .plan-card.tier[data-plan]::before { content: ''; position: absolute; inset: 0 0 auto; height: 4px; background: var(--tier, var(--line-2)); }
:is(.land-plan[data-tier="free"], .plan-card[data-plan="free"], .pw-seg-btn[data-plan="free"]) { --tier: #6B6E76; }
:is(.land-plan[data-tier="athlete"], .plan-card[data-plan="athlete"], .pw-seg-btn[data-plan="athlete"]) { --tier: var(--accent-fill); }
:is(.land-plan[data-tier="pro"], .plan-card[data-plan="pro"], .pw-seg-btn[data-plan="pro"]) { --tier: #F4F4F5; }
html[data-theme="light"] :is(.land-plan[data-tier="pro"], .plan-card[data-plan="pro"], .pw-seg-btn[data-plan="pro"]) { --tier: #0A0A0C; }
.land-simple .land-plan[data-tier="athlete"] { box-shadow: inset 0 0 0 1.5px var(--accent-fill) !important; }
.land-simple .land-plan[data-tier="pro"] .land-plan-btn { background: var(--tier); color: var(--ground, #0B0B0D); border-color: transparent; }
html[data-theme="light"] .land-simple .land-plan[data-tier="pro"] .land-plan-btn { color: #FFFFFF; }
.land-simple .land-plan[data-tier] .land-plan-name::before, .plan-card.tier[data-plan] .tier-name::before, .pw-seg-btn[data-plan]::before { content: ''; display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 50%; background: var(--tier); vertical-align: .12em; }

/* academies: second front door, full-width panel */
.land-simple .land-gym2 { display: grid; gap: 2rem; padding: clamp(24px, 5vw, 48px); border-radius: 32px; background: rgba(255,255,255,.045); }
@media (min-width: 900px) { .land-simple .land-gym2 { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: 3rem; align-items: center; } }
.land-simple .land-gym2-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 1.25rem; margin-top: 1.6rem; }
.land-simple .land-gym2-cta .land-btn { min-height: 56px; padding: 0 28px; border-radius: 999px; font-size: 17px; font-weight: 750; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
.land-simple .land-gym2-cta .land-btn-2 { background: rgba(255,255,255,.07); color: var(--txt-1); border: 0; }
html[data-theme="light"] .land-simple .land-gym2-cta .land-btn-2 { background: rgba(0,0,0,.06); }
.land-simple .land-gym2-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.land-simple .land-gym2-list li { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; padding: 16px 0; border-top: 1px solid rgba(255,255,255,.07); }
.land-simple .land-gym2-list li:first-child { border-top: 0; }
.land-simple .land-gym2-list strong { font-size: 17px; font-weight: 700; color: var(--txt-1); }
.land-simple .land-gym2-list span:not(.land-chip) { grid-column: 1 / -1; font-size: 15px; line-height: 1.5; color: var(--txt-2); }

/* close */
.land-simple .land-close.land-v2 { margin: clamp(3.5rem, 9vw, 6.5rem) 0 clamp(2.5rem, 6vw, 4rem); padding: clamp(32px, 7vw, 64px) 24px; border-radius: 32px; text-align: center; }
.land-simple .land-close.land-v2 .land-h2 { margin-inline: auto; max-width: 14ch; }
.land-simple .land-close.land-v2 .land-p { margin-inline: auto; }
.land-simple .land-close.land-v2 .land-btn { margin-top: 1.6rem; min-height: 60px; min-width: min(100%, 16rem); border-radius: 999px; font-size: 18px; font-weight: 800; }

/* light theme counterparts */
html[data-theme="light"] .land-simple :is(.land-screen, .land-tile2, .land-gym2) { background: rgba(255,255,255,.72); box-shadow: 0 1px 2px rgba(0,0,0,.04); }
html[data-theme="light"] .land-simple :is(.land-plan-limits, .land-tile2 > i, .land-chip) { background: #F2F2F0; }
html[data-theme="light"] .land-simple :is(.land-gets li, .land-gym2-list li) { border-top-color: rgba(0,0,0,.07); }
/* END DS34. */

/* QA 4694882 #9/#10: paywall plan switcher label stays on one line with its
   tier dot at 390px; launch price shown in the billing tiles with its
   renewal figure (the server charges the launch price, so the sheet must say it). */
html .sheet .pw-seg .seg-btn.pw-seg-btn { white-space: nowrap !important; flex-wrap: nowrap !important; display: inline-flex; align-items: center; justify-content: center; gap: 0; min-width: 0; padding-inline: 10px; letter-spacing: .02em; font-size: clamp(12px, 3.4vw, 15px); }
html .sheet .pw-seg .seg-btn.pw-seg-btn[data-plan]::before { flex: none; }
.pw-bill-tile .pw-bill-v b { white-space: nowrap; font-size: clamp(20px, 6vw, 28px); }
.pw-bill-tile .pw-bill-v small { white-space: nowrap; }
.pw-bill-then { display: block; margin-top: 4px; font-size: 12px; line-height: 1.35; color: var(--txt-2); font-weight: 500; }
/* ═══ eng/paddle-site (B. Engineer, 2026-09-23): shared footer,
   plan disclosures, thank-you. Tokens only; Designer's overhaul may restyle. */
.app-footer .af-links { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem 1.1rem; }
.app-footer .af-link-btn { background: none; border: 0; padding: 0; font: inherit; color: var(--txt-3); cursor: pointer; }
.app-footer .af-link-btn:hover, .app-footer a:hover { color: var(--txt-1); }
.app-footer .af-entity { flex-basis: 100%; margin: .35rem 0 0; line-height: 1.5; }
.app-footer .af-entity a { text-decoration: underline; text-underline-offset: 2px; }

/* The cookie notice floats (ds.src.css .cookie-card, FTL 5305148); nothing here positions it. */

.plan-renew { font-size: .78rem; line-height: 1.45; color: var(--txt-3); margin: .45rem 0 0; }
.plan-caps { list-style: none; margin: .7rem 0 0; padding: .65rem 0 0; border-top: 1px solid var(--line); display: grid; gap: .35rem; font-size: .85rem; }
.plan-caps li { display: flex; gap: .5rem; align-items: baseline; }
.plan-caps i { color: var(--txt-3); font-size: .78rem; }
.tiers-mor { font-size: .82rem; line-height: 1.5; color: var(--txt-3); margin: 1.25rem 0 .35rem; max-width: 52rem; }
.tiers-links { font-size: .82rem; color: var(--txt-3); margin: 0; }
.tiers-links a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.thanks { max-width: 34rem; margin: 2rem auto; }
.legal-foot .af-links { justify-content: center; }
.land-mor { font-size: .78rem; color: var(--txt-3); max-width: 44rem; margin-inline: auto; }
.tier-caps { margin-top: .7rem; }
.billing-portal { text-decoration: none; color: inherit; }
.bill-actions { align-items: center; }
@keyframes op-spin { to { transform: rotate(360deg); } }
.thanks .spinner { width: 28px; height: 28px; border-radius: 50%; border: 3px solid var(--line-2); border-top-color: var(--txt-1); animation: op-spin .8s linear infinite; }
@media (prefers-reduced-motion: reduce) { .thanks .spinner { animation: none; } }

/* Daily objectives, last 14 days: one cell per day, its count inside. */
.obj-days { display: grid; grid-template-columns: repeat(14, minmax(0, 1fr)); gap: 6px; }
.obj-day { height: 36px; border-radius: 10px; display: grid; place-items: center; border: 1px dashed var(--txt-3); opacity: .55; }
.obj-day-n { font-size: 10px; font-weight: 700; color: var(--txt-3); }
.obj-day.is-part { border: 1.5px solid var(--txt-1); opacity: 1; }
.obj-day.is-part .obj-day-n { color: var(--txt-1); }
.obj-day.is-full { background: var(--op-lime, #D4FF4F); border-color: transparent; opacity: 1; }
.obj-day.is-full .obj-day-n { color: #0B0B0C; }
@media (max-width: 560px) { .obj-days { grid-template-columns: repeat(7, minmax(0, 1fr)); } }
/* AI held (Tech Lead 4711606): an AI plan shows a quiet, inert "Coming soon". */
.land-plan-btn.is-soon, .plan-cta.is-soon { pointer-events: none; cursor: default; opacity: 1; background: var(--ds-well, rgba(127,127,127,.12)); color: var(--txt-2); border-color: transparent; box-shadow: none; }
.pw-soon-tag { display: inline-block; margin: 4px 0 6px; padding: 3px 10px; border-radius: 999px; background: var(--ds-well, rgba(127,127,127,.14)); color: var(--txt-2); font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.pw-soon-line { margin: 8px 0 0; text-align: center; font-size: 14px; color: var(--txt-2); }
.intro-tier-soon { font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--txt-2); padding: 3px 10px; border-radius: 999px; background: var(--ds-well, rgba(127,127,127,.14)); }

/* Layout gate (QA 4773878): legal-page links and nav are 44pt targets; small text kept. */
.legal-brand, .legal-nav a, .legal-top a, .legal-toc a, .legal-doc footer a, .legal-foot a, .legal-foot button,
header a[class*="is-"], .legal-doc .af-link-btn, .app-footer a, .app-footer .af-link-btn { min-height: 44px; display: inline-flex; align-items: center; }
.legal-brand { min-width: 44px; }
@media (min-width: 900px) { .legal-toc ol { gap: 0; } }   /* the phone chip rail keeps its .4rem gap: at 0 the chips were glued edge to edge */
.legal-contact a, .af-entity a { display: inline-flex; align-items: center; min-height: 44px; }

/* ── Orphan subject rules (copy/test-drift, 2026-09-26) ─────────────────────
   Every class below was rendered with no rule of its own (test:orphans).
   Most are structural hooks whose parent already paints them; they get a
   minimal, layout-safe rule so each class is defined and wraps cleanly at
   375 pt. The trial checkout lines (Legal 4769575) get real type. */
.ck-trial { margin: .7rem 0 0; padding: .8rem .9rem; border-radius: 16px; background: color-mix(in srgb, var(--txt-1) 5%, transparent); }
.ck-trial-price { margin: 0; font-size: 1.05rem; line-height: 1.35; color: var(--txt-1); }
.ck-trial-price strong { font-weight: 800; }
.ck-trial-terms { margin: .35rem 0 0; font-size: .84rem; line-height: 1.5; color: var(--txt-2); text-wrap: pretty; }
.ck-sheet.is-trial { overflow-wrap: anywhere; }
.ck-sheet.is-trial .ck-go { margin-top: .9rem; }
.ck-mor { margin: .8rem 0 0; font-size: .74rem; line-height: 1.45; color: var(--txt-3, var(--txt-2)); text-wrap: pretty; }
.tier-intro-fine { margin: .3rem 0 0; font-size: .78rem; line-height: 1.45; color: var(--txt-2); }
.pw-cta-slot { display: block; width: 100%; }
.pw-restore { display: inline-flex; align-items: center; min-height: 32px; padding: 0; border: 0; background: none; font: inherit; color: inherit; cursor: pointer; }
.stat-meter-t { font-variant-numeric: tabular-nums; white-space: nowrap; }
.ci-page { width: 100%; }
.ci-card { overflow-wrap: anywhere; }
.nm-sheet, .vl-sheet { overflow-wrap: anywhere; }
.nm-row { min-height: 44px; }
.mp-pulse, .mp-techs, .mp-rolls, .mp-belts { min-width: 0; }
.vl-mic-t { white-space: nowrap; }
.tp-row.is-added { box-shadow: inset 3px 0 0 var(--op-500, currentColor); }
.kx-share-txt { min-width: 0; overflow-wrap: anywhere; }
.priv-state { font-size: .82rem; color: var(--txt-2); }
.inst-reward-t { min-width: 0; }
.sd-kids { white-space: nowrap; }
.sd-pend-row { min-width: 0; }
.pf-waiting { min-width: 0; }
.rc-tick-l { font-size: .82rem; font-weight: 700; }

/* design/system-2 (QA gate on the design system, Tech Lead 4818213): legal and server pages that load this
   sheet follow the same rules as the app — sentence case (kickers, labels, table headers), ink-only notices,
   44 pt links and Back. */
html body .legal-kicker, html body .legal-doc th, html body .legal-shell .section-label, html body .legal-doc .section-label, html body .legal-toc .section-label { text-transform: none !important; letter-spacing: 0 !important; }
html body .legal-doc td { text-transform: none !important; }
html body .legal-prose .legal-notice, html body .legal-doc .legal-notice { border-color: var(--line) !important; border-left-color: var(--txt-2) !important; }
html body .legal-prose .legal-notice strong, html body .legal-doc .legal-notice strong { color: var(--txt-1) !important; }
html body .legal-top .legal-back, html body a.legal-back { min-height: 44px !important; min-width: 44px; display: inline-flex !important; align-items: center; }
html body .legal-prose a, html body .legal-doc p a, html body .legal-doc li a, html body .legal-doc td a { display: inline-block; min-height: 44px; line-height: 44px; padding: 0 2px; }

/* design/system-3 (Tech Lead 4820386): the legal/server top bar is the DS-SYSTEM bar — 52 pt + safe area, glass,
   no border; Back always on screen (the doc tabs scroll inside the bar and never push it out). */
html body .legal-top { background: var(--ds-bar, var(--card, #1C1C1E)) !important; border-bottom: 0 !important; box-shadow: 0 .5px 0 var(--line); }
@media (prefers-reduced-transparency: reduce) { html body .legal-top { background: var(--ground) !important; } }
html body .legal-top-in { height: 52px !important; gap: 8px !important; }
html body .legal-top .legal-tabs { flex: 1 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; white-space: nowrap; display: flex; }
html body .legal-top .legal-tabs::-webkit-scrollbar { display: none; }
html body .legal-top .legal-tabs a { display: inline-flex; align-items: center; min-height: 44px; flex: none; }
html body .legal-top .legal-back { flex: none !important; margin-left: auto; min-height: 44px !important; white-space: nowrap; }
html body .legal-logo { width: 30px !important; height: 30px !important; }
@media (max-width: 1023px) { html body .legal-top .legal-tabs { display: none !important; } }
html body .legal-top .legal-back { height: 44px !important; padding: 0 14px !important; margin-block: 0 !important; line-height: 1 !important; border-radius: 999px !important; }
html body .legal-top-in { align-items: center !important; }

/* Carried from main (design/landing-v2 hero B, Reqwa 4829983; 3rd CR 4837226): the landing-v2 block, byte for byte. */
/* LANDING v2 (replay of design/landing-v2 c737f11 + landing-cue c316aa3).
   Scoped to .lv2, rendered only by VIEWS.home. Self-contained on purpose so it
   survives the design/system single-stylesheet rebase (TL #msg:4826135 item 4).
   Palette: lime + black/white by theme only (#msg:4808671); the only lime TEXT
   is none in light: lime is a fill under ink, ink draws the line (Reqwa round 1 items 6/27). Motion: transform/opacity only. */
.lv2 { --lv2-bg: #07080A; --lv2-ink: #F4F4F5; --lv2-ink-2: #A1A1AA; --lv2-card: #111113; --lv2-sk: #26262A; --lv2-line: rgba(255,255,255,.1); --lv2-lime: #CEFF56; --lv2-lime-ink: #CEFF56; --lv2-num-bg: #CEFF56; --lv2-num-ink: #0A0A0C; --lv2-tile: transparent;
  position: relative; margin: 0 calc(50% - 50vw); padding: 0 max(1.25rem, env(safe-area-inset-left)) 3rem; background: var(--lv2-bg); color: var(--lv2-ink); overflow-x: clip; font-family: Inter, system-ui, -apple-system, sans-serif; }
html[data-theme="light"] .lv2 { --lv2-bg: #FFFFFF; --lv2-ink: #0A0A0C; --lv2-ink-2: #5F6068; --lv2-card: #0C0C0E; --lv2-sk: #2A2A2E; --lv2-line: rgba(0,0,0,.09); --lv2-lime-ink: #0A0A0C; --lv2-num-bg: #CEFF56; --lv2-num-ink: #0A0A0C; --lv2-tile: #0A0A0C; }
html #app.pg-app-lv2-c338 main { background: var(--lv2-bg, #101013); padding-bottom: 0; }
html[data-theme="light"] #app.pg-app-lv2-c338, html[data-theme="light"] #app.pg-app-lv2-c338 main { background: #FFFFFF; }
html #app.pg-app-lv2-c338 { background: #07080A; }
.lv2 > * { max-width: 1072px; margin-inline: auto; }

/* nav */
.lv2 .lv2-nav { display: flex; align-items: center; gap: 1.25rem; height: 64px; padding-top: env(safe-area-inset-top); }
.lv2 .lv2-brand { margin-right: auto; display: inline-flex; align-items: center; gap: .6rem; font-weight: 800; font-size: 17px; letter-spacing: -.02em; }
.lv2 .lv2-brand-mark { width: 26px; height: 26px; fill: var(--lv2-lime); }
html[data-theme="light"] .lv2 .lv2-brand-mark { fill: #0A0A0C; }
.lv2 .lv2-navlink { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; justify-content: center; font-size: 15px; font-weight: 500; color: var(--lv2-ink-2); background: none; border: 0; }
.lv2 .lv2-navlink:hover { color: var(--lv2-ink); }

/* hero, direction A round 2 (task #14 item 29; Reqwa #msg:4828002, #msg:4828825):
   a textured surface, one iPhone that carries the story, no floating cards.
   Nothing glows: lime is flat colour only (button, track). No radial gradients. */
/* page surface (item 29, Reqwa #msg:4829983: variant B, no texture, both themes):
   flat near-black / warm off-white with a very soft linear tone shift.
   No texture, no radial, no glow. */
.lv2 { --lv2-bg: #101013; background: #101013; }   /* kit page #101013 (FTL 5010412) */
html[data-theme="light"] .lv2 { --lv2-bg: #F2F2F7; background: #F2F2F7; }   /* DS v1.1 `ground` (Hannah 5194382: no warm cream) */
html #app.pg-app-lv2-c338, html #app.pg-app-lv2-c338 main { background: #101013; }
html[data-theme="light"] #app.pg-app-lv2-c338, html[data-theme="light"] #app.pg-app-lv2-c338 main { background: #F2F2F7; }
.lv2 > * { position: relative; z-index: 1; }
.lv2 .lv2-hero { position: relative; text-align: center; padding: clamp(2.5rem, 7vw, 5rem) 0 clamp(3rem, 8vw, 6rem); }
.lv2 .lv2-hero-copy { min-width: 0; }
.lv2 .lv2-mark :is(.lv2-br, .lv2-br-tl, .lv2-br-tr, .lv2-br-bl, .lv2-br-br, .lv2-knot) { fill: inherit; }
.lv2 .lv2-h1 { margin: 0 auto; max-width: 11em; font-size: clamp(2.75rem, 7vw, 5.5rem); line-height: .96; font-weight: 800; letter-spacing: -.045em; text-wrap: balance; }
.lv2 .lv2-sub { margin: 1.5rem auto 0; max-width: 24em; font-size: clamp(1.0625rem, 1.5vw, 1.25rem); line-height: 1.5; font-weight: 400; color: var(--lv2-ink-2); text-wrap: pretty; }
.lv2 .lv2-cta { display: flex; flex-direction: column; align-items: center; gap: .25rem; margin-top: 2.25rem; }
.lv2 .lv2-btn { min-height: 56px; min-width: 240px; padding-inline: 2.25rem; border-radius: 999px; font-size: 17px; font-weight: 600; letter-spacing: -.01em; background: var(--accent-fill, #CEFF56); color: var(--accent-on, #0A0A0C); border: 0; display: inline-flex; align-items: center; justify-content: center; box-shadow: none; }
.lv2 .lv2-quiet { min-height: 44px; min-width: 44px; padding: 0 .75rem; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 500; color: var(--lv2-ink-2); background: none; border: 0; text-decoration: none; }
.lv2 .lv2-quiet:hover { color: var(--lv2-ink); }
.lv2 .lv2-fine { margin: .25rem auto 0; font-size: 13px; color: var(--lv2-ink-2); }   /* no opacity: .8 washed #5F6068 to 3.66:1 (axe, Web Lead 5340796) */

/* stage: the phone is the LCP; both images carry explicit sizes */
.lv2 .lv2-stage { position: relative; width: 100%; margin: clamp(3rem, 7vw, 4.5rem) auto 0; --pw: clamp(260px, 30vw, 316px); }
.lv2 .lv2-phone { position: relative; margin: 0 auto; width: var(--pw); }
/* plain screen card (no device frame until App Store launch, Legal 5177250): solid tonal layers, one hairline, no glass */
.lv2 .lv2-screen { position: relative; border-radius: calc(var(--pw) * .1); overflow: hidden; background: #000; box-shadow: inset 0 0 0 .5px rgba(255,255,255,.16), 0 30px 60px -36px rgba(0,0,0,.8); }
html[data-theme="light"] .lv2 .lv2-screen { background: #F2F2F7; box-shadow: inset 0 0 0 .5px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.04), 0 30px 60px -34px rgba(20,20,30,.28); }
/* r4/r5 (B6): the hero screen card at iPhone 16 Pro proportions (402 x 874 pt screen, 55 pt corners); --u = one screen point. */
.lv2 .lv2-phone { --u: calc(var(--pw) / 402); }
.lv2 .lv2-screen { aspect-ratio: 402 / 874; border-radius: calc(var(--u) * 55); background: #101013; }
html[data-theme="light"] .lv2 .lv2-screen { background: #F2F2F7; }
/* B1 v2.1 hero film (Hannah PASS 5302854): fills the screen card; one per theme. */
.lv2 .lv2-film { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; background: #101013; }
.lv2 .lv2-film-light { display: none; }
html[data-theme="light"] .lv2 .lv2-film-dark { display: none; }
html[data-theme="light"] .lv2 .lv2-film-light { display: block; background: #F2F2F7; }
/* LANDING_DEVICE_FRAME=true (html.lv2-bezel): Apple's stock iPhone 16 Pro bezel PNG, untouched, around the same screen
   (img/hero/LICENSE.md). Opening x72-1277 y69-2691 of 1350 x 2760: 5.33 % / 2.5 % insets. Off until the App Store listing is live. */
.lv2:is(html.lv2-bezel *) .lv2-phone { width: calc(var(--pw) * 1350 / 1205); aspect-ratio: 1350 / 2760; }
.lv2:is(html.lv2-bezel *) .lv2-screen { position: absolute; left: 5.33%; right: 5.41%; top: 2.5%; bottom: 2.47%; aspect-ratio: auto; box-shadow: none; }
.lv2:is(html.lv2-bezel *) .lv2-phone::after { content: ""; position: absolute; inset: 0; background: url(/static/img/hero/iphone-16-pro-black.webp) center / 100% 100% no-repeat; pointer-events: none; }
html[data-theme="light"] .lv2:is(html.lv2-bezel *) .lv2-phone::after { background-image: url(/static/img/hero/iphone-16-pro-natural.webp); }
@media (max-width: 480px) {
  .lv2 .lv2-hero { padding-top: 3.25rem; }
  .lv2 .lv2-h1 { font-size: 48px; line-height: .97; }
  .lv2 .lv2-sub { margin-top: 1.1rem; font-size: 17px; padding-inline: .25rem; }
  .lv2 .lv2-cta { margin-top: 1.75rem; }
  .lv2 .lv2-btn { width: 100%; }
  .lv2 .lv2-stage { --pw: 264px; margin-top: 2.75rem; }
}
@media (min-width: 1024px) {
  .lv2 .lv2-hero { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); align-items: center; gap: 4rem; text-align: left; padding: 3.5rem 0 5rem; }
  .lv2 .lv2-hero .lv2-h1 { margin: 0; font-size: clamp(3.5rem, 5.2vw, 4.75rem); max-width: 9em; }
  .lv2 .lv2-hero .lv2-sub { margin-left: 0; max-width: 23em; }
  .lv2 .lv2-hero .lv2-cta { align-items: flex-start; }
  .lv2 .lv2-hero .lv2-quiet { padding-inline: 0; justify-content: flex-start; }
  .lv2 .lv2-hero .lv2-fine { margin-left: 0; }
  .lv2 .lv2-stage { margin-top: 0; --pw: 300px; }
}

.lv2 .lv2-legal { max-width: 44rem; margin: 1.75rem auto 0; text-align: center; font-size: 13px; line-height: 1.55; color: var(--lv2-ink-2); }
.lv2 .lv2-legal p { margin: 0; }
.lv2 .lv2-legal p + p { margin-top: .5rem; }
.lv2 .lv2-legal-link { color: inherit; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--lv2-line); display: inline-block; padding-block: 12px; margin-block: -12px; }
.lv2 .lv2-legal-link:hover { color: var(--lv2-ink); }

/* sections along the drawing line */
.lv2 .lv2-rail { position: relative; display: grid; gap: clamp(4.5rem, 12vw, 8.5rem); padding: 4rem 0 2rem; }
.lv2 .lv2-line { position: absolute; top: calc(4rem + 12px); bottom: 0; left: 50%; width: 2px; margin-left: -1px; background: var(--lv2-line); overflow: hidden; }
.lv2 .lv2-line i { position: absolute; inset: 0; background: var(--lv2-lime); transform-origin: top; }
html[data-theme="light"] .lv2 .lv2-line i { background: #0A0A0C; }
.lv2 .lv2-sec { position: relative; display: grid; grid-template-columns: 1fr 1fr; align-items: start; gap: clamp(2rem, 6vw, 5rem); }
.lv2 .lv2-sec:nth-child(even of .lv2-sec) .lv2-copy { order: 2; }
.lv2 .lv2-copy { max-width: 30rem; }
.lv2 .lv2-kick { display: flex; align-items: center; gap: .6rem; margin: 0 0 1rem; font-size: 15px; font-weight: 700; color: var(--lv2-ink); }
.lv2 .lv2-num { display: inline-grid; place-items: center; min-width: 34px; height: 24px; padding: 0 .5rem; border-radius: 999px; background: var(--lv2-num-bg); color: var(--lv2-num-ink); font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums; }
.lv2 .lv2-h2 { margin: 0; font-size: clamp(2.1rem, 4.6vw, 3.6rem); line-height: 1; font-weight: 900; letter-spacing: -.05em; text-wrap: balance; }
.lv2 .lv2-p { margin: 1rem 0 0; font-size: clamp(1rem, 1.35vw, 1.15rem); line-height: 1.5; color: var(--lv2-ink-2); text-wrap: pretty; }
.lv2 .lv2-honest { margin: .9rem 0 0; font-size: 13px; line-height: 1.5; color: var(--lv2-ink-2); }

/* section cards: finished in-app cards (TL #msg:4833516), no skeleton bars.
   Dark: #111113 card. Light: white card with a hairline, ink text, lime only
   as a fill under ink (Reqwa round 1 items 6/27: no deep olive). Bars grow on
   scroll and their end state is the real value. */
.lv2 .lv2-art { --c-bg: #141416; --c-ink: #F4F4F5; --c-ink-2: #A1A1AA; --c-track: #2A2A2E; --c-sub: #1D1D20;
  position: relative; width: 100%; max-width: 440px; justify-self: center; border-radius: 28px; background: var(--c-bg); color: var(--c-ink); padding: 26px 26px 28px; display: flex; flex-direction: column; gap: 14px; overflow: hidden; box-shadow: inset 0 0 0 1px rgba(255,255,255,.07); font-size: 15px; line-height: 1.45; text-align: left; }
html[data-theme="light"] .lv2 .lv2-art { --c-bg: #FFFFFF; --c-ink: #0A0A0C; --c-ink-2: #5F6068; --c-track: #E7E7EA; --c-sub: #F4F4F6; box-shadow: inset 0 0 0 1px rgba(10,10,12,.08); }
.lv2 .lv2-art p { margin: 0; }
.lv2 .lv2-k { font-size: 13px; font-weight: 600; color: var(--c-ink-2); }
.lv2 .lv2-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.lv2 .lv2-row b { font-weight: 700; min-width: 0; }
.lv2 .lv2-dim { font-size: 13px; color: var(--c-ink-2); }
.lv2 .lv2-pill { flex: none; display: inline-flex; align-items: center; height: 26px; padding: 0 10px; border-radius: 999px; background: var(--c-sub); font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.lv2 .lv2-pill.on { background: #3A3A41; color: #FFFFFF; }   /* DS-08c (27 Oct): a picked pill = lifted slate, no lime */
.lv2 .lv2-track { position: relative; height: 18px; margin: 4px 0 -6px; }
.lv2 .lv2-track::before { content: ""; position: absolute; left: 0; right: 0; top: 7px; height: 4px; border-radius: 4px; background: var(--c-track); }
.lv2 .lv2-track i { position: absolute; left: 0; top: 7px; width: 64%; height: 4px; border-radius: 4px; background: #CEFF56; transform-origin: left; }
.lv2 .lv2-track b { position: absolute; top: 3px; left: var(--x); width: 12px; height: 12px; margin-left: -6px; border-radius: 50%; background: var(--c-ink-2); }
.lv2 .lv2-track-real b { width: 2px; height: 12px; top: 3px; margin-left: -1px; border-radius: 2px; }
.lv2 .lv2-track-real b.ok { height: 16px; top: 1px; background: var(--c-ink); }
.lv2 .lv2-track-real i { width: 100%; background: var(--c-track); }
.lv2 .lv2-track-real b.on { border-radius: 50%; }
.lv2 .lv2-track b.on { top: 0; width: 18px; height: 18px; margin-left: -9px; background: #CEFF56; box-shadow: 0 0 0 3px var(--c-bg); }
.lv2 .lv2-note { padding: 14px 16px; border-radius: 18px; background: var(--c-sub); }
.lv2 .lv2-note-k { display: block; margin-bottom: 4px; font-size: 13px; font-weight: 700; }
.lv2 .lv2-big { font-size: 17px; font-weight: 600; line-height: 1.4; letter-spacing: -.01em; }
.lv2 .lv2-drill { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 16px; background: var(--c-sub); }
.lv2 .lv2-drill b { font-weight: 700; }
.lv2 .lv2-area { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) 2.75rem; align-items: center; gap: 12px; font-size: 14px; }
.lv2 .lv2-area b { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
.lv2 .lv2-bar { position: relative; display: block; height: 8px; border-radius: 8px; background: var(--c-track); overflow: hidden; }
.lv2 .lv2-bar i { position: absolute; left: 0; top: 0; bottom: 0; width: var(--v); border-radius: 8px; background: var(--c-ink-2); transform-origin: left; }
.lv2 .lv2-bar.on i { background: #CEFF56; }
.lv2 .lv2-art-chat .lv2-bub { max-width: 86%; padding: 12px 16px; border-radius: 20px; background: var(--c-sub); font-size: 15px; }
.lv2 .lv2-art-chat .lv2-bub.me { align-self: flex-end; max-width: 78%; background: #2E2E35; color: #FFFFFF; border-bottom-right-radius: 6px; }   /* DS-03: never black on lime */
.lv2 .lv2-art-chat .lv2-bub:not(.me) { border-bottom-left-radius: 6px; }
.lv2 .lv2-tech { display: grid; gap: 7px; font-size: 14px; }
.lv2 .lv2-tech .lv2-row span { font-weight: 700; font-variant-numeric: tabular-nums; }

/* pricing */
.lv2 .lv2-pricing { padding-top: clamp(5rem, 12vw, 8rem); }
.lv2 .lv2-head { text-align: center; max-width: 36rem; margin: 0 auto 2.5rem; }
.lv2 .lv2-plans { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; align-items: stretch; }
.lv2 .lv2-plan { display: flex; flex-direction: column; min-width: 0; padding: 1.5rem; border-radius: 26px; background: #0F0F11; box-shadow: inset 0 0 0 1px rgba(255,255,255,.07); }
html[data-theme="light"] .lv2 .lv2-plan, html[data-theme="light"] .lv2 .lv2-art { box-shadow: none; }
html[data-theme="light"] .lv2 .lv2-plan { background: #F5F5F7; }
.lv2 .lv2-plan.is-hi { box-shadow: inset 0 0 0 2px #CEFF56; }
html[data-theme="light"] .lv2 .lv2-plan.is-hi { background: #FFFFFF; box-shadow: inset 0 0 0 2px #0A0A0C, 0 18px 40px -24px rgba(10,10,12,.35); }
.lv2 .lv2-plan-name { margin: 0; font-size: 17px; font-weight: 800; }
.lv2 .lv2-plan-tag { margin: .35rem 0 0; font-size: 14px; line-height: 1.45; color: var(--lv2-ink-2); overflow-wrap: anywhere; }
.lv2 .lv2-plan-price { margin: 1rem 0 0; display: flex; align-items: baseline; gap: .15rem; flex-wrap: wrap; }
.lv2 .lv2-was { margin-right: .4rem; font-size: 15px; color: var(--lv2-ink-2); }
.lv2 .lv2-fig { font-size: clamp(2rem, 3.4vw, 2.6rem); font-weight: 900; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.lv2 .lv2-per, .lv2 .lv2-plan-year { font-size: 14px; color: var(--lv2-ink-2); }
.lv2 .lv2-plan-year { margin: .2rem 0 0; }
.lv2 .lv2-plan-intro { margin: .6rem 0 0; font-size: 13px; line-height: 1.45; color: var(--lv2-ink); }
.lv2 .lv2-feats, .lv2 .lv2-excl { list-style: none; margin: 1.25rem 0 0; padding: 1.25rem 0 0; border-top: 1px solid var(--lv2-line); display: grid; gap: .7rem; }
.lv2 .lv2-feats li { display: grid; grid-template-columns: 1.1rem minmax(0, 1fr); gap: .6rem; font-size: 14px; line-height: 1.45; }
.lv2 .lv2-feats i { margin-top: .2rem; font-size: 12px; color: var(--txt-1); }
.lv2 .lv2-excl { border-top: 0; padding-top: 0; margin-top: 1rem; }
.lv2 .lv2-excl li { font-size: 13px; color: var(--lv2-ink-2); }
.lv2 .lv2-excl li::before { content: "– "; }
.lv2 .lv2-plan-btn { margin-top: auto; min-height: 48px; border-radius: 999px; font-weight: 700; }
.lv2 .lv2-plan .lv2-excl + .lv2-plan-btn, .lv2 .lv2-plan .lv2-feats + .lv2-plan-btn { margin-top: 1.5rem; }
.lv2 .lv2-unavailable { text-align: center; color: var(--lv2-ink-2); }
.lv2 .lv2-unavailable button { min-height: 44px; }

/* academies */
.lv2 .lv2-acad { display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(2rem, 6vw, 4.5rem); align-items: center; padding-top: clamp(5rem, 12vw, 8rem); }
.lv2 .lv2-cta-l { justify-content: flex-start; }
.lv2 .lv2-acad .lv2-btn { min-width: 0; }
.lv2 .lv2-acad-copy { min-width: 0; }
.lv2 .lv2-rows { margin: 0; display: grid; }
.lv2 .lv2-rows > div { padding: 1.05rem 0; border-top: 1px solid var(--lv2-line); }
.lv2 .lv2-rows > div:first-child { border-top: 0; }
.lv2 .lv2-rows dt { font-size: 17px; font-weight: 700; }
.lv2 .lv2-rows dd { margin: .3rem 0 0; font-size: 15px; line-height: 1.45; color: var(--lv2-ink-2); }

/* closing card: the kit card surface, themed (v3 landing, FTL 5002701); see landing-v2.css */
.lv2 .lv2-close { margin-top: clamp(5rem, 12vw, 8rem); padding: clamp(3.5rem, 8vw, 6rem) 1.5rem; border-radius: 28px; background: #1C1C1E; color: var(--lv2-ink); text-align: center; box-shadow: inset 0 0 0 1px rgba(255,255,255,.07); }
.lv2 .lv2-close .lv2-p { color: var(--lv2-ink-2); }
.lv2 .lv2-close .lv2-btn { margin-top: 2rem; }
/* UI Polish 5052320: the inline cookie card after the close card keeps the landing section gap (never fused to it). */
.lv2 .lv2-close-mark { width: 64px; height: 64px; margin: 0 auto 1.5rem; display: block; fill: #CEFF56; }
.lv2 :is(a, button):focus-visible { outline: 2px solid var(--lv2-ink); outline-offset: 4px; }
.lv2 .lv2-close :is(a, button):focus-visible { outline-color: var(--lv2-ink); }

/* v3 landing: the close card is a real card (FTL 5002701 / 5002768). It was pure black in BOTH themes, so the theme never
   reached it. Now the kit card surface (--k-bg-2), radius 28 (--k-r-hero), with the same edge as the art cards. */
.lv2 .lv2-close { background: var(--k-bg-2, #1C1C1E); color: #F4F4F5; border-radius: var(--k-r-hero, 28px); box-shadow: inset 0 0 0 1px rgba(255,255,255,.07); }
html[data-theme="light"] .lv2 .lv2-close { background: #FFFFFF; color: #0A0A0C; box-shadow: inset 0 0 0 1px rgba(10,10,12,.08); }
html[data-theme="light"] .lv2 .lv2-close .lv2-p { color: #5F6068; }
html[data-theme="light"] .lv2 .lv2-close :is(a, button):focus-visible { outline-color: #0A0A0C; }
html[data-theme="light"] .lv2 .lv2-close-mark { fill: #0A0A0C; }

/* scroll-driven reveal (no JS), IO fallback, and still mode.
   v3 (FTL 5002701 / 5003040, UI Polish 5003013): sections now reveal, and the step rail fills. Why nothing moved before:
   extract-landing-v2.mjs makes EVERY declaration !important, and an !important `transform: scaleY(0)` on the rail fill
   outranks the animation in the cascade, so lv2-draw never showed; and .lv2-io had no reveal rule. So the resting scale
   lives only in the keyframes (fill-mode both) and in the fallback/still branches, never on the base rule. The section
   reveal replaces TL 4833516's "no hidden cards" rule, per FTL 5002701. transform/opacity only (§6.5). */
@supports (animation-timeline: view()) {
  /* The fill follows the reader down the rail: the page scroll, from when the rail's top reaches mid-screen to when its
     bottom does. landingV2() measures the rail once (and on resize) into --rail-r0/--rail-r1 (px of scroll). */
  .lv2 .lv2-line i { animation: lv2-draw linear both; animation-timeline: scroll(root block); animation-range: var(--rail-r0, 0px) var(--rail-r1, 100%); }
  /* R12: the spine is invisible until section 01 is on screen, so no stub peeks above the fold under the hero */
  .lv2 .lv2-line { animation: lv2-fade linear both; animation-timeline: view(); animation-range: entry 0% entry 320px; }
  .lv2 .lv2-io { animation: lv2-rise linear both; animation-timeline: view(); animation-range: entry 0% entry 55%; }
}
/* No scroll-driven animations (Safari today): the IntersectionObserver adds .is-in once. 20 px, 500 ms, ease-out. */
.lv2.lv2-fallback .lv2-line i { transform: scaleY(0); transition: transform 1.2s cubic-bezier(.16,1,.3,1); }
.lv2.lv2-fallback .lv2-line.is-in i { transform: scaleY(1); }
.lv2.lv2-fallback .lv2-line { opacity: 0; transition: opacity .6s ease; }
.lv2.lv2-fallback .lv2-line.is-in { opacity: 1; }
.lv2.lv2-fallback .lv2-io { opacity: 0; transform: translateY(20px); transition: opacity .5s cubic-bezier(.16,1,.3,1), transform .5s cubic-bezier(.16,1,.3,1); }
.lv2.lv2-fallback .lv2-io.is-in { opacity: 1; transform: none; }
@keyframes lv2-fade { 0%, 40% { opacity: 0; } 100% { opacity: 1; } }
@keyframes lv2-draw { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes lv2-grow { from { transform: scaleX(0); } }
@keyframes lv2-rise { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }
.lv2.lv2-still .lv2-line i { transform: scaleY(1); }
@media (prefers-reduced-motion: reduce) {
  .lv2 *, .lv2 *::before { animation: none !important; transition: none !important; }
  .lv2 .lv2-io { opacity: 1 !important; transform: none !important; }
  .lv2 .lv2-line i { transform: scaleY(1); }
}

/* phone + iPad: one centred column, the line runs down the left of the copy */
@media (max-width: 859px) {
  .lv2 .lv2-line { left: 0; }
  .lv2 .lv2-sec { grid-template-columns: minmax(0, 1fr); gap: 1.75rem; padding-left: 1.25rem; }
  .lv2 .lv2-sec .lv2-copy { order: 0 !important; }
  .lv2 .lv2-art { justify-self: start; max-width: 520px; }
  .lv2 .lv2-plans { grid-template-columns: minmax(0, 1fr); max-width: 520px; margin-inline: auto; }
  .lv2 .lv2-acad { grid-template-columns: minmax(0, 1fr); }
}
@media (min-width: 600px) and (max-width: 859px) {
  .lv2 .lv2-plans { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: none; }
  .lv2 .lv2-plans > .lv2-plan:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 480px) {
  .lv2 .lv2-nav { gap: .5rem; }
  .lv2 .lv2-btn { width: 100%; }
  .lv2 .lv2-cta { flex-direction: column; gap: .5rem; }
  .lv2 .lv2-cta-l { align-items: stretch; }
}

/* DS v1.1 lime budget (Hannah 5194382): one lime CTA per screen. Section numbers are plain footnote text, no pill and no rail;
   "Drill this" is a label; the user's bubble is surface2; own-data bars share one neutral colour; one labelled marker, no tick strip. */
.lv2 .lv2-kick { gap: 0; font-size: 13px; font-weight: 600; color: var(--lv2-ink-2); }
.lv2 .lv2-num { display: inline; min-width: 0; height: auto; padding: 0; border-radius: 0; background: none; color: inherit; font-size: inherit; font-weight: inherit; }
.lv2 .lv2-line { display: none; }
.lv2 .lv2-feats i { color: var(--lv2-ink-2); }
.lv2 .lv2-drill { display: block; }
.lv2 .lv2-drill .lv2-k { display: block; margin-bottom: 4px; font-size: 13px; font-weight: 600; }
.lv2 .lv2-art-chat .lv2-bub.me { background: var(--c-sub); color: var(--c-ink); }
.lv2 .lv2-bar.on i { background: var(--c-ink-2); }
.lv2 .lv2-track-real i { background: var(--c-track); }
.lv2 .lv2-track-real b.on { background: var(--c-ink); box-shadow: 0 0 0 3px var(--c-bg); }
/* END LANDING v2 */
/* the nav capsule's 12 px app-bar band (ds.src.css header.glass.pt-safe:before, background: inherit) painted a capsule-coloured box above the nav (Uozot 5168562): page colour, full width */
html.pg-html-lv2-8b2a header.tb-float::before { content: ""; position: absolute; bottom: 100%; left: 50%; right: auto; width: 100vw; height: 12px; margin-left: -50vw; background: #101013; pointer-events: none; }
html[data-theme="light"].pg-html-lv2-8b2a header.tb-float::before { background: #F2F2F7; }
/* Landing page ground, dark: the kit page #101013 under html/body too (FTL 5010412); outside the .lv2-scoped block because it styles html. */
html:not([data-theme="light"]).pg-html-lv2-8b2a, html:not([data-theme="light"]).pg-html-lv2-8b2a body { background: #101013; }
/* v3 landing: ONE header (FTL 5002701 / 5003040; UI Polish 5003013; B. Tech Lead 5002782). The app's sticky header.glass is
   the only header on `/` signed out (the .lv2-nav bar is deleted): a floating capsule, sticky 12 px, centred on the page
   column (max 72rem), full width minus 16 px at 430 and under. Brand left; Pricing, Log in, Join free (lime, black text)
   right. SOLID, not glass (Uozot 5004419 via FTL 5004488: no web glass except the belt control): opaque --k-bar / white,
   0.5 px hairline, the soft float shadow, no backdrop-filter. */
html.pg-html-lv2-8b2a header.tb-float { position: sticky; top: 12px; z-index: 40; width: min(72rem, calc(100% - 32px)); margin: 12px auto 0; padding: 0; border: 0; border-radius: 999px; background: var(--k-bar, #1C1C1E); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: inset 0 0 0 .5px rgba(255,255,255,.08), 0 8px 24px rgba(0,0,0,.18); }
html[data-theme="light"].pg-html-lv2-8b2a header.tb-float { background: #FFFFFF; box-shadow: inset 0 0 0 .5px rgba(0,0,0,.08), 0 8px 24px rgba(0,0,0,.08); }
html.pg-html-lv2-8b2a header.tb-float .tb-row { max-width: none; height: 56px; margin: 0; padding: 0 8px 0 16px; gap: 8px; }
html.pg-html-lv2-8b2a header.tb-float .tb-tools { gap: 4px; }
/* logo + wordmark on the landing (the app bar is logo-only elsewhere) */
html.pg-html-lv2-8b2a header.tb-float .tb-brand span.tb-kicker { display: inline; font-size: 20px; line-height: 1; letter-spacing: -.02em; }
html.pg-html-lv2-8b2a header.tb-float .tb-brand { gap: 8px; min-height: 44px; flex: 0 0 auto; width: auto; margin-right: auto; }
html.pg-html-lv2-8b2a header.tb-float .tb-link { display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px; font-size: 15px; font-weight: 500; color: var(--lv2-ink-2, #A1A1AA); text-decoration: none; }
html[data-theme="light"].pg-html-lv2-8b2a header.tb-float .tb-link { color: #5F6068; }
html.pg-html-lv2-8b2a header.tb-float .btn-ghost.tb-cta { padding: 0 12px; }
html.pg-html-lv2-8b2a header.tb-float .btn-primary.tb-cta { padding: 0 18px; }
@media (max-width: 430px) {
  html.pg-html-lv2-8b2a header.tb-float .tb-row { padding: 0 6px 0 12px; gap: 4px; }
  html.pg-html-lv2-8b2a header.tb-float .tb-link { padding: 0 7px; font-size: 14px; }
  html.pg-html-lv2-8b2a header.tb-float .btn-ghost.tb-cta { padding: 0 7px; }
  html.pg-html-lv2-8b2a header.tb-float .btn-primary.tb-cta { padding: 0 13px; }
  html.pg-html-lv2-8b2a header.tb-float .tb-kicker { font-size: 17px; }
}
/* 320: the pill has room for the logo, Log in and Join free only — Pricing hides (still in the page and the footer),
   and the two actions never wrap (UI Polish HOLD 5021623, FTL 5024495). */
html.pg-html-lv2-8b2a header.tb-float .tb-cta { white-space: nowrap; flex: 0 0 auto; }
@media (width < 360px) {
  html.pg-html-lv2-8b2a header.tb-float .tb-link { display: none; }
  /* the app bar's <360 icon-only rule (44 px square CTA) does not apply to the landing's text actions */
  html.pg-html-lv2-8b2a header.tb-float .tb-cta { width: auto; min-width: 44px; }
  html.pg-html-lv2-8b2a header.tb-float .btn-ghost.tb-cta { padding: 0 8px; }
  html.pg-html-lv2-8b2a header.tb-float .btn-primary.tb-cta { padding: 0 14px; }
}

/* LANDING v3 (11 Oct; owner: simple, high-end, real app screens, CSS motion only, light on weak phones, both themes).
   Scoped .lv2.lv3 / .lv2 .l3-*, so scripts/extract-landing-v2.mjs carries every rule into landing-v2.css.
   Theme A: ground #101013 / #F2F2F7, cards #1C1C1E / #FFF, lime only on the one primary button per view and the
   recommended plan's edge; never lime text on light; secondary buttons neutral grey. Motion: transform/opacity only. */
.lv2.lv3 { --l3-ink: #FFFFFF; --l3-ink-2: #B4B7BE; --l3-ink-3: #8A8F98; --l3-dim: #3A3B40; --l3-card: #1C1C1E; --l3-card-2: #2C2C2E;
  --l3-line: rgba(255,255,255,.09); --l3-edge: rgba(255,255,255,.14); --l3-shadow: 0 40px 90px -30px rgba(0,0,0,.75), 0 12px 30px -12px rgba(0,0,0,.5);
  --l3-lime: #CEFF56; --l3-on-lime: #0A0A0C;
  /* the main action (owner 10-11 Oct: no black text on lime; 14 Oct pass): the academy kit's lime tint, edge and label */
  --l3-main-fill:#2E2E35; --l3-main-fill-hover:#36363E; --l3-main-edge:transparent; --l3-main-label:#FFFFFF; --l3-max: 72rem;   /* DS-08c: graphite main, no lime button, never black on lime */ --l3-ground: #101013;
  padding: 0 max(1rem, env(safe-area-inset-left)) 0 max(1rem, env(safe-area-inset-right)); color: var(--l3-ink); }
html[data-theme="light"] .lv2.lv3 { --l3-main-fill:#CEFF56; --l3-main-fill-hover:#CEFF56; --l3-main-edge:#A8D63A; --l3-main-label:#101013; --l3-ink: #0A0A0C; --l3-ink-2: #3F4047; --l3-ink-3: #63656E; --l3-dim: #C7C8CE; --l3-card: #FFFFFF; --l3-card-2: #E9E9EE;
  --l3-line: rgba(0,0,0,.08); --l3-edge: rgba(0,0,0,.10); --l3-shadow: 0 40px 80px -36px rgba(16,16,19,.30), 0 10px 26px -14px rgba(16,16,19,.18); --l3-ground: #F2F2F7; }
.lv2.lv3 .l3-l { display: none; }
html[data-theme="light"] .lv2.lv3 .l3-d { display: none; }
html[data-theme="light"] .lv2.lv3 .l3-l { display: block; }

/* type scale: eyebrow 13 / body 17–19 / h2 clamp 34–64 / h1 clamp 56–132 */
.lv2.lv3 .l3-eyebrow, .lv2.lv3 .l3-kick { margin: 0 0 1rem; font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--l3-ink-3); }
.lv2.lv3 .l3-kick { display: flex; align-items: baseline; gap: .75rem; }
.lv2.lv3 .l3-kick span { font-variant-numeric: tabular-nums; color: var(--l3-ink-2); }
.lv2.lv3 .l3-h2 { margin: 0; font-size: clamp(2.125rem, 4.6vw, 4rem); line-height: 1.02; font-weight: 800; letter-spacing: -.04em; text-wrap: balance; color: var(--l3-ink); }
.lv2.lv3 .l3-p { margin: 1.125rem 0 0; max-width: 34ch; font-size: clamp(1.0625rem, 1.4vw, 1.1875rem); line-height: 1.5; color: var(--l3-ink-2); text-wrap: pretty; }
.lv2.lv3 .l3-btn { display: inline-flex; align-items: center; justify-content: center; min-height: 56px; padding: 0 30px; border-radius: 999px; font-size: 17px; font-weight: 700; letter-spacing: -.01em; background: var(--l3-main-fill); color: var(--l3-main-label); box-shadow: inset 0 0 0 1.5px var(--l3-main-edge); transition: transform .2s ease, background-color .2s ease; }
.lv2.lv3 .l3-btn:hover { background: var(--l3-main-fill-hover); }
html[data-theme="light"] .lv2.lv3 .l3-btn { box-shadow: inset 0 0 0 1.5px var(--l3-main-edge); }
.lv2.lv3 .l3-btn:active { transform: scale(.97); }
.lv2.lv3 .l3-btn-2 { display: inline-flex; align-items: center; justify-content: center; min-height: 52px; padding: 0 24px; border-radius: 999px; font-size: 16px; font-weight: 600; background: var(--l3-card-2); color: var(--l3-ink); box-shadow: none; text-decoration: none; }
.lv2.lv3 .l3-more { display: inline-flex; align-items: center; min-height: 44px; padding: 0 4px; font-size: 16px; font-weight: 600; color: var(--l3-ink); text-decoration: underline; text-decoration-color: var(--l3-dim); text-underline-offset: 5px; }
.lv2.lv3 .l3-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 22px; margin-top: 2rem; }

/* chapter screens: a capture of the real app at 390x844, clipped to a phone screen's radius (the hero is the live phone) */
.lv2.lv3 .l3-scr { position: relative; width: var(--sw, 300px); max-width: 100%; aspect-ratio: 390 / 844; border-radius: 13.5% / 6.24%; overflow: hidden; background: var(--l3-card); box-shadow: 0 0 0 1px var(--l3-edge), var(--l3-shadow); transform: translateZ(0); }
.lv2.lv3 .l3-scr img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top; }

/* HERO */
.lv2.lv3 .l3-hero { max-width: var(--l3-max); margin: 0 auto; padding: clamp(2.5rem, 7vw, 4.5rem) 0 0; display: grid; gap: 3rem; }
.lv2.lv3 .l3-h1 { margin: 0; max-width: 8.5em; font-size: clamp(4rem, 13.5vw, 8.5rem); line-height: .9; font-weight: 800; letter-spacing: -.055em; text-wrap: balance; text-align: left; color: var(--l3-ink); }
.lv2.lv3 .l3-sub { margin: 1.5rem 0 0; max-width: 26ch; font-size: clamp(1.1875rem, 1.9vw, 1.5rem); line-height: 1.4; color: var(--l3-ink-2); text-wrap: pretty; }
.lv2.lv3 .l3-fine { margin: 1rem 0 0; min-height: 1.5em; font-size: 14px; line-height: 1.5; color: var(--l3-ink-3); }
.lv2.lv3 .lv2-stage { margin: 0; --pw: auto; display: flex; flex-direction: column; align-items: center; gap: 1.25rem; }

/* the live phone (owner 11 Oct): the stock iPhone 15 Pro frame over the real roll page (land/phone.html, 393x852 pt,
   scaled by --k from l3PhoneLive). Screen hole of the 1293x2656 frame: x 58..1236, y 50..2605 → the insets below;
   display corner 55 pt of 393 = 14% of the screen width. Nothing leaves the screen. */
.lv2.lv3 .l3-phone { position: relative; width: var(--fw); aspect-ratio: 1293 / 2656; --fw: min(68vw, 290px); isolation: isolate; }
.lv2.lv3 .l3-phone-scr { position: absolute; left: 4.486%; top: 1.883%; width: 91.18%; height: 96.23%; overflow: hidden;
  border-radius: calc(var(--fw) * .9118 * .14); background: var(--l3-ground); }
/* the status bar (drawn: the app below is a web page) and the app, both at 393 pt and scaled by --k */
.lv2.lv3 .l3-phone-sb { position: absolute; left: 0; top: 0; width: 393px; height: 54px; transform-origin: 0 0; transform: scale(var(--k, .6744));
  display: flex; align-items: center; justify-content: space-between; padding: 6px 30px 0 46px; box-sizing: border-box;
  color: var(--l3-ink); font: 600 17px/1 Inter, -apple-system, system-ui, sans-serif; letter-spacing: -.01em; }
.lv2.lv3 .l3-phone-sb span { display: flex; gap: 6px; align-items: center; }
.lv2.lv3 .l3-phone-sb svg { fill: currentColor; }
.lv2.lv3 .l3-phone-if { position: absolute; left: 0; top: calc(54px * var(--k, .6744)); width: 393px; height: 798px; border: 0; transform-origin: 0 0;
  transform: scale(var(--k, .6744)); opacity: 0; transition: opacity .6s ease; background: var(--l3-ground); color-scheme: normal; }
.lv2.lv3 .l3-phone.is-on .l3-phone-if { opacity: 1; }
/* glitch 19 Oct: a still of the same screen under the app (views.js l3Poster) from first paint, never a black phone; the
   app fades in over it on lp-phone-ready and the still steps out once the fade is done */
.lv2.lv3 .l3-phone-poster { position: absolute; left: 0; top: calc(54px * var(--k, .6744)); width: calc(393px * var(--k, .6744)); height: calc(798px * var(--k, .6744)); object-fit: cover; object-position: top; pointer-events: none; user-select: none; }
.lv2.lv3 .l3-phone.is-on .l3-phone-poster { visibility: hidden; transition: visibility 0s linear .6s; }
/* glitch 19 Oct: on touch screens the phone never takes a swipe: the page scrolls, not the sample inside the frame */
@media (hover: none), (pointer: coarse) { .lv2.lv3 .l3-phone-if { pointer-events: none; } }
.lv2.lv3 .l3-phone-frame { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; pointer-events: none; user-select: none; }
.lv2.lv3 .l3-phone-cap { margin: 0; font-size: 13px; line-height: 1.4; color: var(--l3-ink-3); text-align: center; }
@media (prefers-reduced-motion: reduce) { .lv2.lv3 .l3-phone-if { transition: none; } }

/* STATEMENT: words light up with scroll (landingV3 toggles .is-lit) */
.lv2.lv3 .l3-state { max-width: var(--l3-max); margin: clamp(6rem, 14vw, 11rem) auto 0; }
.lv2.lv3 .l3-state-p { margin: 0; max-width: 22em; font-size: clamp(1.875rem, 4.4vw, 3.5rem); line-height: 1.12; font-weight: 700; letter-spacing: -.035em; text-wrap: balance; }
.lv2.lv3 .l3-w { color: var(--l3-ink); }
.lv2.lv3.l3-live .l3-w { color: var(--l3-dim); transition: color .35s ease; }
.lv2.lv3.l3-live .l3-w.is-lit { color: var(--l3-ink); }

/* CHAPTERS: phone = text then its screen; desktop = list left, one pinned screen right that swaps per chapter */
.lv2.lv3 .l3-chapters { max-width: var(--l3-max); margin: clamp(6rem, 12vw, 9rem) auto 0; }
/* chapters (11 Oct): ONE live phone (the sealed sample) pinned while the chapters pass; each chapter moves it to its
   own real screen (land/hero-phone.js l3ChapterPhone). Phones: the phone pins near the top and each chapter's copy
   rises over its lower edge as a card; desktop: copy left, phone right. */
.lv2.lv3 .l3-chapters { display: grid; }
.lv2.lv3 .l3-ch-list, .lv2.lv3 .l3-ch-stage { grid-area: 1 / 1; min-width: 0; }
.lv2.lv3 .l3-ch-stage { position: sticky; top: 84px; align-self: start; z-index: 0; display: flex; justify-content: center; }
.lv2.lv3 .l3-ch-stage .l3-phone { --fw: min(56vw, 30svh, 290px); }
.lv2.lv3 .l3-ch-list { position: relative; z-index: 1; }
.lv2.lv3 .l3-ch { min-height: 96svh; display: flex; flex-direction: column; justify-content: flex-end; padding: 0 0 5svh; scroll-margin-top: 96px; }
.lv2.lv3 .l3-ch-copy { padding: 22px 22px 24px; border-radius: 24px; background: var(--l3-card); box-shadow: 0 0 0 1px var(--l3-edge), var(--l3-shadow); }
.lv2.lv3 .l3-ch-copy .l3-h2 { font-size: clamp(1.75rem, 7vw, 2.5rem); }
.lv2.lv3 .l3-phone.is-moving .l3-phone-if { opacity: .3; transition: opacity .16s ease; }

/* HONESTY */
.lv2.lv3 .l3-honest { max-width: var(--l3-max); margin: clamp(3rem, 8vw, 7rem) auto 0; padding: clamp(1.75rem, 4vw, 3.5rem); border-radius: 32px; background: var(--l3-card); display: grid; gap: 2rem; align-items: center; }
/* the read's own six bars (copied from the live phone's roll page, styled by roll-page.css) */
.lv2.lv3 .l3-bars { margin: 0; width: 100%; max-width: 460px; justify-self: center; padding: 22px 20px; border-radius: 24px; background: var(--l3-ground); box-shadow: 0 0 0 1px var(--l3-line); }
.lv2.lv3 .l3-bars[hidden] { display: none; }
.lv2.lv3 .l3-bars .l3-bars-in { padding: 0; margin: 0; max-width: none; }
.lv2.lv3 .l3-bars .rp5-bars { margin: 0; padding: 0; }

/* HOW */
.lv2.lv3 .l3-how { max-width: var(--l3-max); margin: clamp(6rem, 12vw, 9rem) auto 0; }
.lv2.lv3 .l3-steps { list-style: none; margin: 2.5rem 0 0; padding: 0; display: grid; gap: 2rem; }
.lv2.lv3 .l3-steps li { padding-top: 1.25rem; border-top: 1px solid var(--l3-line); }
.lv2.lv3 .l3-step-n { display: block; font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--l3-ink-3); }
.lv2.lv3 .l3-steps h3 { margin: .75rem 0 0; font-size: clamp(1.75rem, 2.6vw, 2.25rem); line-height: 1.05; font-weight: 800; letter-spacing: -.035em; color: var(--l3-ink); }
.lv2.lv3 .l3-steps p { margin: .625rem 0 0; max-width: 30ch; font-size: 17px; line-height: 1.5; color: var(--l3-ink-2); }

/* PRICING */
.lv2.lv3 .l3-pricing { max-width: var(--l3-max); margin: clamp(6rem, 12vw, 9rem) auto 0; scroll-margin-top: 96px; }
.lv2.lv3 .l3-phead .l3-p { max-width: 44ch; }
.lv2.lv3 .l3-plans { margin-top: 2.5rem; display: grid; gap: 16px; align-items: stretch; }
.lv2.lv3 .l3-plan { display: flex; flex-direction: column; min-width: 0; padding: 28px 24px 24px; border-radius: 28px; background: var(--l3-card); box-shadow: 0 0 0 1px var(--l3-line); }
.lv2.lv3 .l3-plan.is-top { box-shadow: 0 0 0 2px var(--l3-lime); }
html[data-theme="light"] .lv2.lv3 .l3-plan.is-top { box-shadow: 0 0 0 2px var(--l3-lime), 0 0 0 3px rgba(0,0,0,.12); }
.lv2.lv3 .l3-plan-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.lv2.lv3 .l3-plan-name { margin: 0; font-size: 24px; font-weight: 800; letter-spacing: -.03em; color: var(--l3-ink); }
.lv2.lv3 .l3-plan-pick { flex: none; padding: 6px 12px; border-radius: 999px; font-size: 13px; font-weight: 600; background: var(--l3-card-2); color: var(--l3-ink); }
.lv2.lv3 .l3-plan-tag { margin: .5rem 0 0; font-size: 15px; line-height: 1.45; color: var(--l3-ink-2); }
.lv2.lv3 .l3-plan-price { margin: 1.5rem 0 0; display: flex; align-items: baseline; gap: 4px; }
.lv2.lv3 .l3-fig { font-size: clamp(2.75rem, 5vw, 3.5rem); line-height: 1; font-weight: 800; letter-spacing: -.045em; font-variant-numeric: tabular-nums; color: var(--l3-ink); }
.lv2.lv3 .l3-per { font-size: 17px; font-weight: 600; color: var(--l3-ink-3); }
.lv2.lv3 .l3-plan-year, .lv2.lv3 .l3-plan-intro { margin: .5rem 0 0; font-size: 15px; line-height: 1.45; color: var(--l3-ink-2); }
.lv2.lv3 .l3-feats { list-style: none; margin: 1.5rem 0 0; padding: 1.25rem 0 0; border-top: 1px solid var(--l3-line); display: grid; gap: 12px; flex: 1 1 auto; }
.lv2.lv3 .l3-feats li { display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: 10px; font-size: 15px; line-height: 1.45; color: var(--l3-ink); }
.lv2.lv3 .l3-feats i { margin-top: 4px; font-size: 13px; color: var(--l3-ink-2); }
.lv2.lv3 .l3-plan-btn { margin-top: 1.75rem; width: 100%; }
.lv2.lv3 .l3-compare { margin: 1.5rem 0 0; text-align: center; }
.lv2.lv3 .l3-compare a { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; font-size: 16px; font-weight: 600; color: var(--l3-ink); text-decoration: none; }
.lv2.lv3 .l3-compare i { font-size: 13px; }
.lv2.lv3 .l3-legal { color: var(--l3-ink-3); }

/* ACADEMIES */
.lv2.lv3 .l3-acad { max-width: var(--l3-max); margin: clamp(6rem, 12vw, 9rem) auto 0; padding-top: clamp(3rem, 6vw, 4.5rem); border-top: 1px solid var(--l3-line); display: grid; gap: 2.5rem; scroll-margin-top: 96px; }
.lv2.lv3 .l3-acad .l3-h2 { font-size: clamp(1.875rem, 3.4vw, 3rem); }
.lv2.lv3 .l3-rows { margin: 0; display: grid; gap: 0; }
.lv2.lv3 .l3-rows > div { padding: 1.125rem 0; border-top: 1px solid var(--l3-line); }
.lv2.lv3 .l3-rows dt { font-size: 17px; font-weight: 700; color: var(--l3-ink); }
.lv2.lv3 .l3-rows dd { margin: .25rem 0 0; font-size: 15px; line-height: 1.45; color: var(--l3-ink-2); }

/* FAQ */
.lv2.lv3 .l3-faq { max-width: var(--l3-max); margin: clamp(6rem, 12vw, 9rem) auto 0; scroll-margin-top: 96px; }
.lv2.lv3 .l3-faq-list { max-width: 52rem; margin-top: 2rem; border-bottom: 1px solid var(--l3-line); }
.lv2.lv3 .l3-q { border-top: 1px solid var(--l3-line); }
.lv2.lv3 .l3-q summary { list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 64px; padding: 14px 0; font-size: clamp(1.0625rem, 1.6vw, 1.25rem); font-weight: 600; letter-spacing: -.01em; color: var(--l3-ink); }
.lv2.lv3 .l3-q summary::-webkit-details-marker { display: none; }
.lv2.lv3 .l3-q summary i { position: relative; flex: none; width: 14px; height: 14px; }
.lv2.lv3 .l3-q summary i::before, .lv2.lv3 .l3-q summary i::after { content: ""; position: absolute; left: 0; top: 6px; width: 14px; height: 2px; border-radius: 2px; background: var(--l3-ink-2); transition: transform .25s ease; }
.lv2.lv3 .l3-q summary i::after { transform: rotate(90deg); }
.lv2.lv3 .l3-q[open] summary i::after { transform: rotate(0deg); }
.lv2.lv3 .l3-q p { margin: 0; padding: 0 0 1.25rem; max-width: 60ch; font-size: 16px; line-height: 1.55; color: var(--l3-ink-2); }

/* CLOSE */
.lv2.lv3 .l3-close { max-width: var(--l3-max); margin: clamp(6rem, 12vw, 9rem) auto 0; padding: 0 0 clamp(5rem, 10vw, 8rem); text-align: center; display: flex; flex-direction: column; align-items: center; }
.lv2.lv3 .l3-mark { width: 56px; height: 56px; margin: 0 0 1.75rem; }
.lv2.lv3 .l3-close-h { font-size: clamp(2.75rem, 7vw, 6rem); letter-spacing: -.05em; }
.lv2.lv3 .l3-close .l3-p { margin-inline: auto; }
.lv2.lv3 .l3-close .l3-btn { margin-top: 2rem; }

/* reveal (IO adds .is-in once) */
.lv2.lv3.l3-live .l3-io { opacity: 0; transform: translateY(24px); transition: opacity .8s ease, transform .9s cubic-bezier(.2, .8, .2, 1); }
.lv2.lv3.l3-live .l3-io.is-in { opacity: 1; transform: none; }

/* phone pill: appears once the hero button has scrolled away, hides at the closing button */
.lv2.lv3 .l3-pill { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; display: flex; justify-content: center; padding: 0 16px calc(16px + env(safe-area-inset-bottom, 0px)); pointer-events: none; transform: translateY(140%); transition: transform .45s cubic-bezier(.2, .8, .2, 1); }
.lv2.lv3 .l3-pill.is-on { transform: none; }
.lv2.lv3 .l3-pill .l3-btn { pointer-events: auto; min-width: min(100%, 320px); box-shadow: 0 12px 32px -8px rgba(0,0,0,.45); }

@media (min-width: 720px) {
  .lv2.lv3 .l3-phone { --fw: 300px; }
  .lv2.lv3 .l3-steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.5rem; }
  .lv2.lv3 .l3-plans { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 54rem; margin-inline: auto; }
  .lv2.lv3 .l3-phead { text-align: center; }
  .lv2.lv3 .l3-phead .l3-p { margin-inline: auto; }
  .lv2.lv3 .l3-rows { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 2.5rem; }
}
@media (min-width: 960px) {
  .lv2.lv3 .l3-hero { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); align-items: center; min-height: calc(100svh - 92px); padding-top: 0; gap: 2rem; }
  .lv2.lv3 .l3-phone { --fw: clamp(300px, 24vw, 350px); }
  .lv2.lv3 .l3-chapters { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 3rem; }
  .lv2.lv3 .l3-ch-list { grid-area: 1 / 1; }
  .lv2.lv3 .l3-ch-stage { grid-area: 1 / 2; top: calc(50vh - clamp(280px, 22vw, 330px) * 1.0271 + 30px); }
  .lv2.lv3 .l3-ch-stage .l3-phone { --fw: clamp(280px, 22vw, 330px); }
  .lv2.lv3 .l3-ch { min-height: 82vh; justify-content: center; padding: 0; }
  .lv2.lv3 .l3-ch-copy { padding: 0; border-radius: 0; background: none; box-shadow: none; }
  .lv2.lv3 .l3-ch-copy .l3-h2 { font-size: clamp(2.125rem, 4.6vw, 4rem); }
  .lv2.lv3.l3-live .l3-ch { opacity: .28; transition: opacity .5s ease; }
  .lv2.lv3.l3-live .l3-ch.is-on { opacity: 1; }
  .lv2.lv3 .l3-honest { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4rem; }
  .lv2.lv3 .l3-acad { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4rem; align-items: start; }
  .lv2.lv3 .l3-pill { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .lv2.lv3 .l3-scr, .lv2.lv3 .l3-io, .lv2.lv3 .l3-ch { animation: none; transition: none; }
}
.lv2.lv3.l3-still .l3-io { opacity: 1; transform: none; }
.lv2.lv3.l3-still .l3-pill { display: none; }
