/* ===========================================================================
   My Track Record — website v4, DIRECTION A ("Signature Wash")
   Evolves the live v3 cinematic hero onto the app's SHIPPED Signature look.
   Rebuilt S32 around one promise (see index.html's head comment).

   EVERY colour below is an app token. Sources:
     constants/theme.ts        lightTheme / darkTheme / ACCENT_DEFS.Ocean
     constants/signatureElevation.ts   SIGNATURE_FROST (frost a 0.78, hairline 0.65)
   Nothing is invented. See WEBSITE-V4-LANE-S28.md "Palette provenance".

   CONTRAST LAW (measured, not eyeballed — figures in the lane record):
     - Bare wash carries ONLY --ink (#221a2e). Min 10.08:1 across all six
       wash stops. This mirrors the app's own bare-text promotion rule.
       (--ink at .78 opacity — the kicker and the note — composites to
       ≥ 5.96:1 on the darkest stop; gated in contrast-check.js.)
     - --ink-2 (#6f6578) and --accent (#4f46e5) carry body/accent copy ONLY
       on a frosted or white card. Measured 4.98:1 and 5.67:1 at the worst stop.
     - White labels sit on the indigo->violet HALF of the app accent gradient
       (#4f46e5 -> #7c2fe0, both 6.29:1). The sky stop #5ec8fb measures 1.89:1
       against white and is therefore DECORATIVE ONLY — never behind text.

   ONE SCALE EACH (S32 rebuild):
     radius  --r-sm 14 (chips, buttons)  --r-md 22 (cards,
             the demo, plans, FAQ)  --r-lg 40 (the phone ring, the Pro panel).
             The screen inside a ring is derived (--r-lg − 10 = 30, the fan's
             own figure). Excluded: the 30px app icon's own mask (9) and the
             focus ring (6) — neither is a surface.
     body    --fs-body 15 · --fs-cap 13.5 · --fs-lede clamp(17 → 19).
     bezel   ONE: the fan's device ring (.phone.has-shot) on every capture.
   ========================================================================== */

/* --- tokens ------------------------------------------------------------- */
:root {
  /* Signature wash — lightTheme.bgGradient, all six stops, at their
     shipped bgGradientLocations. */
  --wash-0: #f9cde9;
  --wash-1: #f5d3ee;
  --wash-2: #eee0f4;
  --wash-3: #f3ecf9;
  --wash-4: #e4d9f0;
  --wash-5: #d1c3e5;

  --ink: #221a2e;          /* lightTheme.textPrimary */
  --ink-2: #635a6d;        /* lightTheme.textMuted AS RENDERED on Signature frost — IN_CARD_TEXT_BOOST .15 toward textPrimary (S33 colour audit) — card surfaces only */

  --accent: #4f46e5;       /* ACCENT_DEFS.Ocean.accent */
  --accent-sky: #5ec8fb;   /* ACCENT_DEFS.Ocean.accentGradient[0] — decorative */
  --accent-2: #38bdf8;     /* lightTheme.accentSecondary (ACCENT_2, sky-400) — the mic ring's outer stops */
  --accent-violet: #7c2fe0;/* ACCENT_DEFS.Ocean.accentGradient[2] */
  --accent-light: #9aa5ff; /* ACCENT_DEFS.Ocean.accentLight — on plum only */
  --accent-soft: rgba(241, 240, 253, 0.78); /* accentSoft IN FORCE on Signature: tintFrostWithAccent(SIGNATURE_FROST.surface, accent, .08) — the 'Use 2,500' fill */

  /* Label-safe half of the app gradient. */
  --grad: linear-gradient(135deg, var(--accent) 0%, var(--accent-violet) 100%);
  /* Full app gradient — decorative rings/glows, never behind text. */
  --grad-full: linear-gradient(135deg, var(--accent-sky) 0%, var(--accent) 50%, var(--accent-violet) 100%);

  /* SIGNATURE_FROST */
  --frost: rgba(255, 255, 255, 0.78);
  --frost-border: rgba(255, 255, 255, 0.65);
  --catchlight: rgba(255, 255, 255, 0.85);   /* SIGNATURE_FROST.catchlight */
  --hairline: rgba(120, 70, 140, 0.14);      /* lightTheme.border */

  /* Entry badge tokens — lightTheme.badge*Bg / badge*Text */
  --badge-food-bg: #fdeee0;   --badge-food-fg: #c2410c;
  --badge-work-bg: #e3f6ec;   --badge-work-fg: #166534;   /* W4-S36 (F25): the app's green-700 (#15803d) sits at 4.46:1 on this bg — under AA at 14px bold — so the web chip takes green-800, 6.34:1; same family, same bg */
  --badge-hydr-bg: #e6f0ff;   --badge-hydr-fg: #1d4ed8;
  --badge-body-bg: #f1e9ff;   --badge-body-fg: #7c3aed;

  --plum: #160f1c;            /* darkTheme.background */
  --plum-card: #221a28;       /* darkTheme.cardSurface */
  --plum-ink-2: #c5bbcf;      /* darkTheme.textSecondary — 9.07:1 on plum */

  --shadow-card: 0 12px 30px rgba(122, 42, 110, 0.14);   /* cardShadow(cardShadowDeep): #7a2a6e @ .14, r 30, y 12 */
  --shadow-lift: 0 18px 44px rgba(60, 20, 70, 0.16);

  /* the three-step radius scale */
  --r-sm: 14px;
  --r-md: 22px;
  --r-lg: 40px;
  /* the body-size scale */
  --fs-body: 15px;
  --fs-cap: 13.5px;
  --fs-lede: clamp(17px, 1.8vw, 19px);

  --measure: 62ch;
}

