/**
 * Chatterbox funnel — parent-facing surface.
 *
 * The four rules are enforced structurally here, not by convention:
 *   1. Red never touches a headline. `h1,h2,h3 { color: var(--brand-teal) }` is
 *      set once and never overridden. Red lives only on .cta and .bar.
 *   2. Leading 1.0 on every heading.
 *   3. 0px radius, zero shadows. Depth is full-bleed colour blocks butted together.
 *   4. Mono on functional detail — .spec, .stat, price, minutes, sound, position.
 */

@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;700;900&family=Spline+Sans+Mono:wght@400;500&display=swap');

:root {
  --brand-red: #F9423A;
  --brand-red-deep: #DA2228;
  --brand-teal: #008578;
  --brand-teal-deep: #006558;

  --surface-white: #FFFFFF;
  --surface-peach: #FEDEC5;
  --surface-peach-100: #FFEEE2;
  --surface-peach-50: #FFF2EA;
  --surface-mint: #B5E3D8;
  --surface-grey: #F7F7F7;

  --accent-amber: #FFB423;
  --accent-yellow: #FFCB05;
  --accent-orange: #FF7714;
  --accent-green: #00A94F;

  --text-primary: #000000;
  --text-body: #666666;
  --text-ink: #141414;
  --text-inverse: #FFFFFF;

  --border-light: #CCCCCC;

  --font-display: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'Spline Sans Mono', ui-monospace, Menlo, Monaco, monospace;

  --fs-display: 60px;
  --fs-h1: 54px;
  --fs-h2: 50px;
  --fs-h3: 30px;
  --fs-body: 16px;
  --fs-sm: 14px;
  --fs-xs: 12px;

  --lh-heading: 1.0;
  --lh-body: 1.7;
  --tracking-tight: -0.13px;

  --focus-ring: 0 0 0 4px var(--brand-red);

  --shell: 560px;
}

/* Mobile-first type scale. The desktop numbers above are poster sizes; a funnel
   read on a phone at 7pm needs them stepped down or the headline wraps to four
   lines and rule 2 turns a virtue into a wall. */
@media (max-width: 640px) {
  :root {
    --fs-display: 38px;
    --fs-h1: 34px;
    --fs-h2: 30px;
    --fs-h3: 22px;
  }
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-body);
  background: var(--surface-white);
  -webkit-font-smoothing: antialiased;
}

/* Rule 1, enforced once. Every heading is teal. Red is action only. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 900;
  line-height: var(--lh-heading);       /* Rule 2 */
  letter-spacing: var(--tracking-tight);
  color: var(--brand-teal);
  margin: 0 0 var(--sp, 16px) 0;
  text-wrap: balance;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }

p { margin: 0 0 16px 0; }
p:last-child { margin-bottom: 0; }

/* ── Rule 4: mono carries fact ─────────────────────────────────────────── */
.spec, .stat, .price, .cite, .progress-count {
  font-family: var(--font-mono);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.cite {
  font-size: var(--fs-xs);
  color: var(--text-body);
  letter-spacing: 0.02em;
}

/* ── Eyebrow with the hand-drawn wavy sine underline ───────────────────── */
.eyebrow {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-teal);
  margin-bottom: 14px;
  padding-bottom: 9px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='7' viewBox='0 0 40 7'><path d='M0 4.2 C 4 0.6, 6 0.6, 10 4.2 S 16 7.8, 20 4.2 S 26 0.6, 30 4.2 S 36 7.8, 40 4.2' fill='none' stroke='%23008578' stroke-width='2.5' stroke-linecap='round'/></svg>");
  background-repeat: repeat-x;
  background-position: left bottom;
  background-size: 40px 7px;
}

/* ── Shell ─────────────────────────────────────────────────────────────── */
.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 20px;
}

/* Rule 3: depth is full-bleed colour butted edge to edge, never a shadow. */
.block { padding: 40px 0; }
.block--peach { background: var(--surface-peach); }
.block--peach-50 { background: var(--surface-peach-50); }
.block--mint { background: var(--surface-mint); }
.block--teal { background: var(--brand-teal-deep); }
.block--teal h1, .block--teal h2, .block--teal h3 { color: var(--text-inverse); }
.block--teal p { color: rgba(255, 255, 255, 0.88); }
.block--grey { background: var(--surface-grey); }

