/* ==========================================================================
   Heala /start — v7, native.
   ==========================================================================
   This is THE stylesheet now, not a skin: start.html was rebuilt against
   FUNNEL-CONTRACT.md, funnel.css is no longer loaded, and every rule here
   is written for the dark ground directly.

   ONE GROUND, ON PURPOSE. Light only — there is no dark variant and no
   toggle. A signup funnel is a committed environment, not a document
   that must survive both grounds, and carrying two palettes meant every
   surface had to be designed twice (the dark one always won, and light
   inherited its leftovers: a pastel CTA, ghost-faint ruler ticks).
   Deleting dark is what let light be tuned properly.

   The ground is plum-biased near-white, not neutral: the neutral leans
   toward the accent, so hairlines read as chosen rather than inherited.
   One deep-violet accent carries every action — solid, with white text,
   because a tinted gradient on white reads as a disabled button. One
   ember is reserved for the measurement cursor, the only heat in the
   flow, on its only instrument.

   funnel.js also INJECTS markup (ruler tracks + needle, rest-day tiles,
   day tabs, the program week, hook proof cards, recap chips, paywall
   stats). Those structures are styled here too — dropping one leaves a
   step you only meet at checkout unstyled.
   ========================================================================== */

/* ── Tokens ─────────────────────────────────────────────────────────── */
/* ── The display face ──────────────────────────────────────────────────────
   Nunito, variable 700–900, self-hosted because the site CSP is
   `font-src 'self'`. The SAME two files app-v2.css loads, so a visitor
   arriving from heala.fit already has them cached and the funnel's first
   headline paints without a swap.

   ⚠️ latin-ext IS NOT OPTIONAL. We ship en/tr/es and Turkish lives there:
   ğ Ğ ı İ ş Ş are all outside the latin block. */
@font-face {
  font-family: "Heala Display";
  src: url("assets/nunito-latin.woff2") format("woff2");
  font-weight: 700 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Heala Display";
  src: url("assets/nunito-latin-ext.woff2") format("woff2");
  font-weight: 700 900; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ══════════════════════════════════════════════════════════════════════
     THE SITE'S GROUND, NOT THE APP ONBOARDING'S.

     This block used to be monochrome, mirroring lib/onboarding-ui.ts: no hue
     anywhere, so the CTA and the selected answer were always the darkest
     things on screen. That reasoning is still right about HIERARCHY and it is
     kept below — but it was solving the wrong problem here. Someone lands on
     a violet, dark, rounded heala.fit, presses one button, and arrived at a
     near-white grotesk form that looked like a different company. The break
     cost more than the discipline bought.

     So: the site's palette, verbatim from app-v2.css, mapped onto the names
     the 2,000 lines below already use. Nothing downstream had to change.

     ⚠️ THE HIERARCHY RULE SURVIVES THE REPAINT. Violet is spent on STATE —
     the chosen answer, the live rail, the ring on a focused field — and the
     thing you press is --ink, which is near-black on paper and near-white on
     night. A screen where everything is violet has no way left to say
     "this one".
     ══════════════════════════════════════════════════════════════════════ */
  color-scheme: dark;

  --bg:    #17142B;
  --raised:#262146;
  --track: #100D20;
  --line:  rgba(178, 160, 240, .17);
  --line2: rgba(178, 160, 240, .30);
  --tx:    #EFEAFF;
  --dim:   rgba(226, 218, 252, .72);
  --faint: rgba(190, 178, 226, .58);

  /* State, not furniture. */
  --ac:    #B49CFF;
  --ac2:   #D3C4FF;
  --ac-soft: rgba(180, 156, 255, .14);
  --ac-line: rgba(180, 156, 255, .34);

  /* ⚠️ THE PRESSABLE IS --ink, AND IT INVERTS. A near-black pill on a dark
     page is a hole; on paper it is the strongest mark available. Both are
     "the darkest/lightest thing on screen", which is the property the old
     monochrome scheme was actually buying. */
  --ink:   #F3EFFF;
  --on-ink:#17142B;

  /* ⚠️ THE INK CHANNEL, SO A TINT CAN FLIP WITHOUT REWRITING ITS ALPHA.
     Eighty rules across this file paint surfaces with `rgba(10,10,11,X)` —
     ink at low alpha, which is a light grey on paper and, on night, is
     darkening something already dark: invisible. They now read the triplet
     from here and keep their own alpha.

     ⚠️ SHADOWS ARE DELIBERATELY NOT INCLUDED. A shadow that flips to light
     ink stops being a shadow and becomes a glow, so every box-shadow keeps
     its literal near-black. */
  --ink-rgb: 239, 234, 255;

  --ember: #B49CFF;
  --ok:    #4ADE80;
  --amber: #FBBF24;
  --red:   #FF6B5E;
  --on-ac: #100A1F;

  --r:     22px;
  --shadow-1: 0 2px 8px rgba(0, 0, 0, .28);
  --shadow-2: 0 18px 44px -20px rgba(0, 0, 0, .65);

  /* Macro hues are DATA, not decoration — protein/carb/fat have to stay
     told apart at a glance, so they are the one thing the repaint leaves
     alone. */
  --macro-p: #F4795B;
  --macro-c: #46B4D6;
  --macro-f: #F2B33D;
  --ring-from: #F4795B;
  --ring-to: #F2B33D;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --display: "Heala Display", ui-rounded, "SF Pro Rounded", system-ui,
             -apple-system, "Segoe UI", Roboto, sans-serif;
  --body: -apple-system, "SF Pro Text", system-ui, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
}

/* Light is the second theme, and the switch on heala.fit is what picks it —
   start.html reads the same localStorage key before first paint. */
[data-theme="light"] {
  color-scheme: light;

  --bg:    #FFFFFF;
  --raised:#FFFFFF;
  --track: #F1EFF6;
  --line:  rgba(38, 20, 80, .10);
  --line2: rgba(38, 20, 80, .18);
  --tx:    #141021;
  --dim:   rgba(20, 16, 33, .68);
  --faint: rgba(20, 16, 33, .46);

  --ac:    #6D28D9;
  --ac2:   #8B5CF6;
  --ac-soft: rgba(109, 40, 217, .08);
  --ac-line: rgba(109, 40, 217, .26);

  --ink:   #17141F;
  --on-ink:#FFFFFF;
  --ink-rgb: 10, 10, 11;

  --ember: #6D28D9;
  --ok:    #16A34A;
  --amber: #D97706;
  --red:   #D92D20;
  --on-ac: #FFFFFF;

  --shadow-1: 0 2px 10px rgba(38, 20, 80, .06);
  --shadow-2: 0 20px 46px -22px rgba(38, 20, 80, .20);
}


/* ── Reset ──────────────────────────────────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; color-scheme: light; }
html, body { overflow-x: clip; }
body {
  background: var(--bg);
  color: var(--tx);
  font-family: var(--display);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
input, textarea, output { font: inherit; color: inherit; }
input, textarea, select { touch-action: manipulation; }
a { color: inherit; touch-action: manipulation; }
img { display: block; max-width: 100%; }
/* funnel.js hides things by toggling the hidden ATTRIBUTE; any class that
   sets `display` would silently beat the UA's [hidden] rule (the retry
   button under the compute spinner was the visible casualty). */
[hidden] { display: none !important; }

/* ── Ambient room: bloom + grain ────────────────────────────────────────
   The bloom brightens as the visitor commits — funnel.js sets
   --v7-progress on every step change; the fallback keeps it lit before
   the first show(). Purely decorative, fixed, never intercepts input. */
body.onboarding::before {
  content: ""; position: fixed; left: 50%; top: 0; z-index: 0;
  width: 720px; height: 720px; transform: translate(-50%, -56%);
  background: radial-gradient(circle, rgba(var(--ink-rgb), .26), transparent 62%);
  opacity: calc(.45 + var(--v7-progress, .2) * .55);
  pointer-events: none;
  transition: opacity .9s ease;
}
body.onboarding::after {
  content: ""; position: fixed; inset: 0; z-index: 0;
  pointer-events: none; opacity: .035; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence baseFrequency='.85' numOctaves='3'/></filter><rect width='120' height='120' filter='url(%23n)'/></svg>");
}
.fun, .fun-top { position: relative; z-index: 1; }

/* ── Header: chapter rail + controls ────────────────────────────────── */
.fun-top {
  position: sticky; top: 0; z-index: 40;
  /* ⚠️ WAS rgba(247,247,248,.88) — the old paper ground, hardcoded. On the
     night theme that painted a light grey slab across the top with violet
     text on it. color-mix keeps the frosted effect and lets the ground
     follow the theme. */
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.top-inner { max-width: 480px; margin: 0 auto; padding: 14px 20px 10px; }
/* One continuous progress track wearing four chapter segments: funnel.js
   only ever writes #prog's width and aria-valuenow, so the chapter gaps
   are painted OVER the fill at the step boundaries (7.5/25, 17.5/25,
   21.5/25 of the 26-step order) rather than being real elements. */
.fun-progress {
  position: relative; height: 3px; border-radius: 2px;
  /* ⚠️ NOT --track. That token is a SURFACE — a well, sunk below the page —
     and on the night theme it is darker than the ground, so the unfilled part
     of the rail and the gaps between its four chapters read as black slots
     cut out of the header. A progress track has to be LIGHTER than what it
     sits on, whichever theme that is, which is what the ink triplet gives. */
  background: rgba(var(--ink-rgb), .16); overflow: hidden;
}
.fun-progress span#prog, .fun-progress > span {
  display: block; height: 100%; width: 0; border-radius: 2px;
  background: linear-gradient(90deg, var(--ac2), var(--ac));
  transition: width .5s cubic-bezier(.2, .8, .2, 1);
}
.fun-progress::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(90deg,
    transparent 0 calc(30% - 2px), var(--bg) calc(30% - 2px) calc(30% + 2px),
    transparent calc(30% + 2px) calc(70% - 2px), var(--bg) calc(70% - 2px) calc(70% + 2px),
    transparent calc(70% + 2px) calc(86% - 2px), var(--bg) calc(86% - 2px) calc(86% + 2px),
    transparent calc(86% + 2px));
}
.top-row { display: flex; align-items: center; gap: 10px; margin-top: 9px; min-height: 34px; }
.fun-back {
  flex: none; width: 34px; height: 34px; border-radius: 12px;
  display: grid; place-items: center;
  border: 1px solid var(--line); background: var(--raised); color: var(--dim);
  transition: opacity .2s, transform .15s;
}
.fun-back svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.fun-back:disabled { opacity: 0; pointer-events: none; }
.fun-back:active { transform: scale(.94); }
/* The flow states its own length: chapter name left, position right.
   Both are painted by the inline observer in start.html; funnel.js is
   not involved. */
.railtx {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 10px;
  font-family: var(--mono); font-size: 9px; letter-spacing: .8px; color: var(--faint);
}
.rail-ch span { display: none; color: var(--ac); font-weight: 600; text-transform: uppercase; }
.rail-ch span[data-on] { display: inline; }
.fun-restart {
  flex: none; padding: 8px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--raised);
  color: var(--dim); font-size: 11px; font-weight: 700;
  transition: color .2s;
}
.fun-restart:hover { color: var(--tx); }
.fun-restart[data-armed] { color: var(--red); border-color: rgba(217, 45, 32, .4); }
.fun-restart[hidden] { display: none; }

/* ── Layout + step machine ──────────────────────────────────────────── */
.fun { max-width: 480px; margin: 0 auto; padding: 18px 20px 150px; }
/* Per-step scroll budgets carried over from the old system — the account
   step is contracted to one viewport, checkout's stacked CTA is taller
   than the standard reserve and must not cover the renewal disclosure. */
.fun:has(> .step[data-step="account"].on) { padding-bottom: 24px; }
.fun:has(> .step[data-step="checkout"].on) { padding-bottom: 184px; }
.fun:has(> .step[data-step="ready"].on) { padding-bottom: 132px; }
.fun:has(> .step[data-step="program_preview"].on) { padding-bottom: 112px; padding-top: 10px; }
.step { display: none; }
.step.on { display: block; }
/* Animate children, never the step itself — a transform on the step would
   become the containing block for its fixed .cta-row. */
.step.on > :not(.cta-row):not(.free-confirm) { animation: stepIn .32s cubic-bezier(.2, .8, .2, 1) both; }
.step.on > .cta-row { animation: fadeIn .3s ease both; }
@keyframes stepIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
html.no-js .step { display: block; margin-bottom: 60px; }

/* ── Type ───────────────────────────────────────────────────────────── */
.q-head { padding: 16px 0 22px; }
.q-head h1, .hero h1, .compute h1, .dl-box h1 {
  font-size: clamp(27px, 7.4vw, 34px);
  line-height: 1.04; letter-spacing: -.05em; font-weight: 800;
  text-wrap: balance;
}
h1 em { font-style: normal; color: var(--ac); }
.sub { margin-top: 10px; color: var(--dim); font-size: 13.5px; line-height: 1.45; max-width: 34ch; }
.eyebrow {
  margin-bottom: 11px; color: var(--ac);
  font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: 1.6px; text-transform: uppercase;
}
.hint { color: var(--faint); font-size: 13px; line-height: 1.5; margin-top: 14px; }
.hint.center { text-align: center; }
.hint b { color: var(--dim); }
.hint.is-warn { color: var(--amber); font-weight: 600; }
.hint.is-danger { color: var(--red); font-weight: 600; }
.warn-flash { color: var(--amber); font-weight: 600; }

/* ── Primary action ─────────────────────────────────────────────────── */
.btn-main {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; min-height: 54px; padding: 0 24px;
  /* The site's pill, not a 17px rounded rectangle. */
  border-radius: 999px;
  /* ⚠️ --ink, NOT --ac. The accent is spent on STATE — the chosen answer, the
     live rail — and if the button wore it too there would be nothing left to
     distinguish "selected" from "press this". --ink is near-black on paper
     and near-white on night, which is exactly what heala.fit's own CTA does
     and is the property the old all-black scheme was really buying: the
     button is the highest-contrast thing on the screen either way. */
  background: var(--ink);
  color: var(--on-ink);
  font-family: var(--display);
  font-size: 16.5px; font-weight: 900; letter-spacing: -.01em;
  text-decoration: none;
  box-shadow: var(--shadow-2);
  transition: transform .16s cubic-bezier(.3, 1.4, .5, 1), opacity .2s;
}
.btn-main:active { transform: scale(.975); }
.btn-main:disabled { opacity: .32; box-shadow: none; pointer-events: none; }
.btn-main svg { width: 17px; height: 17px; flex: none; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.btn-quiet {
  display: block; width: 100%; padding: 14px;
  color: var(--ac); font-size: 14px; font-weight: 600; text-align: center;
  transition: color .2s;
}
.btn-quiet:hover { color: var(--tx); }
.cta-row {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  max-width: 480px; margin: 0 auto;
  padding: 28px 20px calc(16px + env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--bg) 62%, rgba(248, 246, 253, 0));
  pointer-events: none;
}
.cta-row > * { pointer-events: auto; }
.cta-note {
  margin-top: 10px; text-align: center; color: var(--faint);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .4px;
}
.cta-row.stacked .btn-quiet { margin-top: 4px; }
/* A choice step's Continue only becomes real once something is chosen. It is
   present from the first paint so the page never reflows a button in, and so
   walking BACK into an answered step always has a way forward. */
.step:not(:has([data-answer] [data-value].sel)) .choice-cta .btn-main {
  opacity: .32; box-shadow: none; pointer-events: none;
}
html.no-js .cta-row { position: static; padding: 20px 0; }

/* "Already have an account? Sign in" — quiet but findable. */
.acct-alt {
  display: block; width: 100%; margin: 12px 0 0; padding: 12px 8px;
  color: var(--faint); font-size: 13px; font-weight: 650; text-align: center;
  text-decoration: underline; text-underline-offset: 3px;
  transition: color .2s;
}
.acct-alt:hover { color: var(--ac); }
.acct-alt:disabled { opacity: .55; cursor: default; text-decoration: none; }

/* ── Landing ────────────────────────────────────────────────────────── */
.hero { padding: 5vh 0 0; text-align: left; }
.hero-mark {
  width: 54px; height: 54px; border-radius: 18px; margin-bottom: 20px;
  box-shadow: 0 14px 34px -10px rgba(10, 10, 11, .8);
}
.hero h1 { font-size: clamp(34px, 9.4vw, 44px); }
.hero .sub { max-width: 36ch; font-size: 14px; }
/* Default (no hook) proof block: funnel.js fills #hook-visual with three
   .hero-points spans — restyled from a dot-row into the check list the
   flow uses everywhere else, so the promise reads like the receipts. */