/* --- reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
body {
  margin: 0;
  font-family: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  color: var(--ink);
  background: var(--wash-3);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
h1, h2, h3, p, figure, blockquote { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }

/* The designed wash, painted once behind the whole page — the rose "crown"
   compresses across the header, the palest stop lands in the record field,
   and the deep violet seats at the bottom (behind the footer). */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    180deg,
    var(--wash-0) 0%, var(--wash-1) 14%, var(--wash-2) 32%,
    var(--wash-3) 62%, var(--wash-4) 86%, var(--wash-5) 100%
  );
}

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: #fff; padding: 12px 18px; border-radius: 0 0 var(--r-sm) 0; z-index: 99;
}
.skip:focus { left: 0; }

:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

.wrap { width: min(1120px, 100% - 40px); margin-inline: auto; }
@media (max-width: 600px) { .wrap { width: min(1120px, 100% - 32px); } }

/* --- header ------------------------------------------------------------- */
.site-head {
  position: sticky; top: 0; z-index: 20;
  background: rgba(249, 205, 233, 0.72);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--frost-border);
}
.site-head .wrap { display: flex; align-items: center; gap: 20px; height: 64px; }
@media (max-width: 600px) { .site-head .wrap { height: 56px; } }
.mark { display: flex; align-items: center; gap: 10px; font-weight: 800; letter-spacing: -0.01em; }
.mark img { width: 30px; height: 30px; border-radius: 9px; box-shadow: 0 3px 10px rgba(60,20,70,.18); }
.nav { margin-left: auto; display: flex; align-items: center; gap: 24px; font-size: var(--fs-body); font-weight: 600; }
.nav a.plain { color: var(--ink); }
.nav a.plain:hover { color: var(--accent); }
@media (max-width: 760px) { .nav a.plain { display: none; } }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font: inherit; font-weight: 700; border-radius: var(--r-sm); padding: 14px 26px;
  border: 1px solid transparent; cursor: pointer; text-align: center;
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.btn:hover { transform: translateY(-1px); }
/* W1-S36 (Andrew: "a very thin dark bar on the left side" of every Download
   free button). Root cause: .btn carries `border: 1px solid transparent`, and a
   background-image is sized to the PADDING box by default (background-origin)
   while it is painted out to the BORDER box (background-clip) — so the
   gradient tile repeats under the transparent border, and the left 1px column
   shows the tile's wrapped RIGHT edge (indigo → violet, the darkest stops)
   beside the sky-blue start. Sizing the gradient to the border box makes it
   one continuous fill; padding, size and hover are untouched. */
.btn-primary { background-image: var(--grad-full); background-origin: border-box; background-clip: border-box; color: #fff; box-shadow: 0 10px 24px rgba(79,70,229,.28); }
.btn-primary:hover { box-shadow: var(--shadow-lift); }
.btn-quiet { background: #fff; color: var(--ink); border-color: var(--hairline); box-shadow: var(--shadow-card); }
/* header pill: ≥ 44px tall (the tap-target guideline) */
.btn-sm { padding: 10px 18px; font-size: 14px; min-height: 44px; }

/* --- the one label style ------------------------------------------------
   A plain kicker: --ink on the wash (the bare-wash law), softened to .78 —
   composited ≥ 5.96:1 on the darkest stop. On plum it is --accent-light. */
.kicker {
  font-size: var(--fs-cap); font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink); opacity: .78;
}

/* --- hero --------------------------------------------------------------- */
.hero { padding: clamp(40px, 7vw, 96px) 0 clamp(48px, 7vw, 88px); }
/* Three areas so the demo card can sit ABOVE the buttons on phone and beside
   the copy on desktop (the fold keeps a picture at 390). */
.hero-grid {
  display: grid; gap: clamp(28px, 4vw, 40px) clamp(36px, 5vw, 64px);
  grid-template-columns: 1fr;
  grid-template-areas: "head" "demo" "act";
}
.hero-head { grid-area: head; }
.demo { grid-area: demo; }
.hero-act { grid-area: act; }
@media (min-width: 940px) {
  .hero-grid {
    grid-template-columns: 1.05fr 0.95fr;
    grid-template-rows: auto auto;
    grid-template-areas: "head demo" "act demo";
    align-items: center; row-gap: 0;
  }
  .hero-head { align-self: end; }
  .hero-act { align-self: start; }
}

h1 {
  margin-top: 16px;
  /* Capped at 54px so the promise sets on two lines in the hero column at 1280+
     ("that knows you train." is the long line). */
  font-size: clamp(36px, 5vw, 54px);
  line-height: 1.06; letter-spacing: -0.035em; font-weight: 800;
  text-wrap: balance;
}
/* W4-S36 (F24, the mechanism half): the hard <br> in the h1 exists for the
   desktop two-line set; under 940 it defeats text-wrap: balance at 36px and
   orphans a word on its own line whichever headline wins. The text is untouched —
   the break simply doesn't apply on phone. */
@media (max-width: 939px) { h1 br { display: none; } }
/* W7 (Andrew, 2026-09-17): the second line is one colour, lighter weight — the
   gradient-filled text read as "a huge AI tell"; the brand colour stays on the
   mic and the buttons, where it means something. Same class name so the h1
   markup and the share card don't change. */
h1 .grad {
  color: var(--ink); -webkit-text-fill-color: var(--ink);
  font-weight: 500; letter-spacing: -0.02em;
}
.lede { margin-top: 20px; font-size: var(--fs-lede); max-width: var(--measure); color: var(--ink); }
.hero-cta { margin-top: 30px; display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
@media (max-width: 600px) {
  .hero-cta { flex-direction: column; align-items: stretch; }
  .hero-cta .btn { width: 100%; }
}
.note { margin-top: 16px; font-size: var(--fs-cap); font-weight: 600; color: var(--ink); opacity: .78; max-width: var(--measure); }
/* W4-S36 (F1): the visible sample label under every capture row — the .note
   caption at its composited .78 (≥ 5.96:1 on the darkest stop, the kicker's
   own measure); on plum it takes --plum-ink-2 (9.07:1). */
.sample-note { margin-top: 18px; text-align: center; font-size: var(--fs-cap); font-weight: 600; color: var(--ink); opacity: .78; }
.pro-text .sample-note { text-align: left; margin-top: 18px; color: var(--plum-ink-2); opacity: 1; }
.cta-row { margin-top: 40px; display: flex; justify-content: center; }
/* the trial line under a centered CTA row (coach section, R77-S35) */
.cta-note { margin-top: 14px; text-align: center; margin-inline: auto; }

/* --- the voice demonstration (web graphic — NOT an app screen) ----------- */
.demo {
  background: var(--frost);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border: 1px solid var(--frost-border);
  border-radius: var(--r-md); padding: 26px;
  box-shadow: var(--shadow-lift);
  position: relative;
}
.demo::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: var(--catchlight); border-radius: var(--r-md) var(--r-md) 0 0;
}
.demo-label {
  font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-2);
}
.demo-said {
  margin-top: 14px; display: flex; gap: 14px; align-items: flex-start;
}
/* W1-S36: the demo's mic IS the app's RecordButton (components/RecordButton.tsx):
   ring = LinearGradient [accentSecondary, #fff, accent, accentSecondary] from
   (0,0) to (1,1); disc = cardSurfaceSolid (#fff) at 74% of the button; glyph =
   Ionicons "mic" at 40% of the button in accentOnCard (the accent). 46 → 34 → 18. */