/* ── Header + progress ─────────────────────────────────────────────────── */
.head {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--surface-white);
  border-bottom: 1px solid var(--surface-peach);
}

.head__row {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 12px 20px 10px;
  display: flex;
  align-items: center;
  gap: 14px;
}

.back {
  appearance: none;
  border: 0;
  background: none;
  padding: 4px 6px 4px 0;
  font: inherit;
  font-size: 20px;
  line-height: 1;
  color: var(--brand-teal);
  cursor: pointer;
}
.back:focus-visible { outline: 0; box-shadow: var(--focus-ring); }
.back[hidden] { visibility: hidden; display: block; }

.wordmark {
  font-weight: 900;
  font-size: 19px;
  letter-spacing: -0.02em;
  color: var(--brand-teal);
  margin-right: auto;
}

.progress-count {
  font-size: var(--fs-xs);
  color: var(--text-body);
  letter-spacing: 0.04em;
}

/* Milestone track: 4 dots at 0 / 33 / 66 / 100 that fill and pulse. */
.track {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 20px 12px;
  display: flex;
  align-items: center;
  gap: 0;
}

.track__seg {
  flex: 1;
  height: 3px;
  background: var(--surface-peach);
  overflow: hidden;
}
/* .track__fill's geometry now lives in the motion block at the foot of this
   file, because it is animated. It used to be `width: 0` with a
   `transition: width 380ms` — a layout-and-paint animation on an element inside
   a `position: sticky` header, which is the most expensive possible way to draw
   a 3px line and is banned by the motion contract. CB_MOTION.progress() scales
   it on X from a left origin instead. Do not reintroduce a width here. */

.dot {
  width: 15px;
  height: 15px;
  border-radius: 50%;                 /* radio/dot exception — not a card */
  background: var(--surface-peach);
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--text-inverse);
  font-size: 9px;
  font-weight: 900;
  transition: background 260ms ease;
}
/* Milestone label sits under the track rather than in the header row — at
   390px the wordmark, a label and a fraction on one line is three things
   competing for the same 350px. */
.milestone-row { max-width: var(--shell); margin: 0 auto; padding: 0 20px 10px; min-height: 14px; }
.milestone {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--brand-teal);
}

.dot--done { background: var(--brand-teal); }

/* `.dot--pulse` and `@keyframes pulse` are gone. The keyframe animated
   `box-shadow` spread from 0 to 11px, which repaints a growing area on every
   frame — banned by the motion contract. CB_MOTION.pulse() scales a transform-only
   ring child instead, and owns the once-per-milestone guarantee in JS, where it
   can actually be made idempotent. */

/* ── Screen ────────────────────────────────────────────────────────────── */
.screen {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 26px 20px 130px;
}

/* The `animation: rise` declaration and its @keyframes are gone, and they were
   never doing the job they looked like they were doing: engine.js reuses this one
   <main id="screen"> element and only clears its CHILDREN, so a CSS entry
   animation bound to it fires exactly once per page load. Every screen after the
   first arrived with no transition at all. CB_MOTION.enterScreen() animates the
   host per navigation, and knows which direction she is travelling. */

.screen__reason {
  font-size: var(--fs-sm);
  color: var(--text-body);
  margin: -6px 0 22px;
  padding-left: 12px;
  border-left: 3px solid var(--surface-peach);
}

/* ── Options ───────────────────────────────────────────────────────────── */
.opts { display: grid; gap: 10px; margin-top: 22px; }
.opts--tiles { grid-template-columns: repeat(2, 1fr); }

.opt {
  appearance: none;
  width: 100%;
  text-align: left;
  font: inherit;
  font-weight: 500;
  color: var(--text-ink);
  background: var(--surface-white);
  border: 2px solid var(--surface-peach);
  border-radius: 0;                    /* Rule 3 */
  padding: 17px 18px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 13px;
  transition: border-color 130ms ease, background 130ms ease;
}
.opt:hover { border-color: var(--brand-teal); background: var(--surface-peach-50); }
.opt:focus-visible { outline: 0; box-shadow: var(--focus-ring); }
.opt[aria-pressed="true"] { border-color: var(--brand-teal); background: var(--surface-peach-100); }