.hero-points { display: flex; flex-direction: column; gap: 9px; margin-top: 26px; }
.hero-points span {
  display: flex; align-items: center; gap: 9px;
  color: var(--dim); font-size: 13px; font-weight: 600;
}
.hero-points span::before {
  content: ""; flex: none; width: 16px; height: 16px; border-radius: 50%;
  background: rgba(var(--ink-rgb), .16) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 7 9 18l-5-5' fill='none' stroke='%230A0A0B' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / 9px no-repeat;
}
.hero-points i { display: none; }
/* Momentum eyebrow + trust bar — hook landings only. */
.hero-eyebrow, .hero-trust { display: none; }
.hook-on .hero-eyebrow { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; }
.hero-eyebrow .he-rail { display: inline-flex; gap: 5px; }
.hero-eyebrow .he-rail i { width: 16px; height: 4px; border-radius: 2px; background: rgba(var(--ink-rgb), .18); }
.hero-eyebrow .he-rail i.on { background: var(--ac); }
.hero-eyebrow .he-label {
  font-family: var(--mono); font-size: 9.5px; font-weight: 500;
  letter-spacing: 1px; color: var(--faint); text-transform: uppercase;
}
.hero-eyebrow .he-label b { color: var(--ac); font-weight: 600; }
.hook-on .hero-trust { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-top: 10px; }
.hero-trust span { display: inline-flex; align-items: center; gap: 5px; color: var(--dim); font-size: 11px; font-weight: 700; white-space: nowrap; }
.hero-trust em { font-style: normal; }
.hero-trust span svg { width: 12px; height: 12px; fill: none; stroke: var(--ac); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.hero-trust > i { width: 3px; height: 3px; border-radius: 50%; background: var(--line2); }
/* Hook landings must fit ONE phone screen: compact the hero chrome. */
.hook-on .hero { padding-top: 2vh; }
.hook-on .hero-mark { width: 38px; height: 38px; border-radius: 12px; margin-bottom: 14px; }
.hook-on .hero h1 { font-size: clamp(28px, 7.6vw, 38px); }
.hook-on .hero .sub { margin-top: 8px; font-size: 13.5px; line-height: 1.45; }
@media (max-height: 780px) { .hook-on .hero-trust { margin-top: 8px; } .hook-on .hero-eyebrow { margin-bottom: 9px; } }
@media (max-height: 700px) { .hero-eyebrow .he-label { display: none; } }
@media (max-height: 660px) { .hook-on .hero-trust { display: none; } }

/* ── Heala Proof Card — one system, four hook demos ───────────────────
   funnel.js injects these into #hook-visual. Status strip (violet live →
   green done), a lit dark stage where the product works, a structured
   readout. All motion is transform/opacity/count → zero layout shift. */
.hook-card {
  margin-top: 14px; padding: 12px; border-radius: 18px;
  border: 1px solid var(--line); background: var(--raised);
  max-width: 420px;
}
.hk-strip { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.hk-live { display: inline-flex; align-items: center; gap: 6px; color: var(--ac); font-family: var(--mono); font-size: 9px; font-weight: 600; letter-spacing: 1px; }
.hk-live i { width: 7px; height: 7px; border-radius: 50%; background: var(--ac); animation: pulse 1.6s ease-in-out infinite; }
.hk-done { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; color: var(--ok); font-size: 10px; font-weight: 800; letter-spacing: .02em; white-space: nowrap; opacity: 0; transform: translateX(4px); animation: hkDone .5s ease 2.05s forwards; }
.hk-done svg { width: 12px; height: 12px; fill: none; stroke: var(--ok); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.hk-stage { position: relative; border-radius: 14px; overflow: hidden; background: linear-gradient(180deg, #0A0A0B, #141414); border: 1px solid var(--line); }
.hk-readout { margin-top: 10px; }
.hk-pill { font-size: 11px; font-weight: 800; color: var(--ac); padding: 2px 8px; border-radius: 999px; background: var(--ac-soft); }
@keyframes hkRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes hkPop { from { opacity: 0; transform: translateY(6px) scale(.92); } to { opacity: 1; transform: none; } }
@keyframes hkDone { to { opacity: 1; transform: none; } }
@keyframes hkBarY { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes hkBarX { to { transform: scaleX(1); } }
@keyframes hkStrike { to { transform: scaleX(1); } }
@keyframes pulse { 50% { opacity: .35; } }

/* SCAN — the lit dark studio */
.hook-scan .scan-stage { height: min(23vh, 184px); background: radial-gradient(120% 90% at 50% -10%, #252525 0%, #161616 42%, #120E1A 100%); }
.hook-scan .scan-stage::before { content: ""; position: absolute; inset: 0; background-image: linear-gradient(rgba(var(--ink-rgb), .06) 1px, transparent 1px), linear-gradient(90deg, rgba(var(--ink-rgb), .06) 1px, transparent 1px); background-size: 26px 26px; -webkit-mask-image: linear-gradient(180deg, transparent 40%, #000 100%); mask-image: linear-gradient(180deg, transparent 40%, #000 100%); }
.hook-scan .twin-wrap { position: absolute; inset: 0; display: grid; place-items: center; }
.hook-scan .twin { position: absolute; height: 92%; top: 6%; left: 50%; transform: translateX(-50%); }
.hook-scan .twin path { stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.hook-scan .twin.before path { fill: none; stroke: rgba(var(--ink-rgb), .30); stroke-width: 2; stroke-dasharray: 4 4; }
.hook-scan .twin.after path { fill: rgba(var(--ink-rgb), .10); stroke: var(--ac); stroke-width: 2.4; }
.hook-scan .twin.after { clip-path: inset(0 0 100% 0); animation: twinReveal 1.5s cubic-bezier(.5, 0, .2, 1) .7s forwards; }
@keyframes twinReveal { to { clip-path: inset(0 0 0 0); } }
.hook-scan .scan-line { position: absolute; left: 16%; right: 16%; height: 2px; border-radius: 2px; opacity: 0; background: linear-gradient(90deg, transparent, var(--ac), transparent); box-shadow: 0 0 12px 2px rgba(10, 10, 11, .45); animation: scanIdle 5.4s ease-in-out .3s infinite; }
@keyframes scanIdle { 0% { top: 10%; opacity: 0; } 4% { opacity: 1; } 22% { top: 86%; opacity: 1; } 30% { top: 86%; opacity: 0; } 100% { top: 10%; opacity: 0; } }
.hook-scan .scan-cap { position: absolute; top: 10px; left: 10px; display: flex; align-items: center; gap: 5px; padding: 4px 9px 4px 6px; border-radius: 999px; border: 1px solid var(--line); background: rgba(255, 255, 255, .86); backdrop-filter: blur(6px); font-size: 9px; font-weight: 800; letter-spacing: .04em; color: var(--dim); }
.hook-scan .sc-shot { width: 12px; height: 14px; border-radius: 2px; border: 1.5px solid var(--ac); position: relative; background: var(--track); }
.hook-scan .scan-cap .sc-shot + .sc-shot { margin-left: -7px; box-shadow: -3px 0 0 -1px var(--raised); }
.hook-scan .sc-shot::before { content: ""; position: absolute; left: 50%; top: 2px; width: 3px; height: 3px; border-radius: 50%; background: var(--ac); transform: translateX(-50%); }
.hook-scan .caliper { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; gap: 3px; opacity: 0; animation: calIn .5s ease 1.7s forwards; }
@keyframes calIn { to { opacity: 1; } }
.hook-scan .cal-bar { position: relative; height: 2px; width: 64px; background: var(--tx); border-radius: 2px; animation: calClose 1s cubic-bezier(.5, 0, .2, 1) 1.9s forwards; }
@keyframes calClose { to { width: 40px; } }
.hook-scan .cal-bar::before, .hook-scan .cal-bar::after { content: ""; position: absolute; top: -4px; width: 2px; height: 10px; background: var(--tx); border-radius: 2px; }
.hook-scan .cal-bar::before { left: 0; } .hook-scan .cal-bar::after { right: 0; }
.hook-scan .cal-val { padding: 1px 6px; border-radius: 6px; background: rgba(var(--ink-rgb), .10); font-size: 10px; font-weight: 900; color: var(--ac); }
.hook-scan .scan-scale { position: absolute; left: 10px; bottom: 10px; display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 12px; border: 1px solid var(--line); background: rgba(255, 255, 255, .90); backdrop-filter: blur(6px); }
.hook-scan .ss-spark { width: 34px; height: 14px; } .hook-scan .ss-spark path { fill: none; stroke: var(--dim); stroke-width: 2; stroke-linecap: round; }
.hook-scan .ss-txt { display: flex; flex-direction: column; line-height: 1.1; }
.hook-scan .ss-txt b { color: var(--tx); font-size: 12px; font-weight: 900; font-variant-numeric: tabular-nums; }
.hook-scan .ss-txt span { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; color: var(--dim); text-transform: uppercase; }
.hook-scan .scan-deltas { display: flex; gap: 6px; }
.hook-scan .sd { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 4px; border-radius: 12px; border: 1px solid var(--line); background: var(--track); opacity: 0; transform: translateY(6px); animation: hkRise .5s ease forwards; }
.hook-scan .sd:nth-child(1) { animation-delay: 1.9s; } .hook-scan .sd:nth-child(2) { animation-delay: 2.05s; } .hook-scan .sd:nth-child(3) { animation-delay: 2.2s; }
.hook-scan .sd em { min-height: 24px; display: flex; align-items: center; text-align: center; font-style: normal; font-size: 10px; font-weight: 700; color: var(--dim); }
.hook-scan .sd b { font-size: 15px; font-weight: 900; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.hook-scan .sd b u { text-decoration: none; font-size: 9px; font-weight: 800; margin-left: 1px; }
.hook-scan .sd b.up { color: var(--ok); } .hook-scan .sd b.down { color: var(--ac); }
@media (max-height: 700px) { .hook-scan .scan-stage { height: min(24vh, 196px); } }

/* MEAL — camera already dark; the flash flips to violet */
.hook-meal .meal-cam { height: min(15vh, 118px); background: radial-gradient(90% 120% at 50% 0%, #212121, #17131F); display: grid; place-items: center; margin-bottom: 10px; border: 0; }
.hook-meal .mc-corner { position: absolute; width: 18px; height: 18px; border: 2.5px solid rgba(247, 247, 248, .85); opacity: 0; animation: mealCorner .45s ease .15s forwards; }
.hook-meal .mc-corner.tl { top: 10px; left: 10px; border-right: 0; border-bottom: 0; border-top-left-radius: 6px; }
.hook-meal .mc-corner.tr { top: 10px; right: 10px; border-left: 0; border-bottom: 0; border-top-right-radius: 6px; }
.hook-meal .mc-corner.bl { bottom: 10px; left: 10px; border-right: 0; border-top: 0; border-bottom-left-radius: 6px; }
.hook-meal .mc-corner.br { bottom: 10px; right: 10px; border-left: 0; border-top: 0; border-bottom-right-radius: 6px; }
@keyframes mealCorner { to { opacity: .9; } }
.hook-meal .mc-plate { position: relative; width: 76px; height: 76px; border-radius: 50%; background: #F5F2EC; box-shadow: inset 0 0 0 8px #FFFFFF, 0 10px 24px rgba(0, 0, 0, .35); animation: mealPlate 2.6s ease both; }
@keyframes mealPlate { 0% { transform: scale(.94); opacity: .7; } 20% { transform: scale(1); opacity: 1; } 100% { transform: none; opacity: 1; } }
/* The plated dish. Fills carry the food, strokes carry the detail that makes
   76px read as a meal rather than three coloured smudges. */
.hook-meal .mc-dish { position: absolute; inset: 6px; width: calc(100% - 12px); height: calc(100% - 12px); }
.hook-meal .mc-salmon path:first-child { fill: #979797; }
.hook-meal .mc-flake { fill: none; stroke: #C9C9C9; stroke-width: 1.6; stroke-linecap: round; opacity: .9; }
.hook-meal .mc-greens circle { fill: rgba(10,10,11,.52); }
.hook-meal .mc-greens circle:nth-child(2) { fill: rgba(10,10,11,.30); }
.hook-meal .mc-stalk { fill: none; stroke: #BABABA; stroke-width: 2.4; stroke-linecap: round; }
.hook-meal .mc-grain ellipse { fill: #ECECEC; }
.hook-meal .mc-kernel { fill: none; stroke: #CFCFCF; stroke-width: 1.8; stroke-linecap: round; }
.hook-meal .mc-lemon circle { fill: #C7C7C7; }
.hook-meal .mc-seg { fill: none; stroke: #E8E8E8; stroke-width: 1.3; }
.hook-meal .mc-scan { position: absolute; left: 6%; right: 6%; height: 2px; border-radius: 2px; background: linear-gradient(90deg, transparent, #999999, transparent); animation: mealSweep 1s cubic-bezier(.4, 0, .2, 1) .55s both; }
@keyframes mealSweep { 0% { top: 10%; opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { top: 86%; opacity: 0; } }
.hook-meal .mc-flash { position: absolute; inset: 0; background: var(--ac); opacity: 0; pointer-events: none; animation: mealFlash 2.6s ease both; }
@keyframes mealFlash { 0%, 16% { opacity: 0; } 20% { opacity: .9; } 30% { opacity: 0; } 100% { opacity: 0; } }
.hook-meal .meal-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; font-size: 12.5px; }
.hook-meal .meal-row.head { justify-content: space-between; padding-bottom: 8px; border-bottom: 1px solid var(--line); margin-bottom: 2px; }
.hook-meal .meal-row.head b { font-size: 14.5px; font-weight: 800; }
.hook-meal .meal-row.head span { color: var(--dim); font-weight: 700; }
.hook-meal .mc-kcal { color: var(--tx); font-weight: 800; font-variant-numeric: tabular-nums; text-decoration: none; }
.hook-meal .meal-row:not(.head) > span { display: flex; align-items: center; gap: 7px; width: 84px; color: var(--dim); font-weight: 600; }
.hook-meal .meal-row i { flex: 1; height: 6px; border-radius: 3px; background: var(--track); overflow: hidden; }
/* ⚠️ THE BARS WERE ALL ACCENT WHILE THEIR DOTS WERE MACRO-COLOURED — the one
   place on the page where hue is DATA, thrown away on the widest element in
   the row. Protein, carbs and fat carry their own colour here exactly as they
   do on the handover screen and in the app. */
.hook-meal .meal-row i u { display: block; height: 100%; border-radius: 3px; background: var(--ac); transform-origin: left; transform: scaleX(0); animation: hkBarX .8s cubic-bezier(.3, .8, .3, 1) both; }
.hook-meal .meal-row:has(.dot.p) i u { background: var(--macro-p); }
.hook-meal .meal-row:has(.dot.c) i u { background: var(--macro-c); }
.hook-meal .meal-row:has(.dot.f) i u { background: var(--macro-f); }
.hook-meal .meal-row:not(.head) b { width: 44px; text-align: right; font-weight: 800; }
.hook-meal .meal-readout .meal-row { opacity: 0; animation: hkRise .5s ease both; }
.hook-meal .meal-readout .meal-row:nth-child(1) { animation-delay: 1.5s; }
.hook-meal .meal-readout .meal-row:nth-child(2) { animation-delay: 1.62s; }
.hook-meal .meal-readout .meal-row:nth-child(3) { animation-delay: 1.74s; }
.hook-meal .meal-readout .meal-row:nth-child(4) { animation-delay: 1.86s; }
.hook-meal .meal-readout .meal-row:nth-child(2) u { animation-delay: 1.70s; }
.hook-meal .meal-readout .meal-row:nth-child(3) u { animation-delay: 1.82s; }
.hook-meal .meal-readout .meal-row:nth-child(4) u { animation-delay: 1.94s; }

/* PROGRAM — the week assembles, then a real day writes in */
.hook-program .hp-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; padding: 9px; }
.hook-program .hp-day { display: grid; gap: 4px; justify-items: center; align-content: center; min-height: 44px; padding: 6px 2px; border-radius: 9px; text-align: center; }
.hook-program .hp-day span { color: var(--faint); font-size: 8.5px; font-weight: 800; letter-spacing: .03em; }
.hook-program .hp-day.rest { opacity: .55; } .hook-program .hp-day.rest::after { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--line2); }
.hook-program .hp-day.fill { background: linear-gradient(180deg, rgba(var(--ink-rgb), .12), rgba(var(--ink-rgb), .05)); box-shadow: 0 3px 12px rgba(10, 10, 11, .28); animation: hkPop .42s cubic-bezier(.2, 1.1, .3, 1) both; }
.hook-program .hp-day.fill span { color: var(--ac); }
.hook-program .hp-day.fill em { font-style: normal; font-size: 9px; font-weight: 800; color: var(--ac); line-height: 1.2; padding: 2px 6px; border-radius: 999px; background: var(--ac-soft); white-space: nowrap; }
.hook-program .hp-day.d1 { animation-delay: .25s; } .hook-program .hp-day.d2 { animation-delay: .55s; } .hook-program .hp-day.d3 { animation-delay: .85s; }
.hook-program .hp-card { margin-top: 11px; }
.hook-program .hp-head { display: flex; align-items: baseline; gap: 9px; padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.hook-program .hp-head span { color: var(--ac); font-size: 10px; font-weight: 800; letter-spacing: .08em; }
.hook-program .hp-head b { font-size: 15px; font-weight: 800; }
.hook-program .hp-head i { margin-left: auto; font-style: normal; color: var(--dim); font-size: 11px; font-weight: 700; }
.hook-program .hp-ex { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--line); opacity: 0; transform: translateY(8px); animation: hkRise .4s ease both; }
.hook-program .hp-ex:last-child { border-bottom: 0; padding-bottom: 0; }
.hook-program .hp-ex b { font-size: 13.5px; font-weight: 700; }
.hook-program .hp-ex .hk-pill { font-size: 11.5px; }
.hook-program .hp-ex.r1 { animation-delay: 1.05s; } .hook-program .hp-ex.r2 { animation-delay: 1.25s; } .hook-program .hp-ex.r3 { animation-delay: 1.45s; }
.hook-program .hp-prog { display: flex; align-items: center; gap: 9px; margin-top: 11px; padding: 8px 11px; border-radius: 11px; background: var(--track); }
.hook-program .hp-prog u { flex: none; display: flex; align-items: flex-end; gap: 3px; height: 18px; }
.hook-program .hp-prog u b { width: 5px; border-radius: 2px 2px 0 0; background: var(--ac); transform-origin: bottom; animation: hkBarY .5s cubic-bezier(.2, .9, .3, 1) both; }
.hook-program .hp-prog u b:nth-child(1) { height: 40%; animation-delay: 1.55s; }
.hook-program .hp-prog u b:nth-child(2) { height: 60%; animation-delay: 1.68s; }
.hook-program .hp-prog u b:nth-child(3) { height: 80%; animation-delay: 1.81s; }
.hook-program .hp-prog u b:nth-child(4) { height: 100%; animation-delay: 1.94s; }
.hook-program .hp-prog span { font-size: 11.5px; font-weight: 600; color: var(--dim); line-height: 1.35; }
.hook-program .hp-prog span em { font-style: normal; color: var(--tx); font-weight: 800; }
@media (max-height: 700px) { .hook-program .hp-day em { display: none; } .hook-program .hp-prog u { display: none; } }

/* PRICING — four apps stack up, then collapse to one Heala price */
.hook-price .hp-stack { padding: 2px 0; }
.hook-price .hp-row { display: flex; align-items: center; justify-content: space-between; padding: 6px 0; font-size: 13px; color: var(--dim); opacity: 0; transform: translateY(6px); animation: hkRise .4s ease both; }
.hook-price .hp-row:nth-child(1) { animation-delay: .10s; } .hook-price .hp-row:nth-child(2) { animation-delay: .20s; } .hook-price .hp-row:nth-child(3) { animation-delay: .30s; } .hook-price .hp-row:nth-child(4) { animation-delay: .40s; }
.hook-price .hp-row b { font-weight: 700; color: var(--dim); position: relative; font-variant-numeric: tabular-nums; }
.hook-price .hp-row b::after, .hook-price .hp-sum b::after { content: ''; position: absolute; left: -2px; right: -2px; top: 50%; height: 1.5px; background: rgba(217, 45, 32, .6); transform: scaleX(0); transform-origin: left; }
.hook-price.hp-go .hp-row b, .hook-price.hp-go .hp-sum b { color: var(--faint); }
.hook-price.hp-go .hp-row b::after, .hook-price.hp-go .hp-sum b::after { animation: hkStrike .4s ease forwards; }
.hook-price .hp-sum { display: flex; align-items: center; justify-content: space-between; padding: 8px 0 10px; margin-top: 2px; border-top: 1px solid var(--line); font-size: 12.5px; color: var(--dim); font-weight: 700; }
.hook-price .hp-sum b { position: relative; color: var(--tx); font-weight: 800; font-variant-numeric: tabular-nums; }
.hook-price .hp-total { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; padding: 12px 14px; border-radius: 12px; background: var(--ac-soft); opacity: 0; transform: translateY(10px); }
.hook-price.hp-go .hp-total { animation: hkRise .5s ease forwards; }
.hook-price .hp-total .hp-tlabel { font-weight: 800; color: var(--tx); font-size: 14px; }
.hook-price .hp-total b { font-weight: 900; color: var(--ac); font-size: 19px; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.hook-price .hp-note { margin-top: 8px; color: var(--faint); font-size: 11.5px; text-align: center; }

/* ── Choice lists ───────────────────────────────────────────────────── */
.choices { display: grid; gap: 8px; }
.choice {
  position: relative;
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: 60px; padding: 13px 46px 13px 15px;
  background: var(--raised); border: 1px solid var(--line); border-radius: 18px;
  text-align: left;
  transition: transform .16s cubic-bezier(.3, 1.4, .5, 1), border-color .2s, background .2s, box-shadow .2s;
}
.choice:active { transform: scale(.975); }
/* ⚠️ A TINT AND A RING, NOT A DARKER BOX. The old selected state was a black
   wash at 8% — on the night ground that is invisible, because darkening
   something already dark says nothing. Violet at low alpha reads on both
   themes, and the ring is what actually carries "this one". */
.choice.sel {
  border-color: var(--ac);
  background: var(--ac-soft);
  box-shadow: inset 0 0 0 1px var(--ac-line);
}
.choice[hidden] { display: none; }
/* The preview's tick — drawn, not marked up, so funnel.js's structure
   stays untouched. */
.choice::after {
  content: ""; position: absolute; right: 14px; top: 50%;
  width: 19px; height: 19px; margin-top: -10px; border-radius: 50%;
  border: 1.5px solid var(--line2);
  transition: background .2s, border-color .2s;
}
.choice.sel::after {
  border-color: var(--ac);
  background: var(--ac) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 7 9 18l-5-5' fill='none' stroke='%23121212' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / 10px no-repeat;
}
.ic {
  flex: none; width: 38px; height: 38px; border-radius: 12px;
  display: grid; place-items: center; background: var(--track); color: var(--dim);
  transition: background .2s, color .2s;
}
.ic svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.ic.txt { font-size: 11px; font-weight: 800; letter-spacing: -.02em; font-family: var(--mono); }
.ic.txt.rng { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; }
.ic.txt.rng b { font-size: 11.5px; font-weight: 800; letter-spacing: -.03em; line-height: 1; }
.ic.txt.rng i { font-style: normal; font-size: 7px; font-weight: 800; letter-spacing: .06em; line-height: 1; text-transform: uppercase; opacity: .6; }
.choice.sel .ic { background: rgba(var(--ink-rgb), .12); color: var(--ac); }
.cc { display: grid; gap: 2px; min-width: 0; }
.cc b { font-size: 14.5px; font-weight: 700; letter-spacing: -.02em; }
.cc small { color: var(--faint); font-size: 11px; line-height: 1.35; }
.choice.pill { min-height: 50px; }
.choice.pill .cc b { font-size: 14px; }

/* ── Number screens (age / height / weight / target / pace) ─────────── */
.num-card { padding: 6px 0 0; }
.num-read { display: flex; align-items: baseline; justify-content: flex-start; gap: 9px; padding: 14px 0 8px; }
.num-read output {
  font-size: 62px; font-weight: 800; letter-spacing: -.058em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.num-read span { color: var(--dim); font-family: var(--mono); font-size: 13px; font-weight: 500; letter-spacing: 1px; text-transform: uppercase; }
.num-ctrl { display: grid; grid-template-columns: 44px 1fr 44px; align-items: center; gap: 14px; }
.nudge {
  width: 44px; height: 44px; border-radius: 14px;
  border: 1px solid var(--line); background: var(--raised);
  font-size: 22px; font-weight: 500; color: var(--dim); line-height: 1;
  display: grid; place-items: center;
  transition: transform .12s, background .15s;
}
.nudge:active { transform: scale(.92); background: var(--track); }
input.range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 44px; background: transparent; margin: 0;
  --fill: 50%;
}
input.range:focus { outline: none; }
input.range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px;
  background: linear-gradient(90deg, var(--ac2), var(--ac) var(--fill), var(--track) var(--fill));
}
input.range::-moz-range-track { height: 6px; border-radius: 999px; background: var(--track); }
input.range::-moz-range-progress { height: 6px; border-radius: 999px; background: linear-gradient(90deg, var(--ac2), var(--ac)); }
input.range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 28px; height: 28px; margin-top: -11px; border-radius: 50%;
  background: var(--ac); border: 3px solid var(--raised);
  box-shadow: 0 2px 8px rgba(10, 10, 11, .22), 0 0 0 3px rgba(10, 10, 11, .16);
}
input.range::-moz-range-thumb {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--ac); border: 3px solid var(--raised);
  box-shadow: 0 2px 8px rgba(10, 10, 11, .22), 0 0 0 3px rgba(10, 10, 11, .16);
}
input.range:active::-webkit-slider-thumb { box-shadow: 0 2px 10px rgba(10, 10, 11, .26), 0 0 0 7px rgba(10, 10, 11, .18); }
.range-ends { display: flex; justify-content: space-between; margin: 8px 58px 0; color: var(--faint); font-family: var(--mono); font-size: 9.5px; letter-spacing: .5px; }

/* ── Unit toggle ────────────────────────────────────────────────────── */
.unit-toggle {
  display: flex; gap: 2px; width: max-content; margin: 0;
  padding: 3px; border: 1px solid var(--line); border-radius: 12px; background: var(--track);
}
.unit-toggle button {
  min-width: 58px; padding: 6px 14px; border-radius: 9px;
  font-family: var(--mono); font-size: 11px; font-weight: 600; color: var(--faint);
  transition: background .15s, color .15s;
}
.unit-toggle button.sel { background: var(--ac-soft); color: var(--ac); }
.unit-toggle + .num-card .num-read { padding: 12px 0 6px; }

/* ── The instrument: measurement ruler ─────────────────────────────────
   funnel.js builds .ruler-track (one 12px <i> per unit, labels every
   major) inside [data-ruler] and hangs .ruler-needle on the shell. The
   centre cursor is the only ember in the flow. */
.ruler-shell { position: relative; margin: 12px 0 6px; }
.ruler {
  position: relative;
  height: 84px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  cursor: grab;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%);
}
.ruler:active { cursor: grabbing; }
.ruler::-webkit-scrollbar { display: none; }
/* Percentage padding resolves against the scroll container's width, so
   the first and last tick can always reach the centre needle. */
.ruler-track { display: flex; align-items: flex-start; height: 100%; width: max-content; padding: 0 50%; }
.ruler-track i {
  flex: none; width: 12px; height: 22px;
  position: relative; margin-top: 22px;
  background: linear-gradient(90deg, rgba(var(--ink-rgb), .16) 0 1.5px, transparent 1.5px);
}
.ruler-track i.mid { height: 32px; background: linear-gradient(90deg, rgba(var(--ink-rgb), .30) 0 1.5px, transparent 1.5px); }
.ruler-track i.maj { height: 42px; background: linear-gradient(90deg, rgba(var(--ink-rgb), .55) 0 1.5px, transparent 1.5px); }
.ruler-track i.maj b {
  position: absolute; top: 100%; left: 0;
  transform: translateX(-50%);
  margin-top: 7px;
  color: var(--faint); font-family: var(--mono); font-size: 10px; font-weight: 600;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Keep today's badge in the ruler's top band, clear of the number labels
   below. Explicit type metrics keep it inside the clipped scroll viewport. */
.ruler-track i.here {
  height: 38px; margin-top: 26px;
  background: linear-gradient(90deg, var(--ac) 0 2px, transparent 2px);
}
.ruler-track i.here u {
  position: absolute; bottom: 100%; left: 1px;
  transform: translateX(-50%);
  margin-bottom: 6px; padding: 2px 7px; border-radius: 999px;
  background: var(--ac); color: var(--on-ac);
  font-family: var(--mono); font-size: 9px; line-height: 14px;
  font-style: normal; font-weight: 700; letter-spacing: .4px;
  text-decoration: none; text-transform: uppercase; white-space: nowrap;
}
.ruler-needle {
  position: absolute; top: 12px; bottom: 30px;
  left: 50%; width: 2px; transform: translateX(-50%);
  border-radius: 2px; background: var(--ember);
  box-shadow: 0 0 14px 2px rgba(10, 10, 11, .55);
  pointer-events: none;
}
.num-card.has-ruler .num-ctrl.ruler-nudges {
  grid-template-columns: 44px 44px;
  justify-content: center; gap: 18px;
  margin-top: 10px;
}
.num-card.has-ruler input.range {
  position: absolute; width: 1px; height: 1px;
  opacity: 0; pointer-events: none;
}
.num-card.has-ruler .num-read output { color: var(--tx); }
.target-line { color: var(--faint); font-family: var(--mono); font-size: 11px; letter-spacing: .4px; padding-top: 6px; }
.target-line b { color: var(--dim); font-weight: 600; }
.target-line em { font-style: normal; color: var(--ac); font-weight: 600; }

/* ── Cycle + rest-day picker ────────────────────────────────────────── */
.weekday-picker {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px; padding: 10px 0 4px;
}
#cycle-length-row { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 6px; }
#cycle-length-row button { min-width: 0; padding: 0; }
.weekday-picker button {
  display: grid; place-items: center; align-content: center; gap: 3px;
  min-height: 60px; padding: 8px 4px; border-radius: 14px;
  border: 1px solid var(--line); background: var(--raised); color: var(--tx);
  transition: background .15s, border-color .15s, color .15s, transform .12s;
}
.weekday-picker button span { font-size: 16px; font-weight: 800; line-height: 1; }
.weekday-picker button b { font-family: var(--mono); font-size: 7.5px; font-weight: 600; letter-spacing: .07em; line-height: 1; color: var(--faint); }
.weekday-picker button:active { transform: scale(.94); }
/* FILLED = a day you train; rest days recede. */
.weekday-picker button.sel {
  background: linear-gradient(180deg, rgba(var(--ink-rgb), .16), rgba(var(--ink-rgb), .06));
  border-color: var(--ac); color: var(--ac);
}
.weekday-picker button.sel b { color: var(--ac); opacity: .75; }
.weekday-picker button.rest {
  background: transparent; border-style: dashed; border-color: var(--line2); color: var(--faint);
}
.weekday-picker button.rest b { color: var(--faint); }

/* ── Segmented rows ─────────────────────────────────────────────────── */
.seg-block { display: grid; gap: 20px; padding: 6px 0; }
.seg-row { display: grid; gap: 10px; transition: opacity .25s; }
.seg-row.is-off { opacity: .3; pointer-events: none; }
.seg-row > span,
.q-cap { color: var(--faint); font-family: var(--mono); font-size: 9.5px; font-weight: 600; letter-spacing: 1.2px; text-transform: uppercase; }
/* A caption for a control group that is not a .seg-row — same voice as the
   row labels, so a screen mixing the two does not look like two designs. */
.q-cap { margin: 16px 0 -2px; }
.mini { display: flex; flex-wrap: wrap; gap: 7px; }
/* Rows whose options should share the width evenly rather than hug their
   labels — a 1-to-7 day picker looks broken when "7" is narrower than "3". */
.seg-row.wide .mini { display: grid; grid-auto-columns: 1fr; grid-auto-flow: column; }
.seg-row.wide .mini button { padding: 0 4px; }
/* Compact choice cards: used where a screen already carries another control
   above them and full-height cards would push the CTA off a small phone.
   The subtitle stays — it is what makes "Solid" mean something. */
.choices.tight { gap: 7px; }
.choices.tight .choice { padding: 10px 13px; }
.choices.tight .choice small { font-size: 11.5px; }
.mini button {
  min-height: 40px; padding: 0 16px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--raised);
  font-size: 13.5px; font-weight: 700; color: var(--dim);
  transition: background .15s, border-color .15s, color .15s;
}
.mini button.sel {
  background: linear-gradient(180deg, rgba(var(--ink-rgb), .12), rgba(var(--ink-rgb), .05));
  border-color: var(--ac); color: var(--ac);
}
/* ── Cardio, the app's screen ───────────────────────────────────────────
   OnboardingV3's CardioScreen, in CSS: a tappable week of day columns
   (session length = bar height), a stepper, one movement, one effort,
   and a readout against the 150-minute recommendation. */
.cap-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 16px 0 0; }
.cap-row .q-cap { margin: 0; }
.cap-val {
  font-family: var(--mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: .6px; text-transform: uppercase; color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.cardio-week { display: flex; gap: 7px; margin-top: 10px; align-items: flex-end; }
.cardio-week button {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 7px;
  background: none; border: 0; padding: 0; min-width: 0;
}
.cardio-week button:active { opacity: .85; }
.cw-col {
  position: relative; width: 100%; height: 68px; border-radius: 13px;
  border: 1px solid var(--line); background: var(--raised); overflow: hidden;
  display: flex; align-items: flex-end; justify-content: center;
  transition: border-color .18s;
}
.cardio-week button.on .cw-col { border-color: var(--ac); }
.cw-bar {
  display: block; width: 100%; height: 0; border-radius: 11px;
  background: var(--ac);
  transition: height .28s cubic-bezier(.3, .9, .3, 1);
}
.cw-plus {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-style: normal; font-size: 15px; font-weight: 600; color: var(--line2);
  transition: opacity .18s;
}
.cardio-week button.on .cw-plus { opacity: 0; }
.cw-num { font-size: 11px; font-weight: 700; color: var(--faint); }
.cardio-week button.on .cw-num { color: var(--tx); }
#cardio-rest { transition: opacity .25s; }
#cardio-rest.is-off { opacity: .32; pointer-events: none; }
/* One stepper, three homes: cardio minutes, sleep target, bedtime. The
   hidden [data-segment] buttons remain the control — see .sr-hidden. */
.stepper { display: flex; align-items: center; gap: 9px; margin-top: 9px; }
.st-pm {
  flex: none; width: 52px; height: 52px; border-radius: 15px;
  border: 1px solid var(--line); background: var(--raised);
  display: grid; place-items: center;
  font-size: 20px; font-weight: 600; line-height: 1; color: var(--tx);
}
.st-pm:active { background: var(--ac-soft); }
.st-val {
  flex: 1; height: 52px; border-radius: 15px;
  border: 1px solid var(--line); background: var(--raised);
  display: flex; align-items: center; justify-content: center; gap: 6px;
}
.st-val b {
  font-size: 21px; font-weight: 800; letter-spacing: -.8px; color: var(--tx);
  font-variant-numeric: tabular-nums;
}
.st-val i {
  font-style: normal; font-family: var(--mono); font-size: 9px; font-weight: 700;
  letter-spacing: 1px; text-transform: uppercase; color: var(--faint); margin-top: 5px;
}
/* The fine-grained option lists the steppers and drags click into —
   rendered off-screen, same pattern as the step dial's .sd-notches. */
.sr-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
/* Activity chips: one horizontally scrolling row, bled to the screen edge
   with a trailing inset so the cut-off chip says "this scrolls". */
.cardio-kinds-scroll {
  overflow-x: auto; margin: 9px -20px 0; padding: 0 20px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.cardio-kinds-scroll::-webkit-scrollbar { display: none; }
.cardio-kinds { display: flex; gap: 7px; width: max-content; padding-right: 24px; }
.cardio-kinds button {
  display: flex; align-items: center; gap: 7px; min-height: 42px;
  padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--raised);
  font-size: 13px; font-weight: 700; color: var(--dim); white-space: nowrap;
  transition: background .15s, border-color .15s, color .15s;
}
.cardio-kinds button svg {
  width: 15px; height: 15px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.cardio-kinds button.sel { border-color: var(--ac); background: var(--ac-soft); color: var(--ac); }
.cardio-efforts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin-top: 9px; }
.cardio-efforts button {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 46px; padding: 6px 4px; border-radius: 14px;
  border: 1px solid var(--line); background: var(--raised);
  transition: background .15s, border-color .15s;
}
.cardio-efforts button b { font-size: 13px; font-weight: 800; color: var(--dim); }
.cardio-efforts button span {
  font-family: var(--mono); font-size: 7.5px; font-weight: 700;
  letter-spacing: .7px; text-transform: uppercase; color: var(--faint); margin-top: 2px;
}
.cardio-efforts button.sel { border-color: var(--ac); background: var(--ac-soft); }
.cardio-efforts button.sel b { color: var(--ac); }
/* The readout: your week and the recommendation on one shared axis. */
.cardio-out {
  margin-top: 18px; padding: 15px 16px; border-radius: 20px;
  border: 1px solid var(--line); background: var(--raised);
}
.out-row { display: flex; align-items: center; gap: 11px; }
.out-row + .out-row { margin-top: 10px; }
.out-key {
  flex: none; width: 78px;
  font-family: var(--mono); font-size: 8.5px; font-weight: 700;
  letter-spacing: .8px; text-transform: uppercase; color: var(--faint);
}
.out-row.mine .out-key { color: var(--tx); }
.out-track { flex: 1; height: 10px; border-radius: 5px; background: var(--track); overflow: hidden; }
.out-track i {
  display: block; height: 100%; width: 0; border-radius: 5px;
  background: var(--line2);
  transition: width .5s cubic-bezier(.3, .8, .3, 1);
}
.out-row.mine .out-track i { background: var(--ac); }
.out-val {
  flex: none; width: 58px; text-align: right;
  font-size: 12.5px; font-weight: 800; color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.out-row.mine .out-val { color: var(--tx); }
.cardio-out .hint {
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 12px; line-height: 1.4; color: var(--dim); text-align: left;
}
.cardio-out .hint:empty { display: none; }

/* ── The pet ────────────────────────────────────────────────────────────
   The artwork is never repainted; the volume is built around it. See pet.js
   for the springs. The two blend values below are the whole reason she sits
   IN the page rather than on top of it:
     · the aura is a blurred copy of her own art, so at a tight blur it read
       as a second, grey-blue pet behind the first. Pushed wide and faint,
       the edge stops existing and it becomes light instead of a duplicate.
     · the sheen used `screen` centred on her body, which bleached the lit
       ring around her face — the reported hard edge. It is `overlay` now,
       parked up-left over the shoulder, and masked so it never reaches the
       face at all. Light on the body; her face keeps its own glow. */
.pet { position: relative; display: grid; place-items: center; touch-action: none; user-select: none; -webkit-user-select: none; }
.pet[data-interactive] { cursor: grab; }
.pet[data-interactive].is-grabbed { cursor: grabbing; }
.pet-stage { position: relative; width: 100%; height: 100%; perspective: 620px; display: grid; place-items: center; }
.pet-tilt { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; will-change: transform; }
.pet-aura, .pet-body, .pet-sheen { position: absolute; inset: 0; pointer-events: none; display: block; }
.pet-aura { transform: translateZ(-34px) scale(1.30); filter: blur(26px) saturate(1.25); opacity: .30; }
.pet-body { transform: translateZ(0); }
.pet-aura img, .pet-body img { width: 100%; height: 100%; display: block; -webkit-user-drag: none; }
/* The SVG creature fills the same layers the raster did. `.hp` sizes
   itself off --hp-size, which means nothing inside an inset-0 span. */
.pet-aura .hp, .pet-body .hp { width: 100%; height: 100%; display: block; }
.pet-sheen {
  transform: translateZ(26px); border-radius: 50%;
  mix-blend-mode: overlay; opacity: .5; filter: blur(3px);
  -webkit-mask-image: radial-gradient(circle at 34% 30%, #000 8%, transparent 46%);
  mask-image: radial-gradient(circle at 34% 30%, #000 8%, transparent 46%);
}
.pet-shadow {
  position: absolute; left: 50%; bottom: -1%; width: 54%; height: 9%; border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(var(--ink-rgb), .26), transparent 70%);
  filter: blur(6px); transform: translateX(-50%); will-change: transform, opacity;
}
/* The meeting step. The stage flexes so a longer line takes room from her
   breathing space rather than pushing the CTA off a short phone. */
/* The step itself must be a column for the hero's flex:1 to mean anything —
   .step.on is display:block, so without this she pins to the top and leaves
   a hole above the CTA. */
[data-step="meet"].step.on { display: flex; flex-direction: column; min-height: calc(100dvh - 210px); }
[data-step="meet"] .pet-hero { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; flex: 1; min-height: 0; }
[data-step="meet"] .pet { width: min(52vw, 190px); height: min(52vw, 190px); flex: none; }
.pet-say { margin: 10px 0 0; font-size: 21px; line-height: 1.2; font-weight: 800; letter-spacing: -.6px; color: var(--tx); text-wrap: balance; }
.pet-sub { margin: 6px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--dim); max-width: 30ch; }
.pet-nudge {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 8px;
  font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: var(--faint); transition: opacity .5s;
}
.pet-nudge[data-done] { opacity: 0; }
.pet-nudge i { width: 5px; height: 5px; border-radius: 50%; background: var(--ac); animation: petBlip 1.9s ease-in-out infinite; }
@keyframes petBlip { 0%, 100% { opacity: .25; transform: scale(.8); } 50% { opacity: 1; transform: scale(1); } }
@media (min-width: 760px) {
  /* Not the phone layout stretched: she moves left and the words sit beside
     her at reading size, which is the only arrangement where a 220px
     creature is not stranded in a field of white. */
  [data-step="meet"] .pet-hero { display: grid; grid-template-columns: 1fr 1fr; align-items: center; align-content: center; gap: 34px; text-align: left; }
  [data-step="meet"] .pet { width: 220px; height: 220px; justify-self: center; }
  [data-step="meet"] .pet-copy { display: flex; flex-direction: column; align-items: flex-start; }
  .pet-say { font-size: 30px; }
}
/* THE RIDER — she travels the progress rail for the rest of the flow, so the
   bar stops being an abstract measure and becomes her route. */
.rail-rider {
  position: absolute; top: -13px; width: 30px; height: 30px; margin-left: -15px;
  transition: left .62s cubic-bezier(.34, 1.28, .44, 1);
  pointer-events: none;
}
.rail-rider[hidden] { display: none; }
.fun-progress { position: relative; }

/* ── Own routine: the week, and the effort ramp ─────────────────────────
   Seven slots, the trained ones lit — "4 days" made concrete, and the even
   spread (never a Mon–Thu clump) visible rather than promised. */
.own-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin: 9px 0 2px; }
.own-week button {
  height: 34px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--raised);
  font-family: var(--mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: .5px; text-transform: uppercase; color: var(--faint);
  padding: 0;
  transition: background .22s cubic-bezier(.3, 1, .4, 1), border-color .22s, box-shadow .22s, color .22s;
}
.own-week button.on {
  border-color: var(--ac); color: var(--ac);
  background: linear-gradient(180deg, rgba(var(--ink-rgb), .18), rgba(var(--ink-rgb), .07));
  box-shadow: inset 0 0 0 1px rgba(10, 10, 11, .12);
}
/* Three options on one scale, so they can be compared at a glance — which
   is the only reason to have an intensity scale at all. */
.effort { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.effort button {
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  padding: 13px 6px 11px; border-radius: 16px;
  border: 1px solid var(--line); background: var(--raised);
  transition: transform .16s cubic-bezier(.3, 1.4, .5, 1), border-color .2s, background .2s;
}
.effort button:active { transform: scale(.96); }
.effort .e-ramp { display: flex; align-items: flex-end; gap: 3px; height: 26px; }
.effort .e-ramp u {
  width: 5px; border-radius: 2px; background: var(--line2);
  transition: background .2s, height .2s;
}
.effort .e-ramp u:nth-child(1) { height: 34%; }
.effort .e-ramp u:nth-child(2) { height: 62%; }
.effort .e-ramp u:nth-child(3) { height: 100%; }
/* Each option lights only as far up the ramp as it goes — the bars are the
   answer, not decoration. */
.effort button[data-value="easy"]  .e-ramp u:nth-child(n+2) { opacity: .25; }
.effort button[data-value="steady"] .e-ramp u:nth-child(n+3) { opacity: .25; }
.effort button b { font-size: 12px; font-weight: 700; color: var(--dim); letter-spacing: -.1px; }
.effort button.sel { border-color: var(--ac); background: linear-gradient(180deg, rgba(var(--ink-rgb), .08), rgba(var(--ink-rgb), .03)); }
.effort button.sel b { color: var(--ac); }
.effort button.sel .e-ramp u { background: var(--ac); }

/* ── Steps: one rail, not two bar charts ───────────────────────
   The typical-day answer paints a band on the same rail the goal handle
   slides along, so "above where I walk now" is a position, not a
   calculation. The twelve real steps_goal buttons sit underneath, off
   screen: they are still the control, the handle just clicks them. */
.step-dial { display: grid; gap: 9px; margin-top: 6px; }
.sd-read { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.sd-cap {
  color: var(--faint); font-family: var(--mono); font-size: 9.5px; font-weight: 600;
  letter-spacing: 1.2px; text-transform: uppercase;
}
.sd-out, #sd-out {
  font-size: 30px; font-weight: 700; letter-spacing: -.6px;
  font-variant-numeric: tabular-nums; color: var(--tx);
}
.sd-rail {
  position: relative; height: 44px; border-radius: 16px;
  border: 1px solid var(--line); background: var(--raised);
  touch-action: none; cursor: grab;
}
.sd-rail:active { cursor: grabbing; }
.sd-band {
  position: absolute; top: 7px; bottom: 7px; border-radius: 11px;
  background: repeating-linear-gradient(115deg, rgba(var(--ink-rgb), .12) 0 6px, rgba(var(--ink-rgb), .05) 6px 12px);
  box-shadow: inset 0 0 0 1px rgba(10, 10, 11, .18);
  transition: left .28s cubic-bezier(.3, 1, .4, 1), width .28s cubic-bezier(.3, 1, .4, 1);
}
.sd-fill {
  position: absolute; left: 0; top: 12px; bottom: 12px; border-radius: 999px;
  background: linear-gradient(90deg, rgba(var(--ink-rgb), .28), var(--ac));
  transition: width .12s linear;
}
.sd-knob {
  position: absolute; top: 50%; width: 30px; height: 30px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: var(--raised); border: 2.5px solid var(--ac);
  box-shadow: var(--shadow-1);
  transition: left .12s linear, box-shadow .2s;
}
.sd-knob::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 9px; height: 9px; border-radius: 50%; background: var(--ac);
}
.sd-knob:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(10, 10, 11, .22); }
/* Inside the band the goal is not a stretch — stop selling it as one. */
.sd-rail.in-band .sd-fill { background: linear-gradient(90deg, rgba(var(--ink-rgb), .18), rgba(var(--ink-rgb), .5)); }
.sd-scale { display: flex; justify-content: space-between; padding: 0 2px; }
.sd-scale span {
  color: var(--faint); font-family: var(--mono); font-size: 9.5px;
  font-weight: 600; font-variant-numeric: tabular-nums;
}
.sd-legend { display: flex; align-items: center; gap: 7px; }
.sd-legend i {
  width: 22px; height: 10px; border-radius: 4px;
  background: repeating-linear-gradient(115deg, rgba(var(--ink-rgb), .16) 0 5px, rgba(var(--ink-rgb), .06) 5px 10px);
  box-shadow: inset 0 0 0 1px rgba(10, 10, 11, .2);
}
.sd-legend span { color: var(--faint); font-size: 11.5px; }
/* The contract, kept reachable but not shown: funnel.js binds these. */
.sd-notches { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

/* Receipt card for the computed one-liners (#steps-note / #sleep-note). */
.note-receipt {
  display: flex; align-items: center; gap: 11px;
  margin-top: 16px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: 14px; background: var(--raised);
}
.note-receipt:has(> .hint:empty) { display: none; }
.note-receipt > svg {
  flex: none; width: 18px; height: 18px;
  fill: none; stroke: var(--ac); stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.note-receipt .hint { margin: 0; text-align: left; font-size: 12.5px; color: var(--dim); }

/* ── Sleep: the night-window instrument ─────────────────────────────────
   A 21:00 → 10:00 rail; the glue script in start.html positions the
   glowing window from the two .sel answers and computes the wake time.
   Everything here is decorative — aria-hidden, no funnel.js contract. */
.night-card { margin: 2px 0 18px; }
.night-rail {
  position: relative; height: 56px; border-radius: 14px;
  background: var(--raised); border: 1px solid var(--line);
  overflow: hidden;
}
/* a thin horizon line + a few fixed stars, all paint */
.night-rail::before {
  content: ""; position: absolute; left: 4%; right: 4%; top: 50%;
  height: 1px; background: var(--line);
}
.night-rail::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    radial-gradient(circle 1px at 8% 30%, var(--line2) 99%, transparent),
    radial-gradient(circle 1px at 16% 68%, var(--line) 99%, transparent),
    radial-gradient(circle 1.5px at 55% 26%, var(--line2) 99%, transparent),
    radial-gradient(circle 1px at 72% 62%, var(--line) 99%, transparent),
    radial-gradient(circle 1px at 90% 36%, var(--line2) 99%, transparent);
}
.night-window {
  position: absolute; top: 8px; bottom: 8px; left: 15.4%; width: 61.5%;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 22px 0 10px; border-radius: 10px; z-index: 1;
  background: linear-gradient(135deg, rgba(var(--ink-rgb), .10), rgba(var(--ink-rgb), .18));
  border: 1px solid var(--line2);
  box-shadow: 0 0 22px rgba(10, 10, 11, .28);
  transition: left .35s cubic-bezier(.2, .8, .2, 1), width .35s cubic-bezier(.2, .8, .2, 1);
  cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none;
}
.night-window:active { cursor: grabbing; }
/* right-edge grip — the resize handle for the sleep target */
.night-window .nw-grip {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 9px; height: 18px; cursor: ew-resize;
  background: linear-gradient(90deg, rgba(var(--ink-rgb), .38) 0 2.5px, transparent 2.5px 6.5px, rgba(var(--ink-rgb), .38) 6.5px 9px);
  border-radius: 2px;
}
.night-drag-hint {
  margin-top: 8px; text-align: center;
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .6px;
  color: var(--faint); text-transform: uppercase;
}
/* Two app-style steppers under the rail — target and bedtime. */
.sleep-steppers { display: grid; gap: 14px; margin-top: 4px; }
.sleep-steppers .q-cap { margin: 0 0 -1px; }
.night-window .nw-ic {
  width: 15px; height: 15px; flex: none;
  fill: none; stroke: var(--ac); stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.night-window .nw-hours {
  font-size: 14px; font-weight: 800; letter-spacing: -.02em;
  color: var(--tx); font-variant-numeric: tabular-nums;
}
.night-times {
  position: relative; left: 15.4%; width: 61.5%;
  display: flex; justify-content: space-between;
  margin-top: 6px;
  font-family: var(--mono); font-size: 9.5px; color: var(--dim);
  font-variant-numeric: tabular-nums;
  transition: left .35s cubic-bezier(.2, .8, .2, 1), width .35s cubic-bezier(.2, .8, .2, 1);
}
.night-times b { font-weight: 600; }
.night-ticks { position: relative; height: 14px; margin-top: 2px; }
.night-ticks span {
  position: absolute; left: var(--x); transform: translateX(-50%);
  font-family: var(--mono); font-size: 8px; letter-spacing: .5px; color: var(--faint);
}
.night-ticks span:first-child { transform: none; }

.workout-dose { padding-top: 4px; }
.workout-dose .mini button { flex: 1 1 52px; padding-inline: 12px; }
/* Worded chips ("Let Heala decide", "Push / pull / legs") — five equal
   columns forced three-line labels. Let each chip hug its own label on a
   single line and wrap the ROW instead; smaller type so the label stays
   quieter than the box it sits in. */
.workout-dose .mini.wrap button {
  flex: 1 0 auto; font-size: 12px; padding-inline: 11px;
  line-height: 1.25; white-space: nowrap;
}
.workout-dose-receipt {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 13px 15px; border: 1px solid var(--line); border-radius: 14px; background: var(--raised);
}
.workout-dose-receipt b { font-size: 14px; font-weight: 800; font-variant-numeric: tabular-nums; }
.workout-dose-receipt span { color: var(--faint); font-size: 11px; text-align: right; }

/* ── AI brief ───────────────────────────────────────────────────────── */
.brief { margin-bottom: 18px; }
.brief[hidden] { display: none; }
.brief textarea {
  width: 100%; padding: 15px; border-radius: 15px; resize: vertical;
  border: 1px solid var(--line); background: var(--raised); color: var(--tx);
  font-size: 15px; line-height: 1.5; min-height: 110px;
  transition: border-color .2s;
}
.brief textarea:focus { outline: none; border-color: var(--ac); }
.brief textarea::placeholder { color: var(--faint); }
.brief-foot { display: flex; justify-content: flex-end; margin-top: 8px; }
.brief-foot > span { color: var(--faint); font-family: var(--mono); font-size: 10px; letter-spacing: .5px; }

/* ── Pace v2: drag the landing ──────────────────────────────────────────
   Built from zero to the approved preview. The instrument card holds the
   draggable projection; the safety landscape and receipt rows sit in
   .pace-box (funnel.js hides that whole box on a recomp/maintain plan).
   #curve-svg (funnel.js's own painting) stays in the DOM, off-screen. */
.p2-card { border: 1px solid var(--line); border-radius: 16px; padding: 13px 13px 6px; background: var(--raised); }
.p2-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.p2-head b { font-size: 14px; font-weight: 800; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.safety { padding: 4px 9px; border-radius: 7px; font-family: var(--mono); font-size: 8.5px; font-weight: 700; letter-spacing: .8px; transition: color .2s, background .2s; }
.safety.safe { color: var(--ok); background: rgba(var(--ink-rgb), .12); }
.safety.warn { color: var(--amber); background: rgba(var(--ink-rgb), .12); }
.safety.unsafe { color: var(--red); background: rgba(217, 45, 32, .12); }
.p2-legacy { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.p2-chart {
  display: block; width: 100%; height: auto;
  cursor: grab; touch-action: none;
  -webkit-user-select: none; user-select: none;
}
.p2-chart:active { cursor: grabbing; }
.p2-chart text { font-family: var(--mono); font-size: 11px; fill: var(--faint); }
.p2-chart .flag { font-size: 12px; font-weight: 600; fill: var(--ac); }
.p2-chart .flagbg { fill: var(--track); stroke: var(--line2); }
/* The glue script emits CLASSES, not colors — the chart re-themes with
   the page, no repaint needed. */
.p2-chart .p2-axis { stroke: var(--line); fill: none; }
.p2-chart .p2-maint { stroke: var(--line2); fill: none; }
.p2-chart .p2-curve { stroke: var(--ac); fill: none; }
.p2-chart .p2-start { fill: var(--dim); }
.p2-chart .p2-startlbl { fill: var(--tx); font-weight: 600; }
.p2-chart .p2-halo { fill: var(--ac-soft); }
.p2-chart .p2-dot { fill: var(--ac); stroke: var(--raised); }
#p2a stop { stop-color: var(--ac2); }
.p2-drag-hint {
  margin: 2px 0 8px; text-align: center;
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .6px;
  color: var(--faint); text-transform: uppercase;
}
.goal-date { padding: 2px 2px 8px; color: var(--dim); font-size: 12.5px; text-align: center; }
.goal-date b { color: var(--tx); }
.pace-box { margin-top: 14px; }
.p2-word { display: none; }   /* funnel.js still writes #pace-out; the chip + read row carry the word now */
.p2-band {
  position: relative; height: 40px; padding: 0 2px;
  cursor: grab; touch-action: none;
  -webkit-user-select: none; user-select: none;
}
.p2-band:active { cursor: grabbing; }
.p2-zones {
  position: absolute; left: 0; right: 0; top: 17px; height: 6px;
  border-radius: 99px; display: flex; overflow: hidden;
}
.p2-zones i { height: 100%; }
.p2-zones i:nth-child(1) { background: rgba(var(--ink-rgb), .55); }
.p2-zones i:nth-child(2) { background: rgba(var(--ink-rgb), .42); }
.p2-zones i:nth-child(3) { background: rgba(var(--ink-rgb), .55); }
.p2-zones i:nth-child(4) { background: rgba(217, 45, 32, .45); }
.p2-knob {
  position: absolute; top: 6px; width: 28px; height: 28px; border-radius: 50%;
  background: var(--ac); border: 3px solid var(--raised); transform: translateX(-14px);
  box-shadow: 0 2px 8px rgba(10, 10, 11, .22), 0 0 0 3px rgba(10, 10, 11, .16);
  transition: left .2s cubic-bezier(.2, .8, .2, 1), box-shadow .2s;
}
.p2-band:active .p2-knob { box-shadow: 0 2px 10px rgba(10, 10, 11, .26), 0 0 0 7px rgba(10, 10, 11, .18); }
.p2-zone-labels {
  display: flex; margin-top: -1px;
  font-family: var(--mono); font-size: 7.5px; letter-spacing: .5px;
  color: var(--faint); text-transform: uppercase;
}
.p2-zone-labels span { text-align: center; overflow: hidden; white-space: nowrap; }
.p2-zone-labels span:nth-child(1) { color: rgba(var(--ink-rgb), .8); }
.p2-zone-labels span:nth-child(2) { color: rgba(var(--ink-rgb), .55); }
.p2-zone-labels span:nth-child(3) { color: rgba(var(--ink-rgb), .8); }
.p2-zone-labels span:nth-child(4) { color: rgba(217, 45, 32, .75); }
/* The real control: visually hidden, still focusable — arrow keys drive
   the whole instrument through funnel.js's own input path. */
.p2-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.pace-box:has(.p2-input:focus-visible) .p2-knob { box-shadow: 0 2px 8px rgba(10, 10, 11, .22), 0 0 0 4px var(--ac); }
.p2-out {
  margin-top: 12px; display: flex; flex-direction: column;
  border-radius: 15px; background: var(--raised); border: 1px solid var(--line); overflow: hidden;
}
.p2-out .r {
  display: flex; justify-content: space-between; align-items: center; padding: 10px 14px;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 9.5px; color: var(--faint);
  letter-spacing: .8px; text-transform: uppercase;
}
.p2-out .r:first-child { border-top: 0; }
.p2-out .r b {
  font-family: var(--display); font-size: 15px; color: var(--tx);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; text-transform: none;
}
/* Movement asks three things (activity, walk band, step goal) — full-height
   choice cards pushed the dial under the CTA on a phone. Everything shrinks
   a notch so the whole screen fits without scrolling. */
[data-step="movement"] .q-head { padding: 8px 0 12px; }
[data-step="movement"] .choices { gap: 6px; }
[data-step="movement"] .choice { min-height: 46px; padding: 8px 42px 8px 12px; border-radius: 13px; }
[data-step="movement"] .choice .ic { width: 30px; height: 30px; border-radius: 9px; }
[data-step="movement"] .choice .ic svg { width: 16px; height: 16px; }
[data-step="movement"] .cc b { font-size: 13.5px; }
[data-step="movement"] .cc small { font-size: 10.5px; }
/* The caption needs air under it: the base rule ends on -2px, which is right
   above a .num-card (it carries its own 6px) and far too tight above a bare
   row of chips. */
[data-step="movement"] .q-cap { margin: 14px 0 9px; }
[data-step="movement"] .step-dial { gap: 7px; }
[data-step="movement"] .note-receipt { margin-top: 10px; padding-top: 8px; padding-bottom: 8px; }
[data-step="pace"] .q-head { padding: 8px 0 14px; }
[data-step="pace"] .q-head .sub { margin-top: 6px; font-size: 13px; }
[data-step="pace"] .hint.is-warn, [data-step="pace"] .hint.is-danger { margin-top: 11px; }
@media (max-height: 760px) {
  [data-step="pace"] .q-head h1 { font-size: clamp(22px, 5.6vw, 28px); }
  [data-step="pace"] .p2-drag-hint { display: none; }
  .p2-out .r { padding: 7px 14px; }
  .p2-out .r b { font-size: 13.5px; }
}

/* ── Building the program ───────────────────────────────────────────── */
.compute { padding: 9vh 0 0; text-align: center; }
.spin {
  display: block; width: 42px; height: 42px; margin: 0 auto 24px;
  border-radius: 50%; border: 3px solid var(--track); border-top-color: var(--ac);
  animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.compute-lines { max-width: 360px; margin: 26px auto 0; display: grid; text-align: left; }
.cl { display: flex; align-items: center; gap: 11px; padding: 12px 2px; border-bottom: 1px solid var(--line); opacity: .32; transition: opacity .4s; }
.cl:last-child { border-bottom: 0; }
.cl.on { opacity: 1; }
.cl i {
  flex: none; width: 17px; height: 17px; border-radius: 50%;
  border: 1.5px solid var(--line2); position: relative; transition: background .3s, border-color .3s;
}
.cl.on i { background: var(--ac); border-color: var(--ac); }
.cl.on i::after {
  content: ''; position: absolute; left: 5px; top: 2.5px;
  width: 4px; height: 8px;
  border-right: 2px solid var(--on-ac); border-bottom: 2px solid var(--on-ac);
  transform: rotate(42deg);
}
.cl span { display: grid; gap: 1px; }
.cl b { font-size: 13.5px; font-weight: 700; }
.cl small { color: var(--faint); font-size: 11.5px; }
.form-err { color: var(--red); font-size: 13px; font-weight: 600; min-height: 1em; margin-top: 14px; }
.form-err:empty { margin: 0; min-height: 0; }

/* ── Program preview ────────────────────────────────────────────────── */
[data-step="program_preview"] .q-head { padding-bottom: 14px; }
.ai-proof {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 13px; margin-bottom: 12px;
  border: 1px solid var(--line2); border-radius: 13px; background: var(--ac-soft);
}
.ai-proof[hidden] { display: none; }
.ai-proof i { width: 7px; height: 7px; border-radius: 50%; background: var(--ac); animation: pulse 2s ease-in-out infinite; }
.ai-proof span { color: var(--ac); font-family: var(--mono); font-size: 9px; font-weight: 600; letter-spacing: 1.2px; }
.ai-proof b { width: 100%; color: var(--dim); font-size: 12.5px; font-weight: 500; font-style: italic; }
.day-tabs { display: flex; gap: 7px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 12px; scrollbar-width: none; }
.day-tabs::-webkit-scrollbar { display: none; }
.day-tabs button {
  flex: none; display: grid; gap: 1px; text-align: left;
  padding: 8px 13px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--raised); color: var(--dim);
  transition: border-color .2s, background .2s, color .2s;
}
.day-tabs button span { font-family: var(--mono); font-size: 9px; font-weight: 600; letter-spacing: .8px; text-transform: uppercase; color: var(--faint); }
.day-tabs button b { font-size: 12.5px; font-weight: 700; white-space: nowrap; }
.day-tabs button.is-active {
  border-color: var(--ac); background: var(--ac-soft); color: var(--ac);
}
.day-tabs button.is-active span { color: var(--ac); }
.program-day { border: 1px solid var(--line); border-radius: 16px; overflow: hidden; background: var(--raised); }
.program-day-head { display: flex; align-items: baseline; gap: 10px; padding: 12px 15px; border-bottom: 1px solid var(--line); background: rgba(var(--ink-rgb), .04); }
.program-day-head span { color: var(--ac); font-family: var(--mono); font-size: 9.5px; font-weight: 600; letter-spacing: .8px; text-transform: uppercase; }
.program-day-head b { font-size: 14.5px; font-weight: 800; }
.program-exercise { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 15px; }
.program-exercise + .program-exercise { border-top: 1px solid var(--line); }
.exercise-copy { display: grid; gap: 1px; min-width: 0; }
.exercise-copy b { font-size: 13.5px; font-weight: 700; }
.exercise-copy span { color: var(--faint); font-size: 12px; }
.program-exercise em { flex: none; color: var(--faint); font-family: var(--mono); font-size: 10px; font-style: normal; }
.program-exercise.is-locked .exercise-copy, .program-exercise.is-locked > em { filter: blur(5px); opacity: .55; pointer-events: none; user-select: none; }
.exercise-lock { position: absolute; inset: 0; display: grid; place-items: center; }
.exercise-lock svg { width: 17px; height: 17px; fill: none; stroke: var(--dim); stroke-width: 1.8; stroke-linecap: round; }
.program-cardio {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 15px; border-top: 1px dashed var(--line2); background: rgba(var(--ink-rgb), .035);
}
.program-cardio span { font-size: 13px; font-weight: 700; color: var(--ac); }
.program-cardio em { color: var(--faint); font-family: var(--mono); font-size: 10px; font-style: normal; }
.program-support { margin-top: 12px; }
.program-support-label { display: block; color: var(--faint); font-family: var(--mono); font-size: 9.5px; font-weight: 600; letter-spacing: 1px; margin-bottom: 8px; text-transform: uppercase; }
.program-support div { display: flex; flex-wrap: wrap; gap: 7px; }
.program-support i {
  display: grid; gap: 1px; font-style: normal;
  padding: 8px 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--raised);
}
.program-support i b { font-size: 12px; font-weight: 800; }
.program-support i span { color: var(--faint); font-size: 11px; }
.program-support p { color: var(--faint); font-size: 12.5px; }
.program-more { display: grid; gap: 2px; margin-top: 12px; padding: 12px 15px; border-radius: 13px; background: var(--ac-soft); }
.program-more span { color: var(--ac); font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: 1px; }
.program-more small { color: var(--dim); font-size: 12px; }
.program-more svg { display: none; }
.saved-chip {
  display: grid; grid-template-columns: auto 1fr; align-items: center; column-gap: 10px; row-gap: 1px;
  margin-top: 10px; padding: 11px 15px; border-radius: 13px;
  border: 1px solid rgba(var(--ink-rgb), .3); background: rgba(var(--ink-rgb), .09);
}
.saved-chip[hidden] { display: none; }
.saved-chip svg { grid-row: span 2; width: 18px; height: 18px; fill: none; stroke: var(--ok); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.saved-chip span { color: var(--ok); font-family: var(--mono); font-size: 9.5px; font-weight: 600; letter-spacing: 1px; }
.saved-chip small { color: var(--dim); font-size: 12px; }

/* ── Nutrition targets ──────────────────────────────────────────────── */
.targets { padding-top: 6px; }
.t-ring-wrap { position: relative; width: 205px; height: 205px; margin: 0 auto; }
/* funnel.js paints the arc inline with its own faint remainder; that
   remainder was mixed for a white ground, so a real track ring sits
   under it here. Both use the same radial mask. */
.t-ring-wrap::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 225deg, var(--track) 0 270deg, transparent 270deg 360deg);
  -webkit-mask: radial-gradient(closest-side, transparent 74%, #000 75%);
          mask: radial-gradient(closest-side, transparent 74%, #000 75%);
}
.t-ring { position: absolute; inset: 0; border-radius: 50%; -webkit-mask: radial-gradient(closest-side, transparent 74%, #000 75%); mask: radial-gradient(closest-side, transparent 74%, #000 75%); }
.t-center { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; gap: 3px; }
.t-center b {
  font-size: 46px; font-weight: 800; letter-spacing: -.05em; line-height: 1;
  font-variant-numeric: tabular-nums;
  background: linear-gradient(160deg, var(--tx), var(--ac)); -webkit-background-clip: text;
  background-clip: text; color: transparent;
}
.t-center span { color: var(--faint); font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: .8px; text-transform: uppercase; }
.t-macros { display: grid; gap: 12px; margin-top: 24px; }
.t-macro i { display: flex; align-items: center; justify-content: space-between; font-style: normal; margin-bottom: 6px; }
.t-macro i > span { display: flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: 1px; text-transform: uppercase; color: var(--faint); }
.t-macro i b { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot.p { background: var(--macro-p); }
.dot.c { background: var(--macro-c); }
.dot.f { background: var(--macro-f); }
.t-macro .bar { height: 6px; border-radius: 999px; background: var(--track); overflow: hidden; }
.t-macro .bar span { display: block; height: 100%; width: 0; border-radius: 999px; transition: width .9s cubic-bezier(.3, .8, .3, 1) .15s; }
/* The one deliberate exception to the monochrome room: the handover. The
   plan is the payoff, and the payoff gets the app's own macro identity
   colours (lib/viz.ts MACRO_RING — P coral, C sky, F amber). fillTargets()
   reads --ring-from/--ring-to for the kcal arc, so the hue lives here. */
.t-macro:nth-child(1) .bar span { background: var(--macro-p); }
.t-macro:nth-child(2) .bar span { background: var(--macro-c); }
.t-macro:nth-child(3) .bar span { background: var(--macro-f); }
[data-step="ready"] .q-head { padding: 8px 0 12px; }
[data-step="ready"] .q-head .sub { margin-top: 5px; font-size: 13px; }
@media (max-height: 820px) {
  [data-step="ready"] .q-head h1 { font-size: clamp(22px, 5.6vw, 27px); }
  [data-step="ready"] .t-ring-wrap { width: 168px; height: 168px; }
  [data-step="ready"] .t-center b { font-size: 34px; }
  [data-step="ready"] .t-macros { margin-top: 12px; gap: 8px; }
  [data-step="ready"] .t-macro i { margin-bottom: 4px; }
  [data-step="ready"] .hint { margin-top: 8px; font-size: 12px; }
}
@media (max-height: 690px) {
  [data-step="ready"] .t-ring-wrap { width: 138px; height: 138px; }
  [data-step="ready"] .t-center b { font-size: 29px; }
  [data-step="ready"] .q-head .sub { display: none; }
}

/* ── Account / save-plan step ─────────────────────────────────────────
   Compact by contract: hero + recap + 3 fields + CTA + footer must fit a
   phone viewport with NO scrolling. */
.acct-hero { display: flex; align-items: center; gap: 13px; text-align: left; }
.acct-head h1 { font-size: clamp(22px, 5.9vw, 27px); line-height: 1.08; letter-spacing: -.04em; font-weight: 800; }
.acct-head h1 em { font-style: normal; color: var(--ac); }
.acct-head p { margin-top: 5px; color: var(--dim); font-size: 12.5px; line-height: 1.45; }

/* Living pet companion — breathing bob, aura, ground shadow, JS cheer. */
.pet { position: relative; display: inline-flex; flex: none; will-change: transform; }
.pet > img { display: block; width: 100%; height: 100%; position: relative; z-index: 1; }
.pet::before {
  content: ''; position: absolute; inset: -24%; border-radius: 50%; z-index: 0;
  background: radial-gradient(circle, rgba(var(--ink-rgb), .3), rgba(var(--ink-rgb), .22) 42%, transparent 68%);
  filter: blur(5px); animation: petAura 3.4s ease-in-out infinite; pointer-events: none;
}
.pet::after {
  content: ''; position: absolute; left: 50%; bottom: -8%; width: 56%; height: 11%;
  transform: translateX(-50%); border-radius: 50%; z-index: 0;
  background: radial-gradient(circle, rgba(var(--ink-rgb), .22), transparent 70%);
  filter: blur(1px); animation: petShadow 3.4s ease-in-out infinite; pointer-events: none;
}
@keyframes petAura  { 0%, 100% { opacity: .55; transform: scale(.92); } 50% { opacity: 1; transform: scale(1.08); } }
@keyframes petShadow { 0%, 100% { opacity: .5; transform: translateX(-50%) scale(1); } 50% { opacity: .3; transform: translateX(-50%) scale(.8); } }
.pet.is-cheer { animation: petCheer .72s cubic-bezier(.2, 1.3, .3, 1); }
@keyframes petCheer {
  0% { transform: scale(1) rotate(0); }
  30% { transform: scale(1.16) rotate(-6deg); }
  55% { transform: scale(.95) rotate(5deg); }
  78% { transform: scale(1.06) rotate(-2deg); }
  100% { transform: scale(1) rotate(0); }
}
.pet .spark {
  position: absolute; width: 8px; height: 8px; z-index: 2; opacity: 0; pointer-events: none;
  background: radial-gradient(circle, #fff, rgba(var(--ink-rgb), .55) 55%, transparent 70%);
  border-radius: 50%; animation: petSpark 2.4s ease-in-out infinite;
}
.pet .spark:nth-child(1) { top: 6%;  left: 12%; animation-delay: .0s; }
.pet .spark:nth-child(2) { top: 18%; right: 6%; width: 6px; height: 6px; animation-delay: .5s; }
.pet .spark:nth-child(3) { bottom: 20%; left: 4%; width: 5px; height: 5px; animation-delay: 1.1s; }
.pet .spark:nth-child(4) { bottom: 8%; right: 16%; animation-delay: 1.6s; }
@keyframes petSpark {
  0%, 100% { opacity: 0; transform: scale(.4); }
  40%, 60% { opacity: 1; transform: scale(1); }
}
.acct-hero .pet { width: 64px; height: 64px; }
.acct-pet {
  /* ⚠️ --hp-size, NOT width. The drawing sizes itself off that variable, and
     heala-pet.css loads after this file — a bare `width: 64px` here has the
     same specificity as `.hp`'s own width and loses on source order, so the
     creature would arrive at its 96px default and blow the row apart. */
  --hp-size: 64px;
  display: block;
  animation: petIn .5s cubic-bezier(.2, 1.2, .3, 1) both, petBob 3.4s ease-in-out .55s infinite;
}
@keyframes petBob {
  0%, 100% { transform: translateY(0) rotate(-2.5deg); }
  25% { transform: translateY(-3px) rotate(0deg); }
  50% { transform: translateY(-5px) rotate(2.5deg); }
  75% { transform: translateY(-3px) rotate(0deg); }
}
.plan-recap {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 7px;
  margin: 15px 0 16px;
}
.plan-recap:empty { display: none; }
.plan-recap div {
  display: grid; gap: 3px; align-content: center; padding: 11px 4px 10px;
  border: 1px solid var(--line); border-radius: 13px;
  background: var(--raised);
  text-align: center; min-width: 0;
}
.plan-recap b {
  font-size: clamp(12.5px, 3.7vw, 15px); font-weight: 800; letter-spacing: -.03em; color: var(--ac);
  line-height: 1.1; word-break: normal; overflow-wrap: normal; hyphens: none;
  font-variant-numeric: tabular-nums;
}
.plan-recap span { color: var(--faint); font-family: var(--mono); font-size: 7.5px; font-weight: 600; letter-spacing: .5px; text-transform: uppercase; line-height: 1.25; }

/* Save-plan form — one bordered box per field, label inside. */
.acct-form { gap: 9px; }
.acct-form .field {
  display: grid; gap: 1px; padding: 9px 16px 10px;
  border: 1px solid var(--line); border-radius: 18px; background: var(--raised);
  transition: border-color .16s, box-shadow .16s;
}
/* The focused field is state, so it gets the accent — the same ring the
   chosen answer wears two screens earlier. */
.acct-form .field:focus-within { border-color: var(--ac); box-shadow: 0 0 0 4px var(--ac-soft); }
.acct-form .field > span {
  color: var(--faint); font-family: var(--mono); font-size: 9px; font-weight: 600; letter-spacing: 1.2px; text-transform: uppercase;
}
.acct-form .field > span em { font-style: normal; font-weight: 500; opacity: .7; text-transform: none; letter-spacing: .4px; }
.acct-form .field input {
  width: 100%; min-height: 28px; padding: 0; border: 0; background: none; color: var(--tx);
  font-size: 17px; font-weight: 700; letter-spacing: -.01em;  /* ≥16px: no iOS zoom */
}
.acct-form .field input:focus { outline: none; }
.acct-form .field input::placeholder { color: var(--faint); font-weight: 600; letter-spacing: 0; }
.acct-form .field:focus-within { border-color: var(--ac); box-shadow: 0 0 0 4px rgba(10, 10, 11, .10); }
.acct-form .field:focus-within > span { color: var(--ac); }
.acct-form .form-err { margin: 0; font-size: 12.5px; }
/* ── Signups closed ───────────────────────────────────────────────────
   config.js SIGNUPS_OPEN. By the time anyone reads this the onboarding is
   finished and the plan above it is real, so the CTA is REPLACED rather
   than ghosted: .btn-main:disabled is opacity .32, and the one sentence
   explaining why nothing happens must not be the faintest thing on screen.
   Sign in, directly below, is untouched — it creates no account. */
.acct-form .form-closed {
  margin: 5px 0 0; padding: 13px 15px;
  border: 1px solid var(--line2); border-radius: 16px;
  background: rgba(var(--ink-rgb), .05);
  color: var(--tx); font-size: 13px; line-height: 1.5; font-weight: 600;
}
/* Marketing opt-in. Deliberately NOT styled as a .field: it is not a value
   the form needs, and a box that matches the required inputs reads as one
   more thing to fill in. Quiet, unchecked, and it earns its ink only once
   it is chosen. */
/* ⚠️ NOT A CARD EITHER. Boxed like the inputs, an optional newsletter tick
   carried the same visual weight as the email address — and it is the one
   thing on this screen nobody has to read. No border, no fill: just the
   control and its sentence. */
.acct-form .optin {
  display: flex; gap: 11px; align-items: flex-start; cursor: pointer;
  padding: 2px 2px 0; border-radius: 14px;
  transition: opacity .16s;
}
.acct-form .optin:hover { opacity: .88; }
.acct-form .optin input { position: absolute; opacity: 0; width: 0; height: 0; }
.acct-form .optin-box {
  flex: 0 0 20px; width: 20px; height: 20px; margin-top: 1px; border-radius: 7px;
  border: 1.5px solid var(--line2); background: var(--raised);
  display: grid; place-items: center; transition: background .16s, border-color .16s;
}
.acct-form .optin-box svg { width: 12px; height: 12px; fill: none; stroke: var(--on-ac); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; opacity: 0; transition: opacity .12s; }
.acct-form .optin input:checked ~ .optin-box { background: var(--ac); border-color: var(--ac); }
.acct-form .optin input:checked ~ .optin-box svg { opacity: 1; }
.acct-form .optin input:focus-visible ~ .optin-box { box-shadow: 0 0 0 4px var(--ac-soft); }
.acct-form .optin:has(input:checked) { border-color: var(--line2); }
/* `.form label span` makes every span inside a form label a mono uppercase
   micro-label — right for the field captions it was written for, wrong here,
   where this is sentence copy someone has to read before consenting. It won on
   font-family, text-transform and letter-spacing, so those are reset
   explicitly rather than left to inherit. */
.acct-form .optin-text {
  display: grid; gap: 2px; min-width: 0;
  font-family: var(--display); text-transform: none; letter-spacing: normal;
}
.acct-form .optin-text b {
  font-family: var(--display); text-transform: none;
  font-size: 13.5px; font-weight: 700; color: var(--tx); letter-spacing: -.01em;
}
.acct-form .optin-text em {
  font-family: var(--display); text-transform: none; letter-spacing: normal;
  font-style: normal; font-size: 11.5px; line-height: 1.45; color: var(--faint); font-weight: 500;
}
.acct-form .btn-main { margin-top: 5px; min-height: 54px; }
/* The student offer, at two weights.
   On the ACCOUNT and PAYWALL screens it is a card, because there it is
   guidance about the price being charged. The dashed border went: a dashed
   rule reads as a coupon or a placeholder, and this is neither. The badge
   dropped 30px -> 22px so the mark identifies the offer instead of
   announcing it. */
/* ⚠️ A NOTE, NOT A CARD. This was a bordered box with a 22px avatar tile and
   a two-line stack — on the account step it sat between the email and the
   password taking roughly a fifth of the screen, for an offer that applies to
   one university. A border around something already inside a form is a second
   box drawn for no reason; the violet rule says "aside" in one stroke. */
.student-offer {
  display: block; margin: -2px 0 0; padding: 0 0 0 11px;
  border-left: 2px solid var(--ac-line);
  color: var(--dim); font-size: 11.5px; line-height: 1.45;
}
.student-offer[hidden] { display: none; }
/* The avatar tile is gone. The markup keeps it on the landing and paywall
   placements, so it is hidden rather than deleted from three files. */
.student-offer-icon { display: none; }
.student-offer b {
  display: inline; margin-right: 5px;
  color: var(--ac); font-size: 11.5px; font-weight: 800; letter-spacing: 0;
}
.student-offer em { display: inline; color: var(--dim); font-size: 11.5px; font-style: normal; font-weight: 500; }
/* The paywall's copy is longer and stands alone, so it keeps a little room. */
.student-offer-paywall { margin: 2px 0 12px; }

/* On the LANDING it is one line — see the note in start.html. */
.student-note {
  /* Top-aligned, not centred: on the two lines this wraps to, a centred
     badge floats between them and stops reading as a margin mark. */
  display: flex; align-items: flex-start; gap: 7px;
  width: min(100%, 440px); margin: 12px 0 0;
  color: var(--faint); font-size: 11.5px; line-height: 1.45; text-align: left;
}
.student-note[hidden] { display: none; }
.student-note-m {
  flex: none; display: grid; place-items: center; width: 16px; height: 16px;
  margin-top: 1px;
  border-radius: 5px; background: rgba(var(--ink-rgb), .10); color: var(--ac);
  font-family: var(--mono); font-size: 9px; font-weight: 700;
}
.acct-trust { display: flex; flex-wrap: wrap; justify-content: center; gap: 7px 16px; margin-top: 12px; }
.acct-trust span { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 700; color: var(--dim); }
.acct-trust svg { flex: none; width: 14px; height: 14px; fill: none; stroke: var(--ok); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.acct-foot { margin-top: 10px; color: var(--faint); font-size: 10.5px; line-height: 1.5; text-align: center; }
.acct-foot a { color: var(--dim); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }

.form { display: grid; gap: 14px; }
.form label { display: grid; gap: 7px; }
.form label span { color: var(--faint); font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: 1.2px; text-transform: uppercase; }
.form label span em { font-style: normal; font-weight: 500; opacity: .7; }
.form input {
  width: 100%; min-height: 54px; padding: 0 16px;
  border: 1px solid var(--line); border-radius: 14px; background: var(--raised); color: var(--tx);
  font-size: 16px; /* ≥16px keeps iOS Safari from auto-zooming on focus */
}
.form input:focus { outline: none; border-color: var(--ac); }
.form input::placeholder { color: var(--faint); }
.form .btn-main { margin-top: 4px; }
.tiny-legal { margin-top: 16px; color: var(--faint); font-size: 11px; line-height: 1.5; text-align: center; }
.tiny-legal a { color: var(--dim); font-weight: 600; }

/* ── Student verification holding screen ────────────────────────────── */
.sv-card {
  width: 100%; margin: 0 auto; padding: 24px 20px 20px;
  border: 1px dashed var(--line2); border-radius: 18px;
  background: rgba(var(--ink-rgb), .04); text-align: center;
}
.sv-status { display: grid; place-items: center; height: 56px; margin-bottom: 14px; }
.sv-status .sv-spin {
  width: 40px; height: 40px; border-radius: 50%;
  border: 3px solid var(--track); border-top-color: var(--ac);
  animation: sv-spin 900ms linear infinite;
}
.sv-status .sv-check {
  display: none; width: 44px; height: 44px; border-radius: 50%;
  background: var(--ac); place-items: center;
}
.sv-status .sv-check svg { width: 22px; height: 22px; fill: none; stroke: var(--on-ac); stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round; }
.sv-status[data-state="verified"] .sv-spin { display: none; }
.sv-status[data-state="verified"] .sv-check { display: grid; }
.sv-status[data-state="failed"] .sv-spin { display: none; }
.sv-status[data-state="failed"]::before {
  content: '!'; display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--track); color: var(--dim);
  font: 900 22px/1 var(--display);
}
@keyframes sv-spin { to { transform: rotate(360deg); } }
.sv-mail { margin: 0; color: var(--tx); font-size: 15px; font-weight: 800; overflow-wrap: break-word; }
.sv-note { margin: 8px 0 0; color: var(--faint); font-size: 12.5px; font-weight: 600; line-height: 1.45; }
.sv-prices {
  display: flex; align-items: baseline; justify-content: center; gap: 10px;
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
}
.sv-prices span { display: inline-flex; align-items: baseline; gap: 3px; }
.sv-prices b { color: var(--ac); font-size: 22px; font-weight: 900; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.sv-prices em { color: var(--faint); font-size: 12px; font-style: normal; font-weight: 700; }
.sv-prices .sv-or { color: var(--faint); font-size: 12px; font-weight: 700; }
#sv-continue { width: 100%; margin: 18px auto 0; }
#sv-continue[hidden] { display: none; }
.sv-actions { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-top: 18px; }
.sv-link {
  border: 0; background: none; padding: 4px 8px; cursor: pointer;
  color: var(--ac); font: 700 13.5px var(--display); text-decoration: underline;
  text-underline-offset: 3px;
}
.sv-link[disabled] { color: var(--faint); cursor: default; text-decoration: none; }
.sv-skip { color: var(--faint); font-weight: 650; }

/* ── Checkout ───────────────────────────────────────────────────────── */
.pw-your { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 16px; }
.pw-your:empty { display: none; }
.pw-your div { display: grid; gap: 3px; padding: 12px 6px; border: 1px solid var(--line); border-radius: 13px; background: var(--raised); text-align: center; }
.pw-your b { font-size: 13.5px; font-weight: 800; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.pw-your span { color: var(--faint); font-family: var(--mono); font-size: 8.5px; font-weight: 600; letter-spacing: .5px; text-transform: uppercase; }
/* The discounts that produced the price, ON the card that shows it. A banner
   above the plans said the same thing one screen-region away from the number
   it was talking about, which is exactly where a discount stops being
   believed. */
.plan-badges { grid-column: 2 / -1; display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.plan-badges[hidden] { display: none; }
.plan-badges i {
  font-style: normal; padding: 3px 7px; border-radius: 999px;
  background: var(--ac); color: var(--on-ac);
  font-family: var(--mono); font-size: 8.5px; font-weight: 700;
  letter-spacing: .4px; white-space: nowrap;
}
/* The second badge is the creator's — outlined rather than filled, so two
   pills side by side read as two different things. */
.plan-badges i.alt { background: none; color: var(--ac); box-shadow: inset 0 0 0 1px var(--line2); }

/* The same discounts as a sentence, once, above the prices they produced.
   Reads as a receipt rather than a promotion: the rows name the source, the
   right column carries the percentage, and the foot says the cards below
   already include it so nobody hunts for a code box to apply it with. */
.pw-savings {
  margin: 0 0 14px; padding: 13px 15px;
  border: 1px solid var(--ac-line); border-radius: 16px;
  background: color-mix(in srgb, var(--ac) 5%, var(--raised));
}
.pw-savings[hidden] { display: none; }
.pw-savings-h {
  margin: 0 0 9px; color: var(--ac);
  font-family: var(--mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: 1px; text-transform: uppercase;
}
.pw-savings-row { display: flex; align-items: baseline; gap: 12px; }
.pw-savings-row + .pw-savings-row { margin-top: 9px; }
.pw-savings-row > span { flex: 1; min-width: 0; }
.pw-savings-row b { display: block; font-size: 13px; font-weight: 700; color: var(--tx); }
.pw-savings-row em {
  display: block; margin-top: 2px; font-style: normal;
  font-size: 11.5px; line-height: 1.4; color: var(--faint);
}
.pw-savings-row i {
  flex: none; font-style: normal;
  font-family: var(--mono); font-size: 13px; font-weight: 700;
  font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--ac);
}
.pw-savings-foot {
  margin: 11px 0 0; padding-top: 9px; border-top: 1px solid var(--ac-line);
  font-size: 11.5px; line-height: 1.4; color: var(--dim);
}

/* "Have a creator code?" — quiet until it is wanted. */
.pw-code { margin-top: 12px; text-align: center; }
.pw-code[hidden] { display: none; }
.pw-code-open {
  background: none; border: 0; padding: 4px;
  color: var(--faint); font-size: 12px; font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px;
}
.pw-code-row { display: flex; gap: 7px; margin-top: 6px; }
.pw-code-row[hidden] { display: none; }
.pw-code-row input {
  flex: 1; min-width: 0; height: 42px; padding: 0 13px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--raised);
  font-family: var(--mono); font-size: 13px; font-weight: 700;
  letter-spacing: 1px; text-transform: uppercase; color: var(--tx);
}
.pw-code-row input:focus-visible { outline: none; border-color: var(--ac); }
.pw-code-row button {
  flex: none; height: 42px; padding: 0 16px; border-radius: 12px;
  border: 0; background: var(--ac); color: var(--on-ac);
  font-size: 13px; font-weight: 700;
}
.pw-code-say { margin-top: 6px; font-size: 11.5px; line-height: 1.35; color: var(--faint); }
.pw-code-say:empty { display: none; }
.pw-code-say.ok { color: var(--tx); font-weight: 600; }

/* What Pro is, said once above both cards. */
.pw-perks { list-style: none; display: grid; gap: 7px; margin: 0 2px 16px; }
.pw-perks li { display: flex; align-items: flex-start; gap: 9px; font-size: 13px; line-height: 1.35; color: var(--dim); }
.pw-perks svg, .free-confirm-card ul svg {
  flex: none; width: 15px; height: 15px; margin-top: 1px;
  fill: none; stroke: var(--ac); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
}
.plan-stack { display: grid; gap: 9px; }
/* GRID, not flex-wrap: radio | name | price, with the meta line spanning
   underneath. A price is as wide as its currency makes it (TRY 1,599.99/yr
   is nearly double $69.99/yr), so the name column has to be the one that
   flexes and the price must never be asked to share a line with a
   description. */
.plan-card {
  position: relative; display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center; column-gap: 12px; row-gap: 3px;
  width: 100%; padding: 15px; text-align: left;
  border: 1px solid var(--line); border-radius: 16px; background: var(--raised);
  transition: transform .16s cubic-bezier(.3, 1.4, .5, 1), border-color .2s, background .2s;
}
.plan-card:active { transform: scale(.985); }
.plan-card.sel {
  border-color: var(--ac);
  background: linear-gradient(180deg, rgba(var(--ink-rgb), .08), rgba(var(--ink-rgb), .035));
}
/* The flag is SEATED IN the corner, not hung off it. Half a sticker floating
   above the border read as a mistake; a tab flush with two edges reads as
   part of the card. The annual card pays for it with its own top padding. */
.plan-card:has(.plan-flag) { padding-top: 30px; }
.plan-flag {
  position: absolute; top: 0; left: 0;
  padding: 4px 10px 4px 15px; border-radius: 15px 0 12px 0;
  background: var(--ac); color: var(--on-ac);
  font-family: var(--mono); font-size: 8px; font-weight: 700; letter-spacing: .9px; text-transform: uppercase;
}
.radio { grid-row: 1 / span 2; align-self: center; width: 19px; height: 19px; border-radius: 50%; border: 1.5px solid var(--line2); position: relative; transition: border-color .2s; }
.plan-card.sel .radio { border-color: var(--ac); }
.plan-card.sel .radio::after { content: ''; position: absolute; inset: 4px; border-radius: 50%; background: var(--ac); }
.pc { grid-column: 2; min-width: 0; }
.pc b { font-size: 15.5px; font-weight: 800; letter-spacing: -.02em; }
.pp { grid-column: 3; text-align: right; }
.pp b { font-size: 15.5px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; white-space: nowrap; display: block; }
/* The reference price. Ink strike, never red — and quiet, because the number
   that matters is the one underneath it. */
.pp s {
  display: block; margin-bottom: 1px;
  color: var(--faint); font-size: 11.5px; font-weight: 600;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  text-decoration-color: var(--line2); text-decoration-thickness: 1.5px;
}
/* Not mono: half these lines are a sentence ("Full Pro, billed monthly"),
   and mono makes prose look like a receipt. Tabular figures keep the price
   fragment aligned without it. */
.plan-note {
  grid-column: 2 / -1; font-style: normal;
  color: var(--faint); font-size: 11.5px; font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.plan-card.sel .plan-note { color: var(--dim); }
.plan-note:empty { display: none; }
/* The three questions a hesitating buyer actually has. */
/* Tight enough that the Turkish strings ("İstediğin an iptal") still make
   one line — three items on two rows reads as a list that ran out of room. */
.pw-trust { list-style: none; display: flex; justify-content: center; flex-wrap: wrap; gap: 6px 12px; margin: 14px 0 2px; }
.pw-trust li { display: flex; align-items: center; gap: 5px; color: var(--faint); font-size: 11px; font-weight: 600; white-space: nowrap; }
.pw-trust svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.paywall-error { margin: 10px 2px 0; text-align: center; }
.paywall-error:empty { display: none; }

/* Free-plan confirm modal.
   A BODY CHILD (see start.html) so no ancestor stacking context can trap it,
   and z-index above the sticky header rather than below it. Centring is
   `margin: auto` on the card inside a column flex — justify-content: center
   clips the top of anything taller than the viewport, margin:auto scrolls. */
.free-confirm {
  position: fixed; inset: 0; z-index: 200;
  height: 100vh; height: 100dvh;
  display: flex; flex-direction: column;
  padding: 20px; overflow-y: auto; overscroll-behavior: contain;
  background: rgba(var(--ink-rgb), .38);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.free-confirm[hidden] { display: none; }
.free-confirm-card {
  position: relative; flex: 0 0 auto; margin: auto; width: min(400px, 100%);
  padding: 26px 22px 20px; border-radius: 24px;
  background: var(--raised); border: 1px solid var(--line2);
  box-shadow: 0 24px 70px rgba(10, 10, 11, .22);
  animation: stepIn .3s cubic-bezier(.25, .8, .3, 1) both;
}
/* Two stages in one dialog: what leaving costs, then the offer. A second
   modal would have meant a second close button, a second scrim and a second
   thing to keep in step. */
.free-confirm[data-stage="warn"] .fc-offer { display: none; }
.free-confirm:not([data-stage="warn"]) .fc-warn { display: none; }
.fc-warn .btn-main { margin-top: 18px; }
.free-confirm-card h2 { margin-top: 6px; font-size: 23px; line-height: 1.1; letter-spacing: -.03em; font-weight: 800; }
.free-confirm-card h2 + p, .free-confirm-card > p { margin-top: 8px; color: var(--dim); font-size: 13.5px; line-height: 1.45; }
.free-confirm-card ul { list-style: none; margin: 14px 0 18px; padding: 0; display: grid; gap: 8px; }
.free-confirm-card ul li { display: flex; align-items: flex-start; gap: 9px; color: var(--dim); font-size: 13px; line-height: 1.35; }
.free-confirm-close { position: absolute; top: 12px; right: 14px; width: 34px; height: 34px; border-radius: 50%; font-size: 20px; color: var(--dim); display: grid; place-items: center; background: var(--track); }
.free-offer-eyebrow { display: block; padding-right: 38px; color: var(--faint); font-family: var(--mono); font-size: 9px; font-weight: 600; letter-spacing: 1.4px; }
/* Two INDEPENDENT rows: price + what it saves, then the per-month equivalent
   and the old price. Deliberately not one grid — shared columns let the long
   "Usually TRY 1,599.99" underneath size the column above it and squeeze the
   headline price into a mid-string wrap ("TRY / 1,299.99/yr"). Separate flex
   rows can only ever push themselves. */
.free-offer-price {
  display: grid; gap: 5px;
  margin-top: 16px; padding: 14px 15px; border: 1px solid var(--line2);
  border-radius: 16px; background: linear-gradient(135deg, rgba(var(--ink-rgb), .09), rgba(var(--ink-rgb), .04));
  font-variant-numeric: tabular-nums;
}
.fop-row { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 4px 10px; }
/* The price never breaks mid-string; if space runs out the CHIP wraps. */
.free-offer-price b { font-size: 21px; line-height: 1.15; letter-spacing: -.03em; white-space: nowrap; }
.fop-save {
  flex: none; padding: 3px 8px; border-radius: 999px;
  background: var(--ac); color: var(--on-ac);
  font-family: var(--mono); font-size: 8.5px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase;
}
.fop-save[hidden] { display: none; }
.free-offer-price small { color: var(--dim); font-size: 11.5px; font-weight: 600; }
/* Ink, not red. A red strike on a price reads as an error state, and it was
   the only hue on an otherwise monochrome screen. */
.free-offer-price em { color: var(--faint); font-size: 11.5px; font-style: normal; font-weight: 600; white-space: nowrap; }
.free-offer-price s { text-decoration-color: var(--line2); text-decoration-thickness: 1.5px; }
.free-confirm-card .btn-main { width: 100%; }
.free-offer-trust { display: block; margin-top: 9px; color: var(--faint); font-size: 10.5px; line-height: 1.35; text-align: center; }
body.has-modal { overflow: hidden; }

/* ── Download ───────────────────────────────────────────────────────── */
.dl-box { padding: 7vh 0 0; text-align: center; }
.dl-box .pet { display: flex; width: 140px; margin: 0 auto 22px; }
.dl-pet { --hp-size: 140px; display: block; animation: petIn .6s cubic-bezier(.2, 1.4, .3, 1) both, petCelebrate 3.6s ease-in-out .6s infinite; }
@keyframes petIn { from { opacity: 0; transform: scale(.7) translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes petCelebrate {
  0%, 100% { transform: translateY(0) rotate(-3deg); }
  25% { transform: translateY(-7px) rotate(2deg); }
  50% { transform: translateY(-10px) rotate(3deg); }
  75% { transform: translateY(-5px) rotate(-1deg); }
}
.dl-box .sub { max-width: 340px; margin: 10px auto 0; }
.dl-box .btn-main { max-width: 340px; margin: 28px auto 0; }
.dl-box .hint { font-family: var(--mono); font-size: 11px; letter-spacing: .3px; }

/* ── Reduced motion ─────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .step.on > :not(.cta-row), .step.on > .cta-row, .free-confirm-card, .dl-pet, .acct-pet,
  .pet, .pet::before, .pet::after, .pet .spark { animation: none; }
  .pet::before { opacity: .8; }
  .pet .spark { opacity: .7; }
  .draw-line { animation: none; stroke-dashoffset: 0; }
  .spin { animation-duration: 2.4s; }
  .sv-status .sv-spin { animation: none; }
  body.onboarding::before { transition: none; }
  .fun-progress span, .t-macro .bar span { transition: none; }
  .hk-live i, .hk-done, .hook-scan .twin.after, .hook-scan .scan-line, .hook-scan .caliper,
  .hook-scan .cal-bar, .hook-scan .sd, .hook-meal .mc-corner, .hook-meal .mc-plate, .hook-meal .mc-scan,
  .hook-meal .mc-flash, .hook-meal .meal-row, .hook-meal .meal-row u, .hook-program .hp-day.fill,
  .hook-program .hp-ex, .hook-program .hp-prog u b, .hook-price .hp-row, .hook-price .hp-total,
  .hook-price .hp-row b::after, .hook-price .hp-sum b::after { animation: none !important; }
  .hk-done, .hook-scan .caliper, .hook-scan .sd, .hook-meal .mc-corner, .hook-meal .meal-row,
  .hook-program .hp-ex, .hook-price .hp-row, .hook-price .hp-total { opacity: 1; transform: none; }
  .hook-scan .twin.after { clip-path: inset(0 0 0 0); }
  .hook-scan .cal-bar { width: 40px; }
  .hook-scan .scan-line, .hook-meal .mc-scan, .hook-meal .mc-flash { opacity: 0; }
  .hook-meal .meal-row u, .hook-program .hp-prog u b { transform: none; }
  .hook-price .hp-row b::after, .hook-price .hp-sum b::after { transform: scaleX(1); }
}

/* ── Desktop ────────────────────────────────────────────────────────── */
@media (min-width: 760px) {
  .fun { padding-top: 34px; }
  .q-head { padding-top: 26px; }
  .hero { padding-top: 10vh; }
  .choice:hover, .plan-card:hover { border-color: var(--line2); }
  .choice.sel:hover, .plan-card.sel:hover { border-color: var(--ac); }
  .btn-main:hover { background: var(--ac2); }
}

/* ── Short-viewport compaction ──────────────────────────────────────────
   An onboarding step must NEVER scroll: the Continue button has to be
   reachable without a gesture nobody thinks to make. Keyed on WIDTH first
   (the step shell is a fixed slice of the viewport), then height. */
@media (max-width: 560px) {
  .q-head { padding: 12px 0 15px; }
  .sub { margin-top: 7px; font-size: 13px; line-height: 1.45; }
  .choices { gap: 7px; }
  .choice.pill { min-height: 46px; }
  .seg-block { gap: 12px; padding: 2px 0; }
  .seg-row { gap: 7px; }
  .mini { gap: 6px; }
  .mini button { min-height: 36px; padding: 0 13px; font-size: 12.5px; }
  .hint { margin-top: 9px; font-size: 12px; }
  .weekday-picker { padding: 6px 0 2px; gap: 6px; }
  .weekday-picker button { min-height: 52px; padding: 6px 3px; }
  .weekday-picker button span { font-size: 15px; }
  .cta-row { padding: 14px 20px calc(10px + env(safe-area-inset-bottom)); }
  .cta-note { margin-top: 6px; }
  .fun { padding: 14px 20px 104px; }
  /* Steps that auto-advance carry no CTA, so they need no reserve either. */
  .fun:not(:has(> .step.on .cta-row)) { padding-bottom: 22px; }
}
@media (max-width: 560px) and (max-height: 720px) {
  .q-head { padding: 8px 0 10px; }
  .choices { gap: 6px; }
  .seg-block { gap: 9px; }
  .mini button { min-height: 30px; padding: 0 11px; font-size: 12px; }
  .seg-row > span { font-size: 9px; }
  .hint { margin-top: 5px; font-size: 11.5px; }
}

/* Checkout survives the pass above — it stacks a headline, two plan
   cards, two buttons and the legal paragraph. It gets its own budget;
   prices and plan names keep their size, only air gives ground. */
/* THE BUDGET IS "BOTH CARDS, NO SCROLL". A phone in Safari gives the page
   ~620px, and the fixed CTA takes 130 of them. Fitting the whole step into
   what is left would mean shrinking the value list into nothing, so the
   target is narrower and honest: the headline, the plan tiles, the perks and
   BOTH PRICE CARDS clear the button. The trust row and the legal paragraph
   are allowed to sit below the fold — they are read after a decision, not
   before one. What broke was the monthly card being sliced in half by the
   button, which reads as a bug rather than as "there is more below". */
@media (max-width: 560px) and (max-height: 780px) {
  .fun:has(> .step[data-step="checkout"].on) { padding-bottom: 150px; }
  .step[data-step="checkout"] .q-head { padding: 2px 0 8px; }
  .step[data-step="checkout"] .q-head h1 { font-size: 23px; }
  .step[data-step="checkout"] .sub { margin-top: 4px; font-size: 12.5px; line-height: 1.35; }
  .pw-your { gap: 6px; margin-bottom: 10px; }
  .pw-your div { padding: 8px 5px; border-radius: 11px; }
  .pw-your b { font-size: 12.5px; }
  .pw-web-offer { margin-bottom: 6px; gap: 5px 7px; }
  .pw-web-offer p { font-size: 11px; }
  .pwo-badge { padding: 2px 6px; font-size: 8.5px; }
  .pw-perks { gap: 4px; margin-bottom: 11px; }
  .pw-perks li { font-size: 12px; line-height: 1.28; }
  .pw-perks svg { width: 14px; height: 14px; stroke-width: 2.8; }
  .plan-stack { gap: 7px; }
  .pw-savings { margin-bottom: 11px; padding: 11px 13px; }
  .pw-savings-row b { font-size: 12.5px; }
  .plan-card { padding: 11px 13px; row-gap: 2px; }
  .plan-card:has(.plan-flag) { padding-top: 25px; }
  .pc b, .pp b { font-size: 14.5px; }
  .pp s { font-size: 10.5px; }
  .plan-note { font-size: 10.5px; }
  .pw-trust { margin-top: 10px; gap: 5px 10px; }
  .cta-row.stacked .btn-quiet { margin-top: 2px; }
  /* Sized against the LIVE Turkish string (the longest), not the shorter
     English fallback. Legible, present, smaller. */
  .tiny-legal { margin-top: 6px; font-size: 10px; line-height: 1.3; }
}

/* A phone with both Safari toolbars showing. The fifth perk goes — it is the
   weakest of the five and the only one that is a cap rather than a feature —
   and the rest gives up another few pixels each, which is what buys the
   monthly card its full height. */
@media (max-width: 560px) and (max-height: 700px) {
  .step[data-step="checkout"] .q-head { padding: 0 0 6px; }
  .step[data-step="checkout"] .q-head h1 { font-size: 22px; }
  .step[data-step="checkout"] .sub { font-size: 12px; line-height: 1.3; }
  .pw-your { margin-bottom: 8px; }
  .pw-your div { padding: 6px 5px; }
  .pw-your b { font-size: 12px; }
  .pw-perks { gap: 3px; margin-bottom: 6px; }
  .pw-perks li:nth-child(5) { display: none; }
  /* The offer line costs one row rather than a card, so only the fourth perk
     yields to it — the plan tiles keep their place. */
  .step[data-step="checkout"]:has(#pw-web-offer:not([hidden])) .pw-perks li:nth-child(4) { display: none; }
  .plan-card { padding: 10px 13px; row-gap: 1px; }
  .plan-card:has(.plan-flag) { padding-top: 24px; }
}

/* account / save-plan step — shrink harder as the screen shortens */
@media (max-height: 780px) {
  [data-step="account"] .acct-hero .pet,
  [data-step="account"] .acct-pet { width: 48px; height: 48px; }
  [data-step="account"] .acct-head h1 { font-size: clamp(19px, 5.2vw, 22px); }
  [data-step="account"] .acct-head p { font-size: 11.5px; }
  [data-step="account"] .plan-recap { margin: 11px 0 11px; }
  [data-step="account"] .plan-recap div { padding: 8px 3px 7px; }
  [data-step="account"] .acct-form { gap: 7px; }
  [data-step="account"] .acct-form .field { padding: 6px 13px 7px; border-radius: 13px; }
  [data-step="account"] .acct-form .field input { min-height: 24px; font-size: 16px; }
  [data-step="account"] .acct-form .btn-main { min-height: 50px; }
  [data-step="account"] .acct-trust { margin-top: 9px; }
  [data-step="account"] .acct-trust span { font-size: 11px; }
  [data-step="account"] .acct-foot { margin-top: 8px; font-size: 10px; }
}
@media (max-height: 640px) {
  [data-step="account"] .acct-head p { display: none; }
  [data-step="account"] .plan-recap { display: none; }
  [data-step="account"] .acct-trust span + span { display: none; }
}

/* program-ready step — compact by default; short screens shed the
   nice-to-have receipts before the actual program compresses. */
[data-step="program_preview"] .q-head h1 { font-size: clamp(22px, 5.6vw, 27px); }
[data-step="program_preview"] .ai-proof { padding: 7px 12px; margin-bottom: 8px; }
[data-step="program_preview"] .ai-proof b { font-size: 12px; }
[data-step="program_preview"] .day-tabs { margin-bottom: 8px; padding-bottom: 2px; }
[data-step="program_preview"] .day-tabs button { padding: 6px 11px; }
[data-step="program_preview"] .program-day-head { padding: 9px 14px; }
[data-step="program_preview"] .program-exercise { padding: 7px 14px; }
[data-step="program_preview"] .exercise-copy b { font-size: 13px; }
[data-step="program_preview"] .exercise-copy span { font-size: 11.5px; }
[data-step="program_preview"] .program-cardio { padding: 7px 14px; }
[data-step="program_preview"] .program-support { margin-top: 8px; }
[data-step="program_preview"] .program-support-label { margin-bottom: 6px; }
[data-step="program_preview"] .program-support i { padding: 7px 11px; }
[data-step="program_preview"] .program-more { margin-top: 8px; padding: 9px 14px; }
[data-step="program_preview"] .saved-chip { margin-top: 8px; padding: 9px 14px; }
@media (max-height: 850px) {
  [data-step="program_preview"] .ai-proof b { display: none; }
  [data-step="program_preview"] .program-more { display: none; }
  [data-step="program_preview"] .saved-chip small { display: none; }
  [data-step="program_preview"] .saved-chip svg { grid-row: auto; }
}
@media (max-height: 790px) {
  [data-step="program_preview"] .program-support { display: none; }
}
@media (max-height: 720px) {
  [data-step="program_preview"] .program-exercise { padding: 5px 14px; }
  [data-step="program_preview"] .exercise-copy { gap: 0; }
}
@media (max-height: 640px) {
  [data-step="program_preview"] .ai-proof { display: none; }
  [data-step="program_preview"] .saved-chip { display: none; }
}

/* steps + sleep instruments on short screens */
@media (max-width: 560px) and (max-height: 720px) {
  .sd-rail { height: 38px; }
  #sd-out { font-size: 25px; }
  .sd-legend { display: none; }
  .night-card { margin-bottom: 12px; }
  .night-rail { height: 48px; }
  .note-receipt { margin-top: 10px; padding: 9px 12px; }
}
/* Movement asks three things on one screen, and a phone in Safari has ~620px
   of page — two toolbars shorter than the viewport a desktop preview shows.
   Everything here buys back that difference WITHOUT dropping a label: the
   four descriptions are what let somebody classify themselves honestly, and
   the caption keeps the air under it. The eyebrow is the one safe cut — the
   sticky header rail directly above already reads "YOUR WEEK". */
@media (max-width: 560px) and (max-height: 780px) {
  [data-step="movement"] .eyebrow { display: none; }
  [data-step="movement"] .q-head { padding: 2px 0 8px; }
  [data-step="movement"] .q-head h1 { font-size: 24px; }
  [data-step="movement"] .sub { margin-top: 5px; font-size: 12.5px; }
  [data-step="movement"] .choices { gap: 5px; }
  [data-step="movement"] .choice { min-height: 42px; padding: 6px 38px 6px 11px; }
  [data-step="movement"] .choice .ic { width: 27px; height: 27px; border-radius: 8px; }
  [data-step="movement"] .choice .ic svg { width: 15px; height: 15px; }
  [data-step="movement"] .cc { gap: 0; }
  [data-step="movement"] .cc b { font-size: 13px; }
  [data-step="movement"] .cc small { font-size: 10px; line-height: 1.3; }
  [data-step="movement"] .choice::after { right: 11px; width: 17px; height: 17px; margin-top: -9px; }
  [data-step="movement"] .q-cap { margin: 10px 0 7px; }
  [data-step="movement"] .mini button { min-height: 34px; }
  [data-step="movement"] .step-dial { gap: 5px; margin-top: 2px; }
  [data-step="movement"] .note-receipt { margin-top: 8px; padding: 8px 11px; }
}
/* Shorter still (a phone with the tab bar showing): the receipt goes. It is
   the one element the rail already says on its own — the goal knob sitting
   inside the striped band IS "about where you already walk". */
@media (max-width: 560px) and (max-height: 660px) {
  [data-step="movement"] .note-receipt { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   LITERAL SURFACES
   Tokens carry everything var()-based; these are the surfaces that need a
   real colour rather than a token — accent tints at a chosen alpha, the
   glows, and the few shadows that are grey rather than violet.
   ══════════════════════════════════════════════════════════════════════ */
body.onboarding::before {
  background: radial-gradient(circle, rgba(var(--ink-rgb), .10), transparent 62%);
}
body.onboarding::after { opacity: .02; }
.hero-mark { box-shadow: 0 14px 34px -12px rgba(10, 10, 11, .45); }
.choice.sel,
.plan-card.sel {
  background: linear-gradient(180deg, rgba(var(--ink-rgb), .07), rgba(var(--ink-rgb), .02));
}
.choice.sel .ic { background: rgba(var(--ink-rgb), .10); }
.mini button.sel,
.weekday-picker button.sel {
  background: linear-gradient(180deg, rgba(var(--ink-rgb), .10), rgba(var(--ink-rgb), .04));
}
/* ⚠️ THESE ENDED IN LITERAL #0A0A0B — a black fill and a black knob, which on
   the night ground is a slider that fades into nothing at exactly the end you
   are dragging towards. The accent is the state colour; this is state. */
.sd-fill { background: linear-gradient(90deg, rgba(var(--ink-rgb), .30), var(--ac)); }
.sd-knob { border-color: var(--ac); box-shadow: var(--shadow-1); }
.sd-knob::after { background: var(--ac); }
.ruler-track i { background: linear-gradient(90deg, rgba(var(--ink-rgb), .22) 0 1.5px, transparent 1.5px); }
.ruler-track i.mid { background: linear-gradient(90deg, rgba(var(--ink-rgb), .40) 0 1.5px, transparent 1.5px); }
.ruler-track i.maj { background: linear-gradient(90deg, rgba(var(--ink-rgb), .70) 0 1.5px, transparent 1.5px); }
.night-window {
  background: linear-gradient(135deg, rgba(var(--ink-rgb), .13), rgba(var(--ink-rgb), .05));
  box-shadow: 0 0 22px rgba(10, 10, 11, .14);
}
.night-window .nw-grip {
  background: linear-gradient(90deg, rgba(var(--ink-rgb), .45) 0 2.5px, transparent 2.5px 6.5px, rgba(var(--ink-rgb), .45) 6.5px 9px);
}
.p2-band:active .p2-knob { box-shadow: 0 2px 10px rgba(10, 10, 11, .32), 0 0 0 7px rgba(10, 10, 11, .24); }
.program-day-head { background: rgba(var(--ink-rgb), .04); }
.program-cardio { background: rgba(var(--ink-rgb), .03); }
/* ⚠️ .student-offer DROPPED OUT OF THIS RULE. It sat 550 lines below the
   component and quietly put the card fill back, so removing the border up
   there left a floating grey panel with no edge — worse than the card it
   replaced. The note is a rule and text now, nothing else. */
.sv-card { background: rgba(var(--ink-rgb), .04); }
.free-offer-price { background: linear-gradient(135deg, rgba(var(--ink-rgb), .08), rgba(var(--ink-rgb), .03)); }
/* ⚠️ THE STAGES WERE LIT FOR A WHITE PAGE. `.hk-stage` is defined dark 1,700
   lines above; this block overrode it to near-white back when the funnel was
   light-only, and the comment here used to argue the camera stages should
   "stay lit". On the night ground that is a white slab dropped into the
   middle of the screen — and worse, the glass chips INSIDE it are
   white-on-white, so "2 photos" and the weight readout were invisible.

   A viewfinder is dark. Both stages are studios now, lit from above by the
   accent rather than by a grey wash. */
.hk-stage {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--ac) 7%, var(--track)),
    var(--track));
}
.hook-scan .scan-stage {
  background: radial-gradient(120% 90% at 50% -10%,
    color-mix(in srgb, var(--ac) 16%, var(--track)) 0%,
    color-mix(in srgb, var(--ac) 6%, var(--track)) 45%,
    var(--track) 100%);
}
/* The glass chips floating on those stages: they were white glass for a white
   stage. Now they are the card surface, which reads on either theme. */
.hook-scan .scan-cap,
.hook-scan .scan-scale {
  background: color-mix(in srgb, var(--raised) 88%, transparent);
  color: var(--tx);
}
.hook-scan .scan-scale b { color: var(--tx); }
.hook-scan .scan-scale span { color: var(--faint); }
.hook-program .hp-day.fill {
  background: linear-gradient(180deg, rgba(var(--ink-rgb), .12), rgba(var(--ink-rgb), .04));
  box-shadow: 0 3px 12px rgba(10, 10, 11, .18);
}
.hk-pill { background: rgba(var(--ink-rgb), .09); }
.hook-price .hp-total { background: rgba(var(--ink-rgb), .07); }

/* ══ Hook · COACH ═══════════════════════════════════════════════════════
   One exchange, not a thread. A wall of chat is a screenshot; a question, a
   pause and an answer is a demonstration. */
.hook-coach .hc-thread { display: grid; gap: 10px; }
.hook-coach .hc-ask {
  justify-self: end; max-width: 78%; margin: 0;
  padding: 9px 14px; border-radius: 16px 16px 4px 16px;
  background: var(--ac); color: var(--on-ac);
  font-size: 13px; font-weight: 700; line-height: 1.35;
  opacity: 0; animation: hkRise .4s ease .1s both;
}
.hook-coach .hc-reply { display: flex; align-items: flex-start; gap: 9px; }
.hook-coach .hc-face { --hp-size: 30px; flex: none; display: block; margin-top: 2px; }
.hook-coach .hc-bubble {
  position: relative; flex: 1; min-width: 0;
  padding: 10px 13px 11px; border-radius: 16px 16px 16px 4px;
  border: 1px solid var(--line); background: var(--raised);
  opacity: 0; animation: hkRise .4s ease .55s both;
}
/* The dots run, then hand over to the sentence — the answer is not instant
   and pretending it is would be the one dishonest frame in the demo. */
.hook-coach .hc-typing { display: flex; gap: 4px; padding: 3px 0 1px; animation: hkFadeOut .25s ease 1.45s both; }
.hook-coach .hc-typing i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--faint);
  animation: hkDot 1.1s ease-in-out infinite;
}
.hook-coach .hc-typing i:nth-child(2) { animation-delay: .14s; }
.hook-coach .hc-typing i:nth-child(3) { animation-delay: .28s; }
.hook-coach .hc-said {
  margin: 0; font-size: 13px; line-height: 1.45; color: var(--tx); font-weight: 600;
  height: 0; overflow: hidden; opacity: 0;
  animation: hkSaid .01s linear 1.6s forwards, hkRise .45s ease 1.6s both;
}
.hook-coach .hc-why {
  display: none; margin-top: 7px; padding-top: 7px; border-top: 1px solid var(--line);
  color: var(--faint); font-family: var(--mono); font-size: 9px; letter-spacing: .5px;
  animation: hkRise .4s ease 1.95s both;
}
@keyframes hkSaid { to { height: auto; opacity: 1; } }
@keyframes hkFadeOut { to { opacity: 0; height: 0; padding: 0; } }
@keyframes hkDot { 0%, 100% { opacity: .35; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-3px); } }
.hook-coach .hc-said { animation-fill-mode: forwards, both; }
.hook-coach .hc-bubble .hc-said:not(:empty) { }
/* The provenance line only appears once there is an answer to explain. */
.hook-coach .hc-why { display: block; opacity: 0; animation: hkRise .4s ease 2s both; }

/* ══ Hook · RECOVERY ════════════════════════════════════════════════════
   One number, three signals, a verdict. The dial draws itself so the value
   arrives rather than being asserted. */
.hook-recovery .hr-read { display: flex; align-items: center; gap: 14px; }
/* THE ORB, NOT A RING. The dial used to be an SVG track-and-arc — a
   progress ring, which is the one shape Heala's recovery score deliberately
   is not. orb.js draws the app's aurora cell into .t-orb; the score and unit
   sit on top of it exactly as they do in the app. */
.hook-recovery .hr-dial { position: relative; flex: none; width: 104px; height: 122px; }
.hook-recovery .hr-dial .t-orb { position: absolute; inset: 0 0 auto 0; height: 104px; display: block; }
.hook-recovery .hr-dial .t-orb svg { width: 100%; height: 100%; display: block; }
/* The orb carries the fill; the numeral rides it. `position: relative` is
   what keeps it above the absolutely-positioned cell without a z-index war. */
.hook-recovery .hr-num {
  position: absolute; inset: 0 0 18px 0; display: grid; place-items: center;
  font-family: var(--display); font-size: 30px; font-weight: 900;
  line-height: 1; letter-spacing: -.03em;
  /* Dark funnel: the traced orb is vividised for a light surface, so its
     submerged-numeral ink would sit almost black on this ground. The app
     switches to white past a 0.30 fill for exactly this reason
     (RecoveryOrb.tsx:155) and 86 is well past it. */
  color: #06210F;
  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
/* UNDER the cell, not inside it. The app puts the word in the card's own
   eyebrow and leaves the orb carrying only the number; this card's eyebrow is
   the timestamp, so the unit still has to appear — just not squeezed onto the
   orb's bottom lobe, where it was both cramped and low-contrast. */
.hook-recovery .hr-dial em {
  position: absolute; left: 0; right: 0; bottom: 0; text-align: center;
  font-style: normal; font-family: var(--mono); font-size: 8px;
  letter-spacing: 1px; color: var(--faint);
}
.hook-recovery .hr-say { min-width: 0; }
.hook-recovery .hr-say b { display: block; font-size: 16px; font-weight: 800; letter-spacing: -.02em; }
.hook-recovery .hr-say span { display: block; margin-top: 3px; color: var(--dim); font-size: 12px; line-height: 1.4; }
.hook-recovery .hr-sig { margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--line); display: grid; gap: 7px; }
.hook-recovery .hr-row { display: flex; align-items: center; gap: 10px; font-size: 12px; }
.hook-recovery .hr-row > span { width: 92px; color: var(--dim); font-weight: 600; }
.hook-recovery .hr-row i { flex: 1; height: 6px; border-radius: 3px; background: rgba(var(--ink-rgb), .12); overflow: hidden; }
.hook-recovery .hr-row u {
  display: block; height: 100%; border-radius: 3px; background: var(--ac);
  transform-origin: left; transform: scaleX(0);
  animation: hkBarX .8s cubic-bezier(.3, .8, .3, 1) both;
}
.hook-recovery .hr-row:nth-child(1) u { animation-delay: .5s; }
.hook-recovery .hr-row:nth-child(2) u { animation-delay: .62s; }
.hook-recovery .hr-row:nth-child(3) u { animation-delay: .74s; }
.hook-recovery .hr-row b { width: 52px; text-align: right; font-weight: 800; }

/* ── The meet screen ─────────────────────────────────────────────────────
   Heala and "how should I talk to you?" on one screen, because that question
   is about the creature in front of you, not a setting on a page of its own.
   Portrait stacks her over the copy; wide puts her beside it. */
.ob-meet {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: 2px; flex: 1; min-height: 0;
}
.ob-meet .pet { width: min(52vw, 186px); height: min(52vw, 186px); flex: none; }
.ob-meet .ob-meet-copy { display: flex; flex-direction: column; align-items: center; }
.ob-meet .q-cap { margin-top: 18px; }
@media (min-width: 720px) {
  .ob-meet { display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: 34px; text-align: left; }
  .ob-meet .pet { width: 230px; height: 230px; justify-self: center; }
  .ob-meet .ob-meet-copy { align-items: flex-start; }
  .ob-meet .pet-say { font-size: 30px; }
  .ob-meet .pet-sub { margin-left: 0; }
}
.ob-tone { display: flex; flex-wrap: wrap; gap: 7px; justify-content: center; margin-top: 14px; }
.ob-meet .ob-meet-copy .ob-tone { justify-content: inherit; }
.ob-tone button {
  padding: 9px 13px; border-radius: 11px; border: 1px solid var(--line); background: var(--raised);
  font-family: inherit; font-size: 12.5px; font-weight: 700; color: var(--dim); cursor: pointer;
  transition: border-color .18s, background .18s, color .18s;
}
.ob-tone button.sel { border-color: var(--ac); background: var(--ac-soft); color: var(--ac); }

/* Physiology is two options, so it reads as a pair rather than a list. */
.choices.two-up { grid-template-columns: 1fr 1fr; }
/* A two-up pill carries a label and nothing else, so the 46px reserved for
   the tick on a full-width choice is dead space it cannot afford. */
.choices.two-up .choice { padding-right: 40px; }
.choices.two-up .cc b { font-size: 13.5px; }

/* ── The five systems (app screen) ──────────────────────────────────────
   Structurally a choice list, but every row is independent: this is the one
   group where several ticks are lit at once. Nothing is restyled — the tick
   the choice already draws is exactly the right affordance for a toggle —
   except the rows tighten, because five of them share one viewport with a
   heading and a receipt. */
.choices.systems { gap: 7px; }
.choices.systems .choice { min-height: 46px; padding-top: 9px; padding-bottom: 9px; }
.choices.systems .ic { width: 32px; height: 32px; border-radius: 10px; }
.choices.systems .ic svg { width: 16px; height: 16px; }
.choices.systems .cc small { font-size: 10.5px; }
/* An off system is not an error, so it desaturates rather than greys out —
   it still has to be readable enough to switch back on. */
.choices.systems .choice:not(.sel) .cc b { color: var(--dim); }

/* ── Training: one screen, two shapes ───────────────────────────────────
   The routine-mode pair sits above whichever panel it selects. `hidden`
   already carries !important at the top of this file, which it must: both
   panels would otherwise be beaten by any explicit display. */
.routine-mode { margin-bottom: 16px; }
.training-panel > *:first-child { margin-top: 0; }

/* ── A creator's code ───────────────────────────────────────────────────
   Quiet by default. Most arrivals have no code, and an empty field with a
   label shouting DISCOUNT makes them feel they are paying more than someone
   else — which is true, and still not the first thing to say to them. */
/* ── A creator's code, in the top bar ──────────────────────────────────
   It sits at the right end of the rail row, so it is on screen the moment
   the page is and never fights the hero or hides behind the sticky CTA.
   Quiet by default — most arrivals have no code and must not be made to
   feel they are missing one — and a solid chip once applied, because at
   that point it is a promise being kept rather than a question. */
.code-slot { margin-left: auto; flex: none; }
.code-open {
  background: none; border: 0; padding: 6px 2px; cursor: pointer;
  font: 500 12px/1 inherit; color: var(--dim);
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 3px; text-decoration-color: var(--line);
  white-space: nowrap;
}
.code-open:hover { color: var(--tx) }
.code-chip {
  display: inline-flex; align-items: center; gap: 6px; max-width: 46vw;
  padding: 5px 10px 5px 8px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line); background: var(--raised);
  font: 700 11.5px/1 inherit; color: var(--tx); white-space: nowrap;
}
.code-chip svg {
  width: 12px; height: 12px; flex: none;
  fill: none; stroke: #0E9F68; stroke-width: 3.2;
  stroke-linecap: round; stroke-linejoin: round;
}
.code-chip span {
  overflow: hidden; text-overflow: ellipsis;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  letter-spacing: .04em;
}
.code-chip:hover { border-color: var(--line2); }
.code-clear {
  margin-top: 8px; padding: 4px 2px; background: none; border: 0; cursor: pointer;
  font: 500 12px/1 inherit; color: var(--dim);
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 3px; text-decoration-color: var(--line);
}
.code-clear:hover { color: var(--red, #D62A4C); }
/* Opens BELOW the bar rather than inside it: an input squeezed between the
   back button and the rail is a smaller target than a thumb. */
.code-panel { margin-top: 10px; padding-bottom: 2px; text-align: right; }
.code-row { display: inline-flex; gap: 8px; align-items: center }
.code-row input {
  width: 148px; padding: 10px 12px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--raised); color: var(--tx);
  font: 600 14px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .06em; text-transform: uppercase;
}
.code-row input:focus { outline: 2px solid var(--ac); outline-offset: 1px }
.code-row input:disabled { opacity: .7 }
/* v7 renamed the palette: --tx / --dim / --raised / --ac. This block was
   ported from the old sheet still asking for --ink / --muted / --card, and an
   undefined custom property does not fall back — it invalidates the whole
   declaration. `background: var(--ink)` therefore computed to transparent,
   so Apply has been near-white text on nothing since the v7 rebuild: a
   button nobody could see, on the one control that carries a creator's
   attribution. Enter still worked, which is why it survived this long. */
.code-apply {
  padding: 10px 14px; border-radius: 12px; border: 0; cursor: pointer;
  background: var(--tx); color: var(--bg); font: 700 13px/1 inherit;
}
.code-apply:disabled { opacity: .5; cursor: default }
.code-said { margin-top: 8px; font-size: 12.5px; color: var(--dim); text-align: right }
.code-said.is-ok { color: #0E9F68; font-weight: 600 }
.code-said.is-bad { color: var(--red, #D62A4C) }

/* The language selector stays available in the restored original funnel. */
.onboarding-language { margin-left:auto; order:2; max-width:48%; }
.onboarding-language select { font:inherit; font-size:12px; color:var(--tx); background:var(--raised); border:1px solid var(--line2); border-radius:12px; padding:9px 8px; max-width:100%; min-height:40px; }
.onboarding-language .sr-only { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
@media (max-width:480px) { .onboarding-language { order:0; flex-basis:100%; max-width:100%; text-align:right; } .onboarding .top-row { flex-wrap:wrap; gap:8px; } }