.mic {
  flex: none; width: 46px; height: 46px; border-radius: 50%;
  background-image: linear-gradient(135deg, var(--accent-2) 0%, #fff 33.3%, var(--accent) 66.7%, var(--accent-2) 100%);
  display: grid; place-items: center;
  box-shadow: 0 8px 20px rgba(79,70,229,.34);
}
.mic-disc { width: 34px; height: 34px; border-radius: 50%; background: #fff; display: grid; place-items: center; }
.mic svg { width: 18px; height: 18px; fill: var(--accent); }
.said {
  font-size: clamp(19px, 2.4vw, 23px); font-weight: 700; line-height: 1.4;
  letter-spacing: -0.015em; color: var(--ink);
}
.said .q { color: var(--accent); }

.arrow { margin: 20px 0 16px; display: flex; align-items: center; gap: 12px; color: var(--ink-2); font-size: var(--fs-cap); font-weight: 700; }
.arrow::before, .arrow::after { content: ""; height: 1px; background: var(--hairline); flex: 1; }

.chips { display: flex; flex-wrap: wrap; gap: 9px; }
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 13px; border-radius: var(--r-sm); font-size: 14px; font-weight: 700;
}
.chip .kcal { font-weight: 800; } /* W4-S36 (F25): no opacity — at .85 the three chips composited to 3.64 / 3.46 / 4.41:1; solid they read 4.56 / 6.34 / 5.83 */
.chip-food { background: var(--badge-food-bg); color: var(--badge-food-fg); }
.chip-work { background: var(--badge-work-bg); color: var(--badge-work-fg); }
.chip-hydr { background: var(--badge-hydr-bg); color: var(--badge-hydr-fg); }
.chip-body { background: var(--badge-body-bg); color: var(--badge-body-fg); }
.demo-foot { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--hairline); font-size: var(--fs-cap); color: var(--ink-2); }

/* --- sections ----------------------------------------------------------- */
section { padding: clamp(48px, 7vw, 88px) 0; }
h2 { margin-top: 14px; font-size: clamp(28px, 4.2vw, 44px); line-height: 1.12; letter-spacing: -0.03em; font-weight: 800; max-width: 20ch; text-wrap: balance; }
.sec-lede { margin-top: 16px; font-size: var(--fs-lede); max-width: var(--measure); color: var(--ink); }

.card {
  background: var(--frost);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border: 1px solid var(--frost-border); border-radius: var(--r-md);
  padding: 26px; box-shadow: var(--shadow-card); position: relative;
}
.card::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 1px; background: var(--catchlight); border-radius: var(--r-md) var(--r-md) 0 0; }
.card h3 { font-size: 20px; font-weight: 800; letter-spacing: -0.02em; }
.card p { margin-top: 10px; color: var(--ink-2); font-size: var(--fs-body); }

/* --- capture slots ------------------------------------------------------
   Every capture slot is a real <img> pointing at a FIXED filename under
   assets/captures/. Three states, no fake screen in any of them:
     • file present            -> onload adds .has-shot; the real capture shows and
                                  the placeholder is removed from the a11y tree.
     • file absent             -> onerror removes the <img>; the labelled
                                  placeholder below is what remains.
     • inline handlers blocked -> the <img> stays at opacity 0 and the labelled
                                  placeholder is what remains. Same safe end state.
   The frame is page furniture. The SCREEN is never drawn. */
.phone {
  position: relative;
  aspect-ratio: 9 / 19.5;
  border-radius: var(--r-lg);
  border: 2px dashed rgba(79, 70, 229, 0.42);
  background: var(--frost);   /* SIGNATURE_FROST.surface — measured, see contrast-check.js */
  display: grid; place-content: center; gap: 8px; text-align: center; padding: 22px;
}
.phone .screen {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  opacity: 0;
  border-radius: calc(var(--r-lg) - 10px);
}
/* THE ONE BEZEL (S32): every capture on the page wears the fan's DEVICE RING —
   a plain rounded ring, no notch, no island, which is what keeps the CSS bezel
   licence-safe (same rule as the store set). The ring is a padding on the
   frame; the screen keeps its own corner radius inside it. On the light wash
   the ring is what makes a light Home read as an object, not a card. */