.opt__emoji { font-size: 26px; line-height: 1; flex: 0 0 auto; }
.opt__label { flex: 1; }
.opt__sub { display: block; font-size: var(--fs-xs); color: var(--text-body); font-weight: 400; }

.opts--tiles .opt {
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  min-height: 118px;
  justify-content: center;
}
.opts--tiles .opt__emoji { font-size: 34px; }

/* Multi-select needs a visible checked affordance — the border alone reads as
   "selected one of", not "added to a set". */
.opt__check {
  width: 22px; height: 22px;
  flex: 0 0 auto;
  border: 2px solid var(--border-light);
  display: grid; place-items: center;
  color: var(--text-inverse);
  font-size: 13px; font-weight: 900;
}
.opt[aria-pressed="true"] .opt__check { background: var(--brand-teal); border-color: var(--brand-teal); }

/* 1–5 scale */
.scale { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-top: 22px; }
.scale .opt { justify-content: center; padding: 22px 0; font-weight: 900; font-size: 20px; }
.scale__ends {
  display: flex; justify-content: space-between;
  font-size: var(--fs-xs); color: var(--text-body); margin-top: 9px;
}

/* ── CTA ───────────────────────────────────────────────────────────────── */
.cta {
  appearance: none;
  display: block;
  width: 100%;
  font: inherit;
  font-weight: 900;
  font-size: 17px;
  letter-spacing: 0.01em;
  color: var(--text-inverse);
  background: var(--brand-red);       /* Rule 1: red is action, only here */
  border: 0;
  border-radius: 0;
  padding: 19px 20px;
  cursor: pointer;
  transition: background 130ms ease;
}
.cta:hover { background: var(--brand-red-deep); }
.cta:focus-visible { outline: 0; box-shadow: 0 0 0 4px var(--brand-teal); }
.cta:disabled { background: var(--border-light); cursor: not-allowed; }

.dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--surface-white);
  border-top: 1px solid var(--surface-peach);
  padding: 12px 20px calc(12px + env(safe-area-inset-bottom));
  z-index: 20;
}
.dock__inner { max-width: var(--shell); margin: 0 auto; }

/* ── Interstitial (the give-back) ──────────────────────────────────────── */
.give { text-align: left; }
.give__mark { font-size: 46px; line-height: 1; margin-bottom: 18px; }
.give__body { font-size: 17px; color: var(--text-ink); }
.give__body strong { color: var(--brand-teal); font-weight: 700; }

/* Side-by-side fact pair — the wedge, rendered as two blocks butted together. */
.pair { display: grid; grid-template-columns: 1fr 1fr; margin: 26px 0; }
.pair__half { padding: 22px 18px; }
.pair__half:first-child { background: var(--surface-peach); }
.pair__half:last-child { background: var(--surface-mint); }
.pair__n {
  font-family: var(--font-mono);
  font-size: 30px; font-weight: 500; color: var(--brand-teal-deep);
  line-height: 1; display: block; margin-bottom: 7px;
}
.pair__t { font-size: var(--fs-sm); color: var(--text-ink); }

/* ── Loader ────────────────────────────────────────────────────────────── */
.load__pct {
  font-family: var(--font-mono);
  font-size: 54px; font-weight: 500; color: var(--brand-teal);
  line-height: 1; margin-bottom: 20px;
}
.load__bar { height: 5px; background: var(--surface-peach); margin-bottom: 30px; }
/* `.load__bar span` geometry moved to the motion block at the foot of this file.
   It was `width: 0` written per frame by render.loader — 73 forced layouts and
   73 style recalcs during one 6.5s loader, measured by perf.mjs. */
.phase {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 0;
  font-size: var(--fs-sm);
  color: var(--border-light);
  border-bottom: 1px solid var(--surface-grey);
  transition: color 200ms ease;
}
.phase--active { color: var(--text-ink); font-weight: 700; }
.phase--done { color: var(--text-body); }
.phase__tick { width: 18px; flex: 0 0 auto; color: var(--brand-teal); font-weight: 900; }