.phone.has-shot {
  aspect-ratio: auto;
  display: block; overflow: hidden;
  padding: 8px;
  border: 1px solid rgba(0, 0, 0, 0.55);
  background: #101014;
  border-radius: var(--r-lg);
  box-shadow: 0 22px 48px rgba(60, 20, 70, 0.22), inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}
.phone.has-shot .screen { position: static; opacity: 1; width: 100%; height: auto; border-radius: calc(var(--r-lg) - 10px); display: block; }
.phone.has-shot .slot { display: none; }
.phone .slot { display: grid; gap: 8px; }
.phone .slot-k { font-size: 12px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); }
.phone .slot-v { font-size: var(--fs-body); font-weight: 700; color: var(--ink); }
.phone .slot-n { font-size: var(--fs-cap); color: var(--ink-2); }
.phone .slot-f { font-size: 11.5px; font-weight: 700; color: var(--ink-2); word-break: break-all; opacity: .85; }
.shot-cap { margin-top: 12px; font-size: var(--fs-cap); font-weight: 700; color: var(--ink); }

/* --- how it works: three beats, each under its real screen ---------------
   ≈ 358px frames at 1120 (the old See-it size); one-up at ≤ 899px with the
   phone held to 320px so three screens don't cost four viewports on a phone. */
.beats { margin-top: 44px; display: grid; gap: 36px 22px; grid-template-columns: 1fr; }
@media (min-width: 900px) { .beats { grid-template-columns: repeat(3, 1fr); } }
.beat .phone { max-width: 300px; margin-inline: auto; }
@media (max-width: 600px) { .beat .phone { max-width: 272px; } }
@media (min-width: 900px) { .beat .phone { max-width: none; } }
.beat figcaption { margin-top: 18px; max-width: 40ch; }
/* W10-A (Andrew, 2026-09-17): anatomy A with the feature name ABOVE the phone and the
   tagline BELOW it, framing the picture; the supporting line is gone — the capture
   already says it. */
.beat .beat-kicker { margin: 0 auto 14px; max-width: 40ch; text-align: center; }
/* W10-A2 (Andrew): "center them over each phone. And each phone should be inline" —
   the name is centred at every width, and the coach beats share rows through a
   subgrid (name · phone · tagline), so a two-line name can't push its phone down
   below its neighbours. Fallback for browsers without subgrid: the name reserves
   two lines. */
.beats.coach .beat { display: grid; grid-template-rows: auto auto auto; align-items: end; }
.beats.coach .beat .beat-kicker { min-height: calc(2 * 1.35em); display: flex; align-items: flex-end; justify-content: center; }
@supports (grid-template-rows: subgrid) {
  .beats.coach { grid-auto-rows: auto; }
  .beats.coach .beat { grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; }
  .beats.coach .beat .beat-kicker { min-height: 0; }
  .beats.coach .beat figcaption { align-self: start; }
}
/* W10-A3 (Andrew): the tagline sits the same distance from the bezel on both rows
   (the subgrid no longer adds the section's row gap inside the card), and it wraps
   in two natural lines rather than running long — a ~18ch measure so "Know how
   your training has changed." breaks like its neighbours. */
.beats.coach .beat .beat-kicker { margin-bottom: 12px; }
.beats.coach .beat figcaption { margin-top: 14px; }
.beats.coach .beat h3 { max-width: 18ch; margin-inline: auto; }
@media (max-width: 899px) { .beat figcaption { margin-inline: auto; text-align: center; } }
.beat h3 { margin-top: 0; font-size: 20px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.25; text-wrap: balance; }
.beat figcaption > p:not(.kicker) { margin-top: 10px; color: var(--ink); font-size: var(--fs-body); }
/* W10-S36 (Andrew): the ONE supporting line under the tagline — --ink at .78
   (the wash carries only --ink; the kicker/note figure, ≥ 5.96:1), body size,
   regular weight. The old .sample frost card is gone: every capture on the
   page already prints the card's sentence, so quoting it was the same
   information a fourth time in a fourth style. Three styles per card, not four. */
.beat .line { margin-top: 8px; font-size: var(--fs-body); font-weight: 400; line-height: 1.5; color: var(--ink); opacity: .78; }
/* the coach section (S33, condensed; R88 2026-09-16 adds a face to each row):
   the faces row is the two goal faces + the weekly finding — two-up on phone,
   three-up from 900 like the base rule; the coach row is the three timescales
   + the plan face — two-up on phone (a 2×2, never four viewports), four-up from
   1100 where four 263px phones still clear the 280 cap's neighbourhood. */
.beats.faces, .beats.coach { grid-template-columns: repeat(2, 1fr); gap: 28px 14px; }
.beats.faces .phone, .beats.coach .phone { max-width: 280px; }
.beats.faces figcaption, .beats.coach figcaption { margin-inline: auto; text-align: center; }
/* an odd count in a two-up grid leaves the last beat alone beside an empty
   cell on phone — it spans the pair instead, centered, so the row never ends
   lopsided. Keyed on parity (R88): the faces are three, the timescales four,
   so an even row keeps its 2×2 and only an odd one spans its last beat. */
@media (max-width: 899px) { .beats.faces .beat:last-child:nth-child(odd) { grid-column: 1 / -1; } }
@media (max-width: 1099px) { .beats.coach .beat:last-child:nth-child(odd) { grid-column: 1 / -1; } }
/* R77-S35: under 480px the goal faces go one-up — two-up put a seven-line
   quote in a 165px card and the capture below legibility (the audit's worst
   section on phone). The phone holds to the .beat phone cap (272px ≤ 600). */