/* ── Email capture ─────────────────────────────────────────────────────── */
.field {
  width: 100%;
  font: inherit;
  font-size: 17px;
  color: var(--text-ink);
  background: var(--surface-white);
  border: 2px solid var(--surface-peach);
  border-radius: 0;
  padding: 17px 16px;
}
.field:focus { outline: 0; box-shadow: var(--focus-ring); border-color: var(--brand-red); }
.field[aria-invalid="true"] { border-color: var(--brand-red); }

.chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 11px; }
.chip {
  appearance: none;
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--brand-teal);
  background: var(--surface-peach-50);
  border: 1px solid var(--surface-peach);
  border-radius: 0;
  padding: 7px 10px;
  cursor: pointer;
}
.chip:hover { background: var(--surface-peach-100); }
.chip:focus-visible { outline: 0; box-shadow: var(--focus-ring); }

/* ── Locked strings ───────────────────────────────────────────────────────
   COMPLIANCE-RAILS §1.4 sets the rendering floor for L1 (the SLP sentence) and
   §2.3 sets the same floor for L2 (the pre-purchase disclosure): >= 16px, in
   --text-ink or --text-primary, NEVER --text-body, never in the footer, never
   inside a disclosure accordion, never as an image, and never followed on the
   same line by a "but", a price or a CTA.

   That is why this is not `.fine`. `.fine` is --fs-xs / --text-body, which is
   exactly the rendering the rail forbids. If a future pass "harmonises" the two
   classes, the funnel fails §1.4 and §2.3 silently, on every screen at once.
   Leave them separate. The margin below is what keeps a CTA off the same line. */
.locked {
  font-size: var(--fs-body);          /* 16px floor */
  line-height: 1.55;
  font-weight: 500;
  color: var(--text-ink);
  margin: 18px 0 14px;
}
.locked a { color: var(--brand-teal); }

/* L3, the privacy string (§3.4). >= 14px, and --text-body IS acceptable here —
   the rail says so explicitly, because this is reassurance rather than a
   material term. It still renders inline on the screen, not only in the policy. */
.privacy {
  font-size: var(--fs-sm);            /* 14px floor */
  line-height: 1.6;
  color: var(--text-body);
  margin: 0 0 12px;
}
.privacy a { color: var(--brand-teal); }

.fine { font-size: var(--fs-xs); color: var(--text-body); line-height: 1.55; }
.fine a { color: var(--brand-teal); }

/* ── Plan spec (the honest replacement for the fabricated score) ────────── */
.spec-table { width: 100%; border-collapse: collapse; margin: 22px 0; }
.spec-table th, .spec-table td {
  text-align: left;
  padding: 13px 12px;
  border-bottom: 1px solid var(--surface-peach);
  font-size: var(--fs-sm);
}
.spec-table th {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-body);
  width: 42%;
}
.spec-table td { color: var(--text-ink); font-weight: 500; }

/* Row-level material label — COMPLIANCE-RAILS §10 L7 under "Word positions".
   Deliberately NOT small print: --text-ink, not --text-body, and no smaller than
   the spec rows it qualifies. A fixed default shown without its label reads as a
   selection made for this child, which is the thing the label exists to prevent.
   Do not restyle this into a footnote, a tooltip, or a muted caption. */
.spec-table__note-row td.spec-table__note {
  width: auto;
  padding-top: 10px;
  padding-bottom: 14px;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.55;
  color: var(--text-ink);
  background: var(--surface-peach-50);
}

.notice {
  background: var(--surface-grey);
  border-left: 3px solid var(--brand-teal);
  padding: 15px 16px;
  font-size: var(--fs-sm);
  color: var(--text-ink);
  margin-bottom: 14px;
}

/* Reassurance, not warning. Mint is the soft surface, and this is the one place
   in the funnel where the news is unambiguously good. */
.notice--good { background: var(--surface-mint); border-left-color: var(--brand-teal-deep); }
.notice--good strong { color: var(--brand-teal-deep); }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOTION — companion rules for app/motion.js
   ═══════════════════════════════════════════════════════════════════════════
   Generated from CB_MOTION.CSS so the two cannot drift. Every rule here exists
   because the property it replaces was a layout or paint animation:

     .screen { animation: rise } + @keyframes rise   -> enterScreen()
        (and it never re-fired anyway: engine.js reuses <main id="screen"> and
         clears only its children, so it ran once per page load)
     .track__fill { width: 0; transition: width }    -> progress(), scaleX
     .load__bar span { width: 0 }                    -> progress(), scaleX
     .dot--pulse + @keyframes pulse (box-shadow)     -> pulse(), transform ring

   All four have been deleted above. Do not reintroduce a width or a box-shadow
   transition on any of these elements.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Selection wipe. The button becomes the positioning context; the wipe sits
   exactly over its 2px border box and scales in from the left. pointer-events
   none so it can never eat the tap it is acknowledging. */
.opt { position: relative; }
.opt__wipe {
  position: absolute;
  top: -2px; right: -2px; bottom: -2px; left: -2px;
  border: 2px solid var(--brand-teal);
  border-radius: 0;                    /* Rule 3 */
  pointer-events: none;
  transform: scaleX(0);
  transform-origin: left center;
}

/* Once JS has adopted a button (CB_MOTION.select() adds .opt--wipe) the wipe
   is the only teal border, so the real border goes back to peach. Without
   this the border flips teal instantly and the wipe reveals nothing.
   Buttons JS has NOT adopted keep the instant border, so a forgotten
   select() degrades to the old behaviour rather than to no feedback. */
.opt.opt--wipe[aria-pressed="true"] { border-color: var(--surface-peach); }

/* Progress fills: scaleX from a left origin, never width. Applies to the
   milestone track and the loader bar, which had the same width bug. */
.track__fill, .load__bar span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--brand-teal);
  transform: scaleX(0);
  transform-origin: left center;
  transition: none;
}

/* Milestone pulse ring. border-radius is the documented dot exception. The
   node is created and removed by CB_MOTION.pulse(); this rule only gives it
   geometry. */
.dot { position: relative; }
.dot__ring {
  position: absolute;
  top: -2px; right: -2px; bottom: -2px; left: -2px;
  border: 2px solid var(--brand-teal);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
}

/* ── Progressive disclosure control on a multi-select ─────────────────────
   Reads as a CONTROL, not as an option: dashed edge, no check affordance, teal
   label. It must never look like one more thing to choose. */
.opt--more {
  margin-top: 10px;
  border-style: dashed;
  color: var(--brand-teal);
  font-weight: 700;
}
/* REQUIRED, not cosmetic. `.opt` sets `display: flex`, which out-specifies the
   UA's `[hidden] { display: none }` rule — without this line the `hidden`
   attribute does nothing at all on an option and the fold silently fails open.
   `.back[hidden]` above already handles the same collision. */