@media (max-width: 479px) { .beats.faces { grid-template-columns: 1fr; gap: 36px; } }
/* W4-S36 (F23): the same rule for the coach row — its plan face carries the full
   anatomy (h3 + setup; the quote went in W10) and, the row being four (even), the parity span
   above never rescued it: a six-line quote beside a ~172px phone at 390. One-up
   under 480, the 272px phone cap holding. */
@media (max-width: 479px) { .beats.coach { grid-template-columns: 1fr; gap: 36px; } }
@media (min-width: 900px) { .beats.faces { grid-template-columns: repeat(3, 1fr); gap: 36px 22px; } }
@media (min-width: 1100px) { .beats.coach { grid-template-columns: repeat(4, 1fr); gap: 36px 22px; } }

/* --- the theme fan (S32, ruling 43) -------------------------------------
   Five .phone bezels on one absolutely-positioned stage. --i is the phone's seat
   (-2 … 2, left → right, light → dark); Signature is seat 0, in FRONT, upright,
   fully visible and seated highest. Each seat behind it steps out by --step,
   sits --drop lower and tilts --tilt per seat (max 2·--tilt ≤ 12°) around its
   own bottom edge, so the tops fan open like a hand of cards. The stage's
   aspect-ratio reserves the height (the phones are out of flow) and every
   number is a % of the stage width so the fan is fluid inside each tuning.
   Nothing is clipped. The three tunings are sized so the outermost tilted
   corner stays inside the viewport at 1024, 768, 600 and 390 (the swing of a
   tilted phone is (w/2)·cosθ + h·sinθ from its seat — see the lane record).
   No hover or scroll effect — the composition is still. */
/* W1-S36: Themes is a coda, not a pitch (Andrew: "not a selling point … help them
   stick around once they are in it"). The section keeps the fan but takes about
   a quarter less room on desktop (measured 986 → ~750 px at 1280): shorter padding,
   the h2 at the h3 scale, the lede at body size, the fan a step narrower (its
   height follows its width via aspect-ratio). */
.themes-coda { padding: clamp(32px, 4.5vw, 56px) 0; }
.themes-coda h2 { font-size: clamp(22px, 2.6vw, 28px); margin-top: 10px; max-width: none; }
.themes-coda .sec-lede { font-size: var(--fs-body); margin-top: 10px; }
.themes-coda .fan { margin-top: 26px; width: min(70%, 720px); }
.fan { margin: 40px auto 0; width: min(88%, 960px); }
.fan-stage {
  --pw: 24%;      /* phone width */
  --step: 15%;    /* horizontal step per seat */
  --drop: 5%;     /* how much lower each seat behind sits */
  --base: 3%;     /* room under the outermost seats for their tilted corners */
  --tilt: 6deg;   /* per seat; the outer seats carry 12° */
  position: relative;
  aspect-ratio: 960 / 595;
}
.fan-phone {
  position: absolute;
  width: var(--pw);
  left: calc(50% - var(--pw) / 2 + var(--i) * var(--step));
  bottom: calc(var(--base) + var(--lift, 0%));
  transform-origin: 50% 100%;
  transform: rotate(calc(var(--i) * var(--tilt)));
}
.fan-phone[style*="--i:0"]  { --lift: calc(var(--drop) * 2); z-index: 5; }
.fan-phone[style*="--i:-1"], .fan-phone[style*="--i:1"] { --lift: var(--drop); z-index: 4; }
.fan-phone[style*="--i:-2"], .fan-phone[style*="--i:2"] { --lift: 0%; z-index: 3; }
/* S32 (Andrew): the fan's phones wear a DEVICE RING, not a hairline, so the four
   backgrounds read as phones rather than cards. That ring is now the site's one
   bezel (.phone.has-shot above, same figures); the fan's composition is unchanged. */
.fan-phone .slot { padding: 0; }
.fan-phone .slot-k { font-size: 11px; }
.fan-phone .slot-v { font-size: 12.5px; }
.fan-phone .slot-n, .fan-phone .slot-f { font-size: 10.5px; }
.fan-cap { text-align: center; margin-top: 22px; }
.fan-arrow { margin: 0 .25em; }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
/* tablet: same fan, the phones a little wider relative to the stage */
@media (max-width: 1023px) {
  .fan { width: min(92%, 960px); }
  .themes-coda .fan { width: min(80%, 720px); }
  .fan-stage { --pw: 30%; --step: 14%; --drop: 4.5%; aspect-ratio: 760 / 570; }
}
/* phone: a tighter overlap — Signature stays a real phone (38% of the width,
   ≈136px at 390) and the four behind it show as fanned edges, never a 5-wide
   row of thumbnails. The tilt eases to 3° per seat so the corners stay inside
   the 16px page margin. */
@media (max-width: 600px) {
  .fan { margin-top: 30px; width: 100%; }
  .themes-coda .fan { margin-top: 22px; width: 100%; }
  .fan-stage { --pw: 38%; --step: 12%; --drop: 3.5%; --base: 2%; --tilt: 3deg; aspect-ratio: 358 / 332; }
  .fan-phone .slot-n, .fan-phone .slot-f { display: none; }
  .fan-cap { margin-top: 16px; }
}

/* --- pro: the one dark block, about one viewport --------------------------
   Placeholder ink on the dark ground is re-tokened: #9aa5ff 7.33:1,
   #ffffff 16.73:1, #c5bbcf 9.07:1 on #160f1c (contrast-check.js). */
.pro { position: relative; }
.pro-panel {
  --pad: clamp(28px, 4vw, 48px);
  background: var(--plum); color: #fff; border-radius: var(--r-lg);
  padding: var(--pad); box-shadow: var(--shadow-lift);
  position: relative; overflow: hidden;
}
.pro-panel::after {
  content: ""; position: absolute; right: -120px; top: -120px; width: 380px; height: 380px;
  background-image: var(--grad-full); filter: blur(90px); opacity: .38; border-radius: 50%;
}
.pro-panel > * { position: relative; }
.pro-panel .kicker { color: var(--accent-light); opacity: 1; }
.pro-panel h2 { color: #fff; }
.pro-panel .sec-lede { color: var(--plum-ink-2); }

/* The strip: [text column] [Fueling check] [Ask]. W13 (Andrew, 2026-09-17):
   the phones are WHOLE — no fixed height, no open bottom edge — each capped at
   the page's phone width (300px) and centred in its column, the caption centred
   over it. Two-up while Recovery waits; a third 1fr column takes it when it
   lands. */
.pro-strip {
  margin-top: 36px; display: grid; gap: 28px; align-items: start;
  grid-template-columns: 1fr;
}
/* Desktop: the captions share one row and the phones another (subgrid), so a
   two-line caption over one phone doesn't push that phone's top below its
   neighbour's; each caption hugs its phone from above. */
@media (min-width: 900px) {
  .pro-strip { grid-template-columns: 240px 1fr 1fr; grid-template-rows: auto auto; row-gap: 0; }
  .pro-text { grid-row: 1 / span 2; }
  .pro-shot { display: grid; grid-row: 1 / span 2; grid-template-rows: subgrid; }
  .pro-shot .shot-cap { align-self: end; }
}
.pro-text h3 { font-size: 20px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.25; color: #fff; }
.pro-text p { margin-top: 10px; color: var(--plum-ink-2); font-size: var(--fs-body); }
.pro-text .pro-prep { margin-top: 18px; }
.pro-text .pro-prep strong { color: #fff; font-weight: 800; }
/* W13 (Andrew): the 17 sports as five short groups — a bold label, then its
   sports — so the reader finds their own in one scan without reading a wall
   of chips. Same 17, nothing dropped; the W4-S36 chip rules are retired. */
.sport-groups { margin-top: 10px; display: grid; gap: 8px; }
.sport-groups li { font-size: var(--fs-cap); line-height: 1.45; color: var(--plum-ink-2); }
.sport-groups strong { display: block; color: #fff; font-weight: 800; }
.pro-shot .shot-cap { margin: 0 auto 12px; max-width: 300px; text-align: center; text-wrap: balance; color: #fff; font-weight: 800; font-size: 16px; letter-spacing: -0.01em; }
.pro-shot .phone { max-width: 300px; margin-inline: auto; }
.pro-shot .phone.has-shot { box-shadow: 0 22px 48px rgba(0, 0, 0, 0.35); }
.pro-shot .phone:not(.has-shot) { border-color: rgba(154, 165, 255, 0.5); background: rgba(255, 255, 255, 0.05); }
.pro-shot .slot-k { color: var(--accent-light); font-size: 11px; }
.pro-shot .slot-v { color: #fff; }
.pro-shot .slot-n, .pro-shot .slot-f { color: var(--plum-ink-2); }
/* phone: the two screens in a snap-scroll row, each 82% of the panel's width
   (≈ 240px at 390 — never 139), both shown whole. */
@media (max-width: 899px) {
  .pro-strip { gap: 24px; }
  .pro-shots { display: flex; gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--pad); scrollbar-width: none; margin-inline: calc(-1 * var(--pad)); padding-inline: var(--pad); }
  .pro-shots::-webkit-scrollbar { display: none; }
  .pro-shot { flex: 0 0 82%; scroll-snap-align: start; }
  /* R77-S35: Ask (the page's best rendered answer) is the FIRST card on phone;
     Insights peeks at the right edge as the swipe affordance. Desktop order
     is untouched — this rule lives inside the ≤ 899 query only. */
  .pro-shot:last-child { order: -1; }
}
@media (min-width: 900px) { .pro-shots { display: contents; } }

/* --- pricing ------------------------------------------------------------ */
.plans { margin-top: 36px; display: grid; gap: 20px; grid-template-columns: 1fr; align-items: stretch; }
@media (min-width: 780px) { .plans { grid-template-columns: repeat(2, 1fr); } }
.plan { display: flex; flex-direction: column; padding: 30px; }
.plan .price { margin-top: 6px; font-size: 34px; font-weight: 800; letter-spacing: -0.03em; }
.plan .per { font-size: var(--fs-body); font-weight: 600; letter-spacing: 0; color: var(--ink-2); }
.plan ul { margin: 20px 0 0; display: grid; gap: 11px; }
.plan li { display: flex; gap: 10px; font-size: var(--fs-body); color: var(--ink-2); }
.plan li svg { flex: none; width: 18px; height: 18px; margin-top: 3px; fill: var(--accent); }
.plan .plan-foot { margin-top: auto; padding-top: 22px; font-size: var(--fs-cap); font-weight: 700; color: var(--ink-2); }
/* R76 — the earned-month line under the Pro card's foot; `hidden` until the probe answers. */
.plan .plan-guarantee { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--hairline); font-size: var(--fs-cap); font-weight: 600; color: var(--ink-2); line-height: 1.5; }
.plan .plan-guarantee[hidden] { display: none; }
.plan .plan-guarantee a { color: var(--accent); font-weight: 700; }

/* FAQ — five collapsed questions under the plans */
.faq { margin-top: 40px; display: grid; gap: 12px; max-width: 760px; margin-inline: auto; }
.faq details { padding: 0; }
.faq summary {
  cursor: pointer; list-style: none; padding: 18px 26px;
  font-size: var(--fs-body); font-weight: 700; color: var(--ink);
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; font-weight: 800; color: var(--accent); font-size: 20px; line-height: 1; flex: none; }
.faq details[open] summary::after { content: "–"; }
.faq details p { margin: 0; padding: 0 26px 20px; color: var(--ink-2); font-size: var(--fs-body); }

/* --- closing + footer --------------------------------------------------- */
.welcome {
  margin: 20px auto 0; max-width: 58ch;
  font-size: var(--fs-lede); color: var(--ink);
}
.close { text-align: center; }
.close h2 { margin-inline: auto; max-width: 22ch; }
.close .hero-cta { justify-content: center; }
.close .note { margin: 22px auto 0; }

.site-foot { background: var(--plum); color: #fff; padding: 56px 0 34px; }
.foot-grid { display: grid; gap: 34px; grid-template-columns: 1fr; }
@media (min-width: 760px) { .foot-grid { grid-template-columns: 1.5fr 1fr 1fr; } }
.site-foot p, .site-foot a { color: var(--plum-ink-2); font-size: var(--fs-body); }
.site-foot a:hover { color: #fff; text-decoration: underline; }
.site-foot h3 { margin: 0 0 14px; font-size: var(--fs-cap); font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: #fff; }
.site-foot li { margin-bottom: 9px; }
.foot-blurb { margin-top: 14px; max-width: 44ch; }
.foot-bar { margin-top: 40px; padding-top: 22px; border-top: 1px solid rgba(255,255,255,.12); display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; font-size: var(--fs-cap); color: var(--plum-ink-2); }

.store-row { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.site-foot .store-link { color: #fff; font-weight: 700; display: inline-flex; align-items: center; min-height: 44px; }
.soon {
  display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700;
  color: var(--ink-2); background: #fff; border: 1px solid var(--hairline);
  padding: 13px 20px; border-radius: var(--r-sm);
}
.site-foot .soon { background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.16); color: var(--plum-ink-2); }

/* --- W6: the free-offer band, full width, right under the hero -----------
   Ported from the W2 preview (2-band.html / "(2) full-width band"), C2 —
   Andrew's picked treatment. h2 is solid ink (no gradient text: "a huge AI
   tell" per Andrew, R-S36). The three method icons reuse the hero's OWN
   .mic ring treatment (gradient ring + white disc + accent glyph, from
   components/RecordButton.tsx via the .mic rule above) instead of the
   preview's separate filled-gradient-disc pattern, so the only gradient in
   this section is one already live on the page, on a disc, never on text. */
.free-band { padding: 0 0 clamp(40px, 6vw, 72px); }
.free-band .panel {
  background: var(--frost); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border: 1px solid var(--frost-border); border-radius: var(--r-md); box-shadow: var(--shadow-lift);
  padding: clamp(26px, 4vw, 40px); position: relative;
  display: grid; gap: 18px 40px; align-items: center;
  grid-template-columns: 1fr;
}
.free-band .panel::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 1px; background: var(--catchlight); border-radius: var(--r-md) var(--r-md) 0 0; }
@media (min-width: 900px) { .free-band .panel { grid-template-columns: 1.1fr 0.9fr; } }
.free-band h2 { margin-top: 10px; max-width: 20ch; font-size: clamp(28px, 4vw, 40px); color: var(--ink); }
.free-band .methods { display: grid; gap: 12px; }
.free-band .method {
  display: flex; align-items: center; gap: 14px; padding: 14px 16px;
  background: #fff; border: 1px solid var(--hairline); border-radius: var(--r-sm);
  font-weight: 700; color: var(--ink);
}
.free-band .method .ic {
  flex: none; width: 40px; height: 40px; border-radius: 50%;
  background-image: linear-gradient(135deg, var(--accent-2) 0%, #fff 33.3%, var(--accent) 66.7%, var(--accent-2) 100%);
  display: grid; place-items: center;
  box-shadow: 0 8px 20px rgba(79,70,229,.28);
}
.free-band .method .ic-disc { width: 30px; height: 30px; border-radius: 50%; background: #fff; display: grid; place-items: center; }
.free-band .method .ic svg { width: 16px; height: 16px; fill: var(--accent); }
.free-band .method .ex { font-weight: 600; color: var(--ink-2); font-size: var(--fs-cap); display: block; }

/* ==================== PHOTOGRAPHS (W17, from W14's proposals) ====================
   Two photographs on a fourteen-phone page: the woman logging in the free band
   (E) and the gym rack behind the Pro panel (B). Tokens only. The wash is the
   store frames' grade-highkey — a multiply of the page's OWN wash stops — so a
   photograph tints INTO the page instead of sitting on it; the plum panel uses
   a plum multiply so the rack tints DOWN into the dark ground. A photograph is
   a mood, not a claim: no photo implies a result or a customer. */
.ph { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.ph img {
  width: 100%; height: 100%; object-fit: cover; object-position: var(--ph-pos, 50% 50%);
  filter: saturate(var(--ph-sat, .6));
  transform: scale(var(--ph-zoom, 1)); transform-origin: var(--ph-pos, 50% 50%);
}
.ph .grade {
  position: absolute; inset: 0; mix-blend-mode: multiply; opacity: var(--ph-a, .42);
  background: linear-gradient(180deg, var(--wash-0) 0%, var(--wash-2) 46%, var(--wash-5) 100%);
}

/* (E) the woman logging inside the free band's panel. Desktop (≥ 900): a photo
   column on the left, full-bleed to the panel's rounded edge (negative margins
   undo the panel's padding), dissolving right into the frost under the h2.
   Phone: a 220px strip across the top, dissolving down into the frost. */
.free-band .panel.has-ph { grid-template-columns: 1fr; overflow: hidden; }
@media (min-width: 900px) { .free-band .panel.has-ph { grid-template-columns: 0.62fr 1fr 0.9fr; } }
.free-band .panel.has-ph .ph-col {
  position: relative; align-self: stretch; min-height: 260px;
  margin: calc(-1 * clamp(26px, 4vw, 40px)) 0 calc(-1 * clamp(26px, 4vw, 40px)) calc(-1 * clamp(26px, 4vw, 40px));
}
.free-band .panel.has-ph .ph-col .ph img { filter: saturate(.72); }
.free-band .panel.has-ph .ph-col .ph .grade { opacity: .34; }
.free-band .panel.has-ph .ph-col .ph::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent 55%, var(--frost) 100%); }
@media (max-width: 899px) {
  .free-band .panel.has-ph .ph-col { margin: calc(-1 * clamp(26px, 4vw, 40px)) calc(-1 * clamp(26px, 4vw, 40px)) 0; min-height: 220px; }
  .free-band .panel.has-ph .ph-col .ph::after { background: linear-gradient(180deg, transparent 55%, var(--frost) 100%); }
}

/* (B) the gym rack behind the Pro panel. The photograph is darkened and
   desaturated, a plum multiply (--plum → --plum-card → --plum) tints it down,
   and a left-to-right plum gradient keeps the text column on near-solid plum
   (the rack shows on the right, under the phones). The blurred blob dims to
   .3 so it doesn't lift the photo. Contrast of every token on the panel is
   re-checked over the photo's LIGHTEST pixel behind text (the W17 commit
   message carries the numbers: worst 6.87:1 at 1280, 5.83:1 at 390). */
.pro-panel.has-ph .ph { position: absolute; border-radius: var(--r-lg); z-index: 0; }
.pro-panel.has-ph .ph img { filter: saturate(.4) brightness(.72) contrast(1.05); }
.pro-panel.has-ph .ph .grade { background: linear-gradient(180deg, var(--plum) 0%, var(--plum-card) 45%, var(--plum) 100%); opacity: .62; mix-blend-mode: multiply; }
.pro-panel.has-ph .ph::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(90deg, rgba(22,15,28,.92) 0%, rgba(22,15,28,.55) 45%, rgba(22,15,28,.25) 100%),
    linear-gradient(180deg, rgba(22,15,28,0) 0%, rgba(22,15,28,.2) 55%, var(--plum) 100%);
}
.pro-panel.has-ph::after { opacity: .3; }
/* phone: the text column spans the panel's full width and the rack's bright
   window sits under the head, so the wash deepens from the top (the kicker
   measured 4.69:1 over the photo's lightest pixel at 390 before this — AA,
   but a point under its 5.73:1 on plain plum). The photo shows through under
   the phones, where nothing is read. */
@media (max-width: 899px) {
  .pro-panel.has-ph .ph::after {
    background:
      linear-gradient(180deg, rgba(22,15,28,.78) 0%, rgba(22,15,28,.6) 30%, rgba(22,15,28,.2) 55%, var(--plum) 100%),
      linear-gradient(90deg, rgba(22,15,28,.6) 0%, rgba(22,15,28,.25) 100%);
  }
}

/* (G) the runner closes the page — W17b. Full-bleed under the close: the copy
   and the CTA sit on the pale dawn sky, the runner sits below-left of the note,
   and the dark road runs straight into the plum footer (the only place a dark
   photograph can land on this pale page without a contrast fight). The mask
   dissolves the photo's TOP into the wash so the section starts on bare wash.
   Never the hero: it is the last thing on the page, where the CTA repeats. */
.ph.fade-up { --pf: var(--ph-fade, 46%);
  -webkit-mask-image: linear-gradient(0deg, #000 0%, #000 var(--pf), rgba(0,0,0,.94) calc(var(--pf) + (100% - var(--pf))*.15), rgba(0,0,0,.78) calc(var(--pf) + (100% - var(--pf))*.3), rgba(0,0,0,.58) calc(var(--pf) + (100% - var(--pf))*.45), rgba(0,0,0,.35) calc(var(--pf) + (100% - var(--pf))*.6), rgba(0,0,0,.12) calc(var(--pf) + (100% - var(--pf))*.78), transparent 100%);
          mask-image: linear-gradient(0deg, #000 0%, #000 var(--pf), rgba(0,0,0,.94) calc(var(--pf) + (100% - var(--pf))*.15), rgba(0,0,0,.78) calc(var(--pf) + (100% - var(--pf))*.3), rgba(0,0,0,.58) calc(var(--pf) + (100% - var(--pf))*.45), rgba(0,0,0,.35) calc(var(--pf) + (100% - var(--pf))*.6), rgba(0,0,0,.12) calc(var(--pf) + (100% - var(--pf))*.78), transparent 100%);
}
.close.has-ph { position: relative; padding-top: clamp(80px, 12vw, 160px); padding-bottom: clamp(150px, 20vw, 260px); }
.close.has-ph > .wrap { position: relative; z-index: 1; }
.close.has-ph h2 { text-shadow: 0 1px 0 rgba(255,255,255,.55), 0 0 28px rgba(255,255,255,.6); }
/* phone: un-zoomed, the photograph anchored to the section's bottom 62% so
   the runner sits UNDER the copy, never behind it. */
@media (max-width: 899px) {
  .close.has-ph { padding-bottom: 380px; }
  .close.has-ph .ph { top: auto; bottom: 0; height: 62%; --ph-fade: 55%; }
  .close.has-ph .ph img { transform: none; object-position: 44% 100%; }
}