.opt[hidden] { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE MONEY SCREEN — disclosure band, expanders, seller identity
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── The mandated-VISIBLE disclosure band ─────────────────────────────────
   COMPLIANCE-RAILS §2.3: >= 16px, --text-ink, NEVER --text-body, never
   truncated, never collapsed. Do NOT add max-height, line-clamp,
   text-overflow or overflow:hidden to anything in here — each of those is a
   truncation, and §2.3 forbids truncation as explicitly as it forbids an
   accordion. */
.disclose { background: var(--surface-peach-50); padding: 18px; margin-top: 20px; }
.disclose__p { font-size: 17px; line-height: 1.7; color: var(--text-ink); margin: 0 0 12px 0; }
.disclose__p:last-child { margin-bottom: 0; }
.disclose__p strong { color: var(--brand-teal); font-weight: 700; }

/* ── Expander rows ─────────────────────────────────────────────────────── */
.rows { margin-top: 22px; border-top: 1px solid var(--surface-peach); }
.row { border-bottom: 1px solid var(--surface-peach); }
.row__btn {
  appearance: none; display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 17px 0; background: none; border: 0; border-radius: 0;
  font: inherit; font-size: var(--fs-body); font-weight: 500; text-align: left;
  color: var(--text-ink); cursor: pointer;
}
.row__btn:focus-visible { outline: 0; box-shadow: var(--focus-ring); }
/* NO text-overflow here. A truncated label is a cut label, and every row label
   has to be true and complete while the row is closed. */
.row__label { flex: 1 1 auto; }
.row__mark { flex: 0 0 14px; width: 14px; height: 14px; position: relative; }
.row__mark::before, .row__mark::after {
  content: ''; position: absolute; inset: 50% 0 auto 0; height: 2px; margin-top: -1px;
  background: var(--brand-teal);
  transition: transform 180ms cubic-bezier(0.22, 0.61, 0.36, 1);   /* transform only */
}
.row__mark::after { transform: rotate(90deg); }                    /* the plus's upright */
.row__btn[aria-expanded="true"] .row__mark::after { transform: rotate(0deg); }  /* -> minus */
.row__body { padding: 0 0 18px 0; }
.row__body p { font-size: var(--fs-sm); line-height: 1.7; color: var(--text-ink); margin: 0; }

/* ── Seller identity ──────────────────────────────────────────────────────
   §2.3 requires >= 14px. Deliberately NOT .cite, which is 12px/--text-body —
   the one line naming who takes the money is not fine print. */
.merchant {
  font-family: var(--font-mono); font-size: var(--fs-sm);
  color: var(--text-ink); line-height: 1.6; margin-top: 20px;
}
.fine--14 { font-size: var(--fs-sm); }

/* §5.2 fold mitigation at small-Android width: PADDING ONLY. Never L2's type
   size, never its order. */
@media (max-width: 400px) {
  .disclose { padding: 14px; }
  .eyebrow { margin-bottom: 10px; }
}

/* ── Chatterbox mechanism animations ──────────────────────────────────
   GENERATED from CB_MECH_CSS in app/mechanisms.js — edit there, not here.
   Tokens only, 0px radius (the mic ring is the documented dot/ring
   exception), no shadows, and every animated property is transform or
   opacity. */

.mech { margin: 26px 0; }

/* ── 1 · s_travels ─────────────────────────────────────────────────── */
.mech-tr__stage { position: relative; }
.mech-tr__row { display: flex; align-items: center; gap: 12px; padding: 3px 0; }
.mech-tr__w {
  font-family: var(--font-mono);
  font-size: 28px; font-weight: 400; line-height: 1.25;
  letter-spacing: 0.02em; color: var(--text-body); white-space: nowrap;
}
.mech-tr__slot { position: relative; display: inline-block; }
/* The ghost the flyer leaves behind. Same glyph, same weight, same size —
   the argument is that it is the SAME letter, so it may not change. */
.mech-tr__hit {
  color: var(--brand-teal); font-weight: 500; opacity: 0;
  transition: opacity 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-tr__hit--ghost { opacity: 0.32; }
.mech-tr__hit--on { opacity: 1; }
.mech-tr__pos {
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.06em; color: var(--text-body);
  opacity: 0; transition: opacity 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-tr__pos--on { opacity: 1; }
.mech-tr__fly {
  position: absolute; left: 0; top: 0;
  font-family: var(--font-mono);
  font-size: 28px; font-weight: 500; line-height: 1.25;
  letter-spacing: 0.02em; color: var(--brand-teal);
  white-space: nowrap; opacity: 0;
  transition: opacity 160ms linear;
}
.mech-tr__fly--in { opacity: 1; }
/* Overshoot-and-settle, not a bounce: the 1.04 carries the letter a hair
   past the hole and eases it back in. */
.mech-tr__fly--move {
  transition: transform 520ms cubic-bezier(0.24, 0.86, 0.28, 1.04),
              opacity 160ms linear;
}
@media (max-width: 380px) {
  .mech-tr__w, .mech-tr__fly { font-size: 23px; }
}

/* ── 2 · week_fills ────────────────────────────────────────────────── */
.mech-wk__count { display: flex; align-items: baseline; gap: 7px; }
.mech-wk__n {
  font-family: var(--font-mono);
  font-size: 44px; font-weight: 500; line-height: 1; color: var(--brand-teal);
}
.mech-wk__u { font-family: var(--font-mono); font-size: 14px; color: var(--text-body); }
.mech-wk__sum {
  font-family: var(--font-mono); font-size: 12px; color: var(--text-body);
  margin-top: 6px; opacity: 0;
  transition: opacity 240ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-wk__sum--on { opacity: 1; }
.mech-wk__grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; margin-top: 18px;
}
.mech-wk__col {
  position: relative; height: 74px;
  background: var(--surface-peach); overflow: hidden;
}
/* Fills with scaleY from the bottom edge. Never height — CONTRACT rule 1. */
.mech-wk__fill {
  position: absolute; left: 0; right: 0; top: 0; bottom: 0; display: block;
  background: var(--brand-teal);
  transform: scaleY(0); transform-origin: 50% 100%;
  transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-wk__fill--on { transform: scaleY(1); }
.mech-wk__lab {
  display: block; text-align: center;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em;
  color: var(--text-body); margin-top: 6px;
}
.mech-wk__lab--rest { color: var(--border-light); }

/* ── 3 · list_reorders ─────────────────────────────────────────────── */
.mech-ls__card {
  display: flex; align-items: center; gap: 12px; padding: 11px 13px;
  background: var(--surface-white); border: 2px solid var(--surface-peach);
  margin-bottom: 8px;
  /* 240ms is paired with the 250ms swap step in mechanisms.js: one swap
     lands before the next begins, so only two cards ever move at once. */
  transition: transform 240ms cubic-bezier(0.22, 0.61, 0.36, 1),
              border-color 200ms ease, opacity 260ms ease;
}
.mech-ls__card--up { border-color: var(--brand-teal); }
.mech-ls__card--up .mech-ls__word { color: var(--brand-teal); }
.mech-ls__card--out { opacity: 0.16; }
.mech-ls__emoji {
  flex: 0 0 auto; width: 30px; font-size: 22px; line-height: 1;
  transition: transform 260ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-ls__emoji--big { transform: scale(1.35); }
.mech-ls__word {
  font-family: var(--font-mono); font-size: 15px; color: var(--text-ink);
  transition: color 200ms ease;
}
.mech-ls__flag {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em;
  color: var(--brand-teal); opacity: 0; transition: opacity 200ms ease;
}
.mech-ls__flag--on { opacity: 1; }
/* music: the held-word bar. scaleX from the left, never width. */
.mech-ls__dur {
  position: relative; flex: 1; height: 3px;
  background: var(--surface-peach); overflow: hidden;
}
.mech-ls__durfill {
  position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: block;
  background: var(--brand-teal);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 400ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-ls__durfill--on { transform: scaleX(1); }
.mech-ls__note {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.05em;
  color: var(--text-body); margin-top: 10px;
  opacity: 0; transition: opacity 240ms ease;
}
.mech-ls__note--on { opacity: 1; }

/* ── 4 · session_loop ──────────────────────────────────────────────── */
.mech-lp__card {
  display: flex; align-items: center; gap: 13px; padding: 14px;
  background: var(--surface-peach-50); border: 2px solid var(--surface-peach);
  opacity: 0; transform: translateY(8px);
  transition: opacity 220ms cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-lp__card--on { opacity: 1; transform: none; }
.mech-lp__emoji { font-size: 30px; line-height: 1; }
.mech-lp__word {
  font-family: var(--font-mono); font-size: 22px; font-weight: 500;
  color: var(--text-ink);
}
/* Fixed height: the three phases cross-fade inside the same box, so nothing
   reflows between model, record and compare. */
.mech-lp__stage { position: relative; height: 104px; margin-top: 10px; }
.mech-lp__phase {
  position: absolute; left: 0; right: 0; top: 0; bottom: 0;
  display: flex; align-items: center; justify-content: center; gap: 18px;
  opacity: 0; transition: opacity 200ms ease;
}
.mech-lp__phase--on { opacity: 1; }
.mech-lp__spk {
  font-size: 34px; line-height: 1;
  transition: transform 260ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-lp__spk--pulse { transform: scale(1.16); }
.mech-lp__mic {
  position: relative; width: 62px; height: 62px;
  border: 2px solid var(--surface-peach); border-radius: 50%;
  display: grid; place-items: center; overflow: hidden;
}
.mech-lp__micfill {
  position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: block;
  border-radius: 50%; background: var(--surface-mint);
  transform: scale(0); transform-origin: 50% 50%;
  transition: transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.mech-lp__micfill--on { transform: scale(1); }
.mech-lp__micglyph { position: relative; font-size: 24px; line-height: 1; }
.mech-lp__waves { display: flex; align-items: flex-end; gap: 18px; }
.mech-lp__wave { display: flex; flex-direction: column; align-items: center; gap: 7px; }
.mech-lp__bars { display: flex; align-items: center; gap: 3px; height: 54px; }
/* Bars, not an SVG path and not a canvas. scaleY about the centre line. */
.mech-lp__bar {
  display: block; width: 4px; height: 100%;
  background: var(--brand-teal);
  transform: scaleY(0); transform-origin: 50% 50%;
  transition: transform 150ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Two palette teals, neither ranked. The right-hand waveform is NOT drawn as
   better, worse, or converging on the left one. */
.mech-lp__wave--b .mech-lp__bar { background: var(--brand-teal-deep); }
.mech-lp__wlab {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.05em;
  color: var(--text-body);
}
.mech-lp__caps { display: flex; gap: 16px; margin-top: 12px; }
.mech-lp__cap {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.07em;
  color: var(--border-light); transition: color 200ms ease;
}
.mech-lp__cap--on { color: var(--brand-teal); }
/* Cycle rewind. !important because it has to beat the per-property
   transitions above for exactly one frame, and it is removed immediately. */
.mech--loop-instant * { transition: none !important; }
/* Reduced motion: the same three phases as a still storyboard. */
.mech-lp__board {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 12px;
}
.mech-lp__framebox {
  border: 2px solid var(--surface-peach); background: var(--surface-peach-50);
  min-height: 92px; display: grid; place-items: center; padding: 8px 6px;
}
.mech-lp__board .mech-lp__waves { gap: 8px; }
.mech-lp__board .mech-lp__bars { gap: 2px; height: 40px; }
.mech-lp__board .mech-lp__bar { width: 3px; }
.mech-lp__board .mech-lp__wlab { font-size: 9px; letter-spacing: 0; }
.mech-lp__board .mech-lp__cap { display: block; margin-top: 7px; }


/* ── Paywall plan ladder (engine planLadder) ────────────────────────────────
   The reference funnel's tiered per-day pricing frame, on brand tokens.
   Square and flat per the design system; teal marks selection, red never
   touches anything here except nothing — the CTA lives in the dock. */
.pwplans__head {
  font-size: 13px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--brand-teal); margin: 22px 0 10px;
}
.pwplans { display: flex; flex-direction: column; gap: 10px; }
.pwplan {
  display: flex; align-items: center; gap: 12px; width: 100%;
  border: 1.5px solid var(--surface-peach); background: #fff;
  padding: 14px; cursor: pointer; text-align: left; position: relative;
  font: inherit; color: inherit;
}
.pwplan[aria-checked="true"] { border-color: var(--brand-teal); border-width: 2px; background: var(--surface-peach-50); }
.pwplan:focus-visible { outline: 3px solid var(--brand-teal-deep); outline-offset: 2px; }
.pwplan__dot {
  flex: 0 0 18px; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--surface-peach); position: relative;
}
.pwplan[aria-checked="true"] .pwplan__dot { border-color: var(--brand-teal); }
.pwplan[aria-checked="true"] .pwplan__dot::after {
  content: ""; position: absolute; inset: 3px; border-radius: 50%;
  background: var(--brand-teal);
}
.pwplan__main { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.pwplan__main strong { font-size: 15.5px; }
.pwplan__main em { font-style: normal; font-size: 12.5px; color: var(--text-body); }
.pwplan__tag {
  position: absolute; top: -9px; right: 12px;
  background: var(--brand-teal); color: #fff;
  font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  padding: 2px 8px;
}
.pwplan__price { display: flex; flex-direction: column; align-items: flex-end; gap: 0; }
.pwplan__price b { font-size: 21px; letter-spacing: -.01em; }
.pwplan__price span { font-size: 11px; color: var(--text-body); }
.pwplans__terms { margin-top: 12px; }
