/* =========================================================================
   site.css — full site surface. Replaces the original styles.css.
   Loads after tokens.css. No raw hex anywhere: tokens only (§6).
   All motion is transform/opacity, one easing, four durations (§4).
   ========================================================================= */

/* ------------------------------------------------------------------ base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-base);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: var(--t-4xl); }
h2 { font-size: var(--t-3xl); }
h3 { font-size: var(--t-lg); line-height: var(--lh-snug); }
p { margin: 0; }
a { color: inherit; text-decoration-color: var(--rule-strong); text-underline-offset: 3px; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg { max-width: 100%; }
button { font: inherit; color: inherit; }

/* Slides in on transform, not top — the one place this sheet animated a
   layout property. Absolute positioning meant it never reflowed neighbours,
   but the motion contract says transform/opacity and a rule with one
   exception invites a second. Parked at its focused position; the transform
   carries it off-screen until focus. */
.skip-link {
  position: absolute; left: var(--s-4); top: var(--s-4); z-index: 200;
  background: var(--ink); color: var(--paper-card);
  padding: var(--s-2) var(--s-4); border-radius: var(--r-2);
  transform: translateY(calc(-100% - var(--s-4) - var(--s-2)));
  transition: transform var(--dur-1) var(--ease);
}
.skip-link:focus { transform: none; }

.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;
}

/* ---------------------------------------------------------------- layout */
.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--s-5); }
.container--narrow { max-width: var(--container-narrow); }

/* Alternating grounds so sections read as a sequence of sheets (§3). */
.section { padding-block: clamp(var(--s-8), 7vw, var(--s-10)); position: relative; }
.section--band { background: var(--paper-band); position: relative; }
.section--band::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 60%;
  background: var(--wash-band); pointer-events: none;
}
.section--band > * { position: relative; }
.section--band + .section--band { padding-top: 0; }

/* Anchor landing clearance. An in-page click goes through initSmoothScroll,
   which subtracts the header height; a link ARRIVED at — a share, a search
   result, llms.txt — gets a native browser scroll and no such offset.

   Until now the headings cleared the 67px sticky header only because section
   padding happens to exceed it. That is an accident, and the rule directly
   above this one already zeroes that padding in some adjacencies. This makes
   the clearance explicit so it survives any future padding change.

   s-8 + s-4 = 80px, comfortably over the header, and both already exist —
   no new token. check-anchors.mjs verifies the landings rather than assuming
   this is enough. */
[id] { scroll-margin-top: calc(var(--s-8) + var(--s-4)); }

/* Hairline between adjacent same-ground sections keeps the "page" feel. */
.section + .section:not(.section--band):not(.section--flush)::before {
  content: ''; position: absolute; inset-inline: var(--s-5); top: 0; height: 1px;
  background: var(--rule); max-width: var(--container); margin-inline: auto;
}

/* =================== the mono label system ==============================
   Every small mono label on this page does one of three jobs, and until now
   each was styled ad hoc: an audit found three colours, three letter-cases,
   two weights and two sizes across fourteen label types. Changing .eyebrow to
   uppercase/600 in the last pass made it worse by splitting labels that do the
   same job.

   One rule now: CASE AND WEIGHT say "this is a label"; COLOUR says which kind.

     tier 1  section eyebrow   UPPERCASE 600  --ink-muted   one per section
     tier 2  field label       UPPERCASE 600  role colour   labels a value
     tier 3  metadata          as-typed  400  --ink-muted   numbers, sources

   Colour stays role-specific on purpose. The comparison kicker is muted on the
   two neutral columns and --present on ours; that difference is load-bearing,
   so it is not normalised away.
   ======================================================================== */

/* ------------------------------------------------- eyebrow + ornament (§4.5) */
/* UPPERCASE and semibold, changed 2026-08-01. This label opens every section,
   so it is the first thing read in each — and it was the page's weakest text:
   regular weight, lowercase, at the smallest size in the system. Uppercase is
   the established convention that marks a string as a label rather than a
   sentence fragment, and 600 gives it enough presence to lead a 56px heading
   instead of apologising in front of it. Tracking was already correct; the
   fixture strings stay lowercase because the transform is presentational. */
.eyebrow {
  display: flex; align-items: center; gap: var(--s-3);
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--ink-muted); margin-bottom: var(--s-4);
}
.ornament { flex: 0 0 auto; width: 18px; height: 18px; color: var(--present); }
/* The ornament draws 300ms AHEAD of the headline (§4.5). */
.js [data-reveal] .ornament,
.js [data-reveal].eyebrow .ornament { transition: opacity var(--dur-2) var(--ease); }
.ornament path, .ornament line { stroke: currentColor; stroke-width: 1.5; fill: none; }
.ornament .ob { stroke-dasharray: 28; stroke-dashoffset: 28; transition: stroke-dashoffset var(--dur-3) var(--ease); }
.js [data-reveal].in-view .ornament .ob, .in-view .ornament .ob { stroke-dashoffset: 0; }

/* max-width in rem, NOT ch: `ch` resolves against this block's own font-size
   (body, ~1rem) while the h2 inside runs up to 2.9rem, so a ch-based cap
   crushed every headline into a handful of characters per line. */
.section-head { max-width: 46rem; margin-bottom: var(--s-7); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head--center .eyebrow { justify-content: center; }
.section-head p {
  margin-top: var(--s-4); color: var(--ink-2); font-size: var(--t-md);
  max-width: 56ch;
}
.section-head--center p { margin-inline: auto; }
.section-head .section-provenance {
  margin-top: var(--s-3); color: var(--ink-muted); font-size: var(--t-xs); max-width: none;
}

/* --------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  padding: .78em 1.5em; border-radius: var(--r-3); border: 1px solid transparent;
  font-weight: 600; text-decoration: none; cursor: pointer;
  transition: transform var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn--primary {
  background: var(--brand); color: var(--paper-card);
  box-shadow: var(--shadow-brand);
}
.btn--primary:hover { background: var(--brand-deep); box-shadow: var(--shadow-2); }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--rule-strong); }
.btn--ghost:hover { border-color: var(--ink); background: var(--paper-card); }
.btn--lg { padding: .92em 1.8em; font-size: var(--t-md); }

/* ---------------------------------------------------------------- header */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(150%) blur(10px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease);
}
.site-header.is-scrolled { border-bottom-color: var(--rule); }
.nav { display: flex; align-items: center; gap: var(--s-5); min-height: var(--header-h); }
.brand {
  display: inline-flex; align-items: center; gap: var(--s-3);
  font-family: var(--font-display); font-weight: var(--display-weight);
  font-size: var(--t-md); text-decoration: none; letter-spacing: var(--tracking-tight);
}
.brand-mark {
  display: grid; place-items: center; width: 30px; height: 30px;
  border: 1px solid var(--rule-strong); border-radius: var(--r-2);
  color: var(--present); background: var(--paper-card);
}
.primary-nav { display: flex; align-items: center; gap: var(--s-5); margin-left: auto; }
.nav-menu { display: flex; align-items: center; gap: var(--s-5); }
.nav-menu a {
  text-decoration: none; font-size: var(--t-sm); color: var(--ink-2);
  padding-bottom: 2px; position: relative;
  transition: color var(--dur-1) var(--ease);
}
.nav-menu a::after {
  content: ''; position: absolute; inset-inline: 0; bottom: 0; height: 1px;
  background: var(--ink); transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-1) var(--ease);
}
.nav-menu a:hover { color: var(--ink); }
.nav-menu a:hover::after { transform: scaleX(1); }

/* Current section. Reuses the hover underline rather than inventing a second
   marker — the only difference is the colour, so hover and position stay
   distinguishable without adding a visual language. Set by initNavPosition
   alongside aria-current, so it is never colour-only. */
.nav-menu a.is-current { color: var(--ink); }
.nav-menu a.is-current::after { transform: scaleX(1); background: var(--accent); }
@media (prefers-reduced-motion: reduce) {
  /* The mark moves as you scroll. Sliding it is motion tied to scrolling,
     which is exactly what this preference is asking us not to do. */
  .nav-menu a::after { transition: none; }
}

.icon-btn {
  display: grid; place-items: center; width: 34px; height: 34px;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-2);
  cursor: pointer; color: var(--ink-2);
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.icon-btn:hover { border-color: var(--rule-strong); color: var(--ink); }
.theme-toggle .icon-sun { display: none; }
[data-theme='dark'] .theme-toggle .icon-sun { display: block; }
[data-theme='dark'] .theme-toggle .icon-moon { display: none; }
.nav-toggle { display: none; }
.nav-toggle-bar { display: block; width: 17px; height: 1.5px; background: currentColor; }
.nav-toggle-bar + .nav-toggle-bar { margin-top: 4px; }

/* ------------------------------------------------------------------ hero */
.hero {
  position: relative;
  padding-top: clamp(var(--s-7), 5vw, var(--s-9));
  padding-bottom: clamp(var(--s-7), 5vw, var(--s-8));
  overflow: hidden;
}
.hero::before {
  content: ''; position: absolute; inset: -20% -10% auto -10%; height: 150%;
  background: var(--wash-hero); pointer-events: none; z-index: 0;
}
.hero > * { position: relative; z-index: 1; }
/* Centred hero. The two-column layout capped the headline at a ~560px measure,
   which at 84px produced a six-line h1 that pushed the capture below the fold.
   The best-looking pages in the category (Semrush 100px, Rankscale 96px) run a
   full-width centred headline with the product visual BELOW it — that is what
   lets big display type actually work. */
.hero-grid { display: grid; gap: clamp(var(--s-7), 5vw, var(--s-8)); }
/* rem, NOT ch — ch resolves against this block's own 1rem font-size while the
   h1 inside is 76px, which is exactly the bug that crushed the section heads. */
.hero-copy { max-width: 46rem; margin-inline: auto; text-align: center; }
.hero h1 { max-width: none; }
.hero-sub { margin-inline: auto; max-width: 54ch; }
.capture { margin-inline: auto; }
.capture-row { justify-content: center; }
.hero .eyebrow { justify-content: center; }
/* No max-width: the grid column already sets the measure. A ch cap here did the
   same damage as on .section-head. */
.hero-copy { min-width: 0; }
.hero h1 { margin-bottom: var(--s-5); }

/* The .cycle / .cycle-measure rules were removed with the cycling headline at
   Stage 1 — see the note in site.js. Nothing renders those classes now. */

.hero-sub { margin-bottom: var(--s-6); color: var(--ink-2); font-size: var(--t-md); max-width: 46ch; }

/* Inline hero capture (§4.3) — one field, expands to the full form on submit. */
.capture { max-width: 30rem; }
.capture-row { display: flex; gap: var(--s-2); }
.capture-field {
  flex: 1 1 auto; min-width: 0;
  padding: .8em 1em; font: inherit; color: var(--ink);
  background: var(--paper-card);
  border: 1px solid var(--rule-strong); border-radius: var(--r-3);
  transition: border-color var(--dur-1) var(--ease);
}
.capture-field::placeholder { color: var(--ink-muted); }
.capture-field:hover { border-color: var(--ink-muted); }
/* What happens next — three numbered beats under the field. A CTA that answers
   "and then what?" before it is asked removes the last hesitation; burying it
   in a run-on sentence, which is what was here, does not. Numerals are mono and
   quiet so the sequence reads without competing with the button. */
.capture-next {
  margin-top: var(--s-4); display: grid; gap: var(--s-2);
  counter-reset: next; text-align: left;
  font-size: var(--t-sm); color: var(--ink-2);
}
/* Absolutely-positioned numeral, NOT a grid column. `display:grid` on the li
   promotes every inline child to its own grid item, so a <strong> mid-sentence
   was thrown onto its own row and the step read as four broken fragments. Block
   flow keeps the sentence a sentence. */
.capture-next li {
  position: relative; padding-left: 1.4rem;
  counter-increment: next;
}
.capture-next li::before {
  content: counter(next);
  position: absolute; left: 0; top: 0;
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted);
}
.capture-next strong { color: var(--present); font-weight: 600; }

/* Left-aligned, matching .capture-next and the field's left edge. The hero
   headline stays centred; everything from the input down shares one left rail,
   so the eye has a single column to follow instead of three alignments. */
/* What the engagement delivers, distinct from the three sign-up beats above it.
   Given the brand tone rather than muted: it is the only forward-looking
   commitment on the page and it should not read as fine print. */
.capture-outcome {
  margin-top: var(--s-4); padding-top: var(--s-3);
  border-top: 1px solid var(--rule);
  text-align: left; font-size: var(--t-sm); color: var(--ink-2);
}
.capture-note { margin-top: var(--s-3); font-size: var(--t-sm); color: var(--ink-muted); text-align: left; }
.capture-note strong { color: var(--present); font-weight: 600; }
.capture-alt { text-align: left; }
.capture-msg { margin-top: var(--s-3); font-size: var(--t-sm); }
.capture-msg[data-tone='error'] { color: var(--absent); }
.capture-msg[data-tone='ok'] { color: var(--present); }

/* --------------------------------------------- hero answer dissection (§4.2) */
/* --- the answer dissection ------------------------------------------------
   Query on top, three measurement cards below, a connector between. The old
   stage was a 3-up grid of unrelated cards; this is one figure read top to
   bottom, so it needs rows rather than columns at the outer level. */
.hero-stage {
  position: relative;
  display: grid; gap: var(--s-3); justify-items: center;
  max-width: 68rem; margin-inline: auto;
}
.stage-row {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--s-4); align-items: start; width: 100%;
}
.hero-stage .float { position: static; width: auto; }
.hero-stage .float--q { width: min(28rem, 100%); }
.hero-stage .float--a,
.hero-stage .float--b,
.hero-stage .float--c { margin-top: 0; }

.stage-queries { display: grid; gap: var(--s-2); font-size: var(--t-sm); }
/* Quoted so they read as things a person typed, not as our labels. */
.stage-queries li::before { content: '\201C'; color: var(--ink-muted); }
.stage-queries li::after { content: '\201D'; color: var(--ink-muted); }
.stage-more { margin-top: var(--s-3); font-size: var(--t-xs); color: var(--ink-muted); }

/* The connector carries the aggregation in words. 13% is share of category
   answers measured across the sample — without this line, one query sitting
   above one number reads as "we asked this and got 13%". */
.stage-flow {
  display: grid; justify-items: center; gap: var(--s-2);
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted);
}
.stage-flow-rule {
  display: block; width: 1px; height: var(--s-5); background: var(--rule-strong);
  transform-origin: top center;
}
.float {
  background: var(--paper-card);
  border: 1px solid var(--rule); border-radius: var(--r-3);
  box-shadow: var(--shadow-3); padding: var(--s-4);
}
/* Perpetual drift retired with the dissection. Three cards bobbing on their
   own timers read as decoration; these three are one figure now, and motion
   that never resolves fights the sequence that does. The keyframe is gone
   rather than left dormant — a rule nothing uses is a rule someone re-adds. */

/* --- the dissection sequence ---------------------------------------------
   Pure CSS, deliberately. The reveal system elsewhere gates on .js so that a
   failed script cannot leave content permanently hidden; an animation needs
   no such gate, because its resting state IS the settled frame. Nothing here
   depends on JS running, or on when it runs.

   One shared --beat per card drives the stagger, so adding a card cannot
   desynchronise the sequence. */
@keyframes dissect-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes dissect-rule { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes dissect-bar  { from { transform: scaleX(0); } }
@keyframes dissect-chip { from { opacity: 0; } }

[data-dissect] [data-beat] {
  animation: dissect-in var(--dur-2) var(--ease) both;
  animation-delay: calc(var(--beat) * 120ms);
}
/* The connector draws downward, leading the eye from query to measurement
   rather than the two merely appearing near each other. */
[data-dissect] .stage-flow-rule {
  animation: dissect-rule var(--dur-2) var(--ease) both;
  animation-delay: calc(var(--beat) * 120ms);
}
/* Bars draw after their card has arrived — hence the +1 beat. Competitors
   fill first and "You" lands last and short, which is the whole point of the
   figure. */
[data-dissect] .bar-fill {
  animation: dissect-bar var(--dur-3) var(--ease) both;
  animation-delay: calc((var(--beat) + 1) * 120ms);
}
[data-dissect] .chip {
  animation: dissect-chip var(--dur-2) var(--ease) both;
  animation-delay: calc((var(--beat) + 1) * 120ms);
}

@media (prefers-reduced-motion: reduce) {
  /* No sequence, not a faster one. With the animations off every element
     falls back to its authored state, which is the settled frame. */
  [data-dissect] [data-beat],
  [data-dissect] .stage-flow-rule,
  [data-dissect] .bar-fill,
  [data-dissect] .chip { animation: none; }
}
/* The absolute top/left/bottom placements and --drift-* values that used to
   live here were already dead — .hero-stage .float sets position:static — and
   the drift they fed is retired. Removed rather than left as a trap. */

.float-label {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--s-3);
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted);
  padding-bottom: var(--s-2); margin-bottom: var(--s-3);
  border-bottom: 1px solid var(--rule);
}

/* share-of-answer bars, reused by float card + exhibits */
.bars { display: grid; gap: var(--s-3); }
.bar-row { display: grid; grid-template-columns: minmax(4.5rem, auto) 1fr auto; gap: var(--s-3); align-items: center; font-size: var(--t-sm); }
.bar-track { display: block; height: 10px; background: var(--paper-band); border: 1px solid var(--rule); border-radius: var(--r-1); overflow: hidden; }
.bar-fill { display: block; height: 100%; background: var(--ink-2); transform-origin: left center; transform: scaleX(var(--fill, 1)); transition: transform var(--dur-3) var(--ease); }
/* Bars draw on scroll, riding the one reveal pattern rather than adding a second. */
.js [data-reveal] .bar-fill { transform: scaleX(0); }
.js [data-reveal].in-view .bar-fill { transform: scaleX(var(--fill, 1)); }
.bar-row[data-client='true'] .bar-fill { background: var(--absent); }
.bar-row[data-client='true'] .bar-val { color: var(--absent); }
.bar-val { font-weight: 600; text-align: right; }

.score-readout { display: flex; align-items: baseline; gap: var(--s-3); }
.score-readout b { font-family: var(--font-display); font-size: var(--t-2xl); line-height: 1; }
.score-readout span { font-size: var(--t-xs); color: var(--ink-muted); }

.chip-cluster { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.chip {
  font-family: var(--font-mono); font-size: var(--t-xs);
  padding: .25em .6em; border-radius: var(--r-pill);
  border: 1px solid var(--rule-strong); color: var(--ink-2);
}
.chip[data-owner='competitor-owned'] { color: var(--absent); border-color: var(--absent); }

/* ------------------------------------- mechanism in three, under the hero */
/* The fastest "I understand what this is" beat on the page. Deliberately a
   numbered list, deliberately above the statistics band: comprehension first,
   stakes second. */
.section--tight { padding-block: clamp(var(--s-6), 4vw, var(--s-7)); }
/* .mech* retired with the mechanism-in-three band, replaced by the
   absence -> inclusion chain. Nothing renders these classes. */

/* secondary hero link — dual CTA is the category norm */
.capture-alt { margin-top: var(--s-3); font-size: var(--t-sm); }
.capture-alt a { color: var(--ink-2); text-decoration-color: var(--rule-strong); }
.capture-alt a:hover { color: var(--present); }

/* ------------------------------------------------- execution modes ------ */
.modes { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-4); }
.mode {
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-3);
  padding: var(--s-6);
  transition: transform var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-1) var(--ease);
}
.mode:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--ink) 20%, transparent);
  box-shadow: var(--shadow-2);
}
.mode-tag {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); text-transform: uppercase;   /* tier 2 */
  color: var(--present); margin-bottom: var(--s-3);
}
.mode h3 { margin-bottom: var(--s-3); }
/* :not(.mode-tag) — .mode p is (0,1,1) and .mode-tag is (0,1,0), so the
   descendant rule silently won and the tag rendered at --t-sm in --ink-2
   despite declaring neither. Fourth time this specificity shape has bitten
   this file; excluding the class is more durable than raising the label to
   match, because it fails loudly if the markup changes. */
.mode p:not(.mode-tag) { color: var(--ink-2); font-size: var(--t-sm); }
.mode-foot {
  margin-top: var(--s-5); padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  max-width: 62ch; margin-inline: auto; text-align: center;
  font-size: var(--t-sm); color: var(--ink-muted);
}

/* ------------------------------------------------- execution boundary */
/* Deliberately quieter than .mode above it: this is the fine print a buyer
   goes looking for, so it should read as a document, not as another sales
   card. A ledger rule per row, label left, answer right. */
.boundary {
  margin-top: var(--s-7);
  border: 1px solid var(--rule);
  border-radius: var(--r-3);
  background: var(--paper-card);
  padding: var(--s-6);
}
.boundary-head { margin-bottom: var(--s-5); }
.boundary-head h3 { margin-top: var(--s-2); }
.boundary-list { display: grid; gap: 0; }
.boundary-row {
  /* 15rem, not 13: mono at --t-xs with wide tracking wrapped the longer
     labels onto a second line, which broke the ledger's alignment. */
  display: grid; grid-template-columns: 15rem 1fr; gap: var(--s-5);
  padding-block: var(--s-4);
  border-top: 1px solid var(--rule);
}
/* Presentation only. No character of the frozen block's copy is touched — this
   is the shared label treatment the block inherits. */
.boundary-row dt {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); text-transform: uppercase;   /* tier 2 */
  color: var(--present); padding-top: 0.15em;
}
/* margin:0 — the UA stylesheet gives dd a 40px inline start margin, which the
   desktop grid hides but the single-column mobile layout exposed as a stray
   indent under every label. */
.boundary-row dd { margin: 0; color: var(--ink-2); font-size: var(--t-sm); max-width: 58rem; }
.boundary-foot {
  margin-top: var(--s-4); padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  font-size: var(--t-xs); color: var(--ink-muted);
  font-family: var(--font-mono); letter-spacing: var(--tracking-wide);
}

/* ------------------------------------- absence -> inclusion chain ---- */
/* Five steps across, stacking on narrow screens. Each step is a column rather
   than a card: cards would give five equal-weight boxes, and this is a
   SEQUENCE — the eye needs to move along it, not stop at each one. The rule
   between columns carries that movement. */
/* 3 x 2 since the merge took it to six steps. Six across at this container
   width is ~190px a column, which crushes the copy; five across orphaned the
   sixth onto a row of its own. Three reads left-to-right, top-to-bottom, and
   the numbers carry the order regardless. */
.chain { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-6) 0; }
.chain-step { padding: 0 var(--s-5); border-left: 1px solid var(--rule); min-width: 0; }
/* First in each ROW loses its rule, not just the first overall — otherwise the
   second row opens with a divider hanging off nothing. */
.chain-step:nth-child(3n + 1) { border-left: 0; padding-left: 0; }
.chain-step:nth-child(3n) { padding-right: 0; }
/* --brand-deep in light for the same reason as .loss-link a: the step number
   sits on the band's wash, where --present measures 4.38:1 — under AA. This
   was the long-standing marginal recorded as deferred item 7; the resequence
   moved the section to a different point in the gradient, so it is closed
   here with the pass's established token pattern rather than left drifting. */
.chain-n {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); color: var(--brand-deep);
  margin-bottom: var(--s-3);
}
[data-theme='dark'] .chain-n { color: var(--present); }
.chain-step h3 {
  font-size: var(--t-base); line-height: var(--lh-snug);
  margin-bottom: var(--s-3); text-wrap: balance;
}
.chain-figs { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-bottom: var(--s-2); }
.chain-fig b { display: block; font-family: var(--font-display); font-size: var(--t-xl); line-height: 1; }
.chain-fig s { text-decoration: none; display: block; font-size: var(--t-xs); color: var(--ink-muted); margin-top: 2px; }
.chain-def { font-size: var(--t-xs); color: var(--ink-muted); line-height: var(--lh-normal); }
.chain-chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.chain-chips li {
  font-family: var(--font-mono); font-size: var(--t-xs);
  border: 1px solid var(--rule-strong); border-radius: var(--r-2);
  padding: 2px var(--s-2); color: var(--ink-2);
}
/* The competitor-owned source is marked: "you are not on them" reads
   differently once one of them belongs to a competitor. */
.chain-chips li[data-owner='competitor-owned'] { border-color: var(--absent); color: var(--absent); }
.chain-list { display: grid; gap: var(--s-2); font-size: var(--t-sm); color: var(--ink-2); }
.chain-list li { display: grid; grid-template-columns: 10px 1fr; gap: var(--s-2); }
.chain-list li::before { content: ''; width: 6px; height: 1px; background: var(--rule-strong); margin-top: .7em; }
.chain-tally { display: grid; gap: var(--s-2); }
.chain-tally li { display: flex; align-items: baseline; gap: var(--s-2); font-size: var(--t-sm); }
.chain-tally b { font-family: var(--font-display); font-size: var(--t-lg); line-height: 1; min-width: 1.2em; }
.chain-tally span { color: var(--ink-2); }
/* The zero is the point of the step, so it gets the absent treatment rather
   than sitting quietly at the bottom of a list. */
.chain-tally li[data-zero='true'] b, .chain-tally li[data-zero='true'] span { color: var(--absent); font-weight: 600; }
.chain-cadence { font-size: var(--t-sm); color: var(--ink-2); margin-bottom: var(--s-3); }
.chain-return {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--present); display: flex; align-items: center; gap: var(--s-2);
}
.chain-note {
  margin-top: var(--s-3); padding-top: var(--s-3);
  border-top: 1px solid var(--rule);
  font-size: var(--t-xs); color: var(--ink-muted); line-height: var(--lh-normal);
}
.chain-prov { margin-top: var(--s-5); text-align: right; }

/* ------------------------------------------------- the invisible loss */
/* The argument, set above the statistics that evidence it. Larger than body
   copy and narrower than full measure, because it is the one paragraph on this
   page a visitor most needs to actually read. */
.loss { margin-bottom: var(--s-7); max-width: 60rem; }
.loss-lead { font-size: var(--t-md); color: var(--ink); max-width: 54ch; }
.loss-intent {
  margin-top: var(--s-4); padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm); color: var(--ink-2); max-width: 58ch;
}

/* The sourcing promise sits with the figures it describes, in the quiet mono
   the page uses for provenance elsewhere. */
/* A text link, deliberately not a button: this feeds the primary funnel and
   must not compete with the hero CTA for the same click. */
.loss-link { margin-top: var(--s-4); font-size: var(--t-sm); }
/* These two standalone links (this and .capture-alt) were 20px-tall touch
   targets. Inline links inside sentences are exempt from the 24px minimum;
   a link that is its own paragraph is not — and both are conversion paths.
   inline-block + padding-block grows the tap area without moving the text. */
.loss-link a,
.capture-alt a { display: inline-block; padding-block: var(--s-2); margin-block: calc(-1 * var(--s-2)); }
/* --brand-deep, not --present: on a band background with its wash, --present
   measures 4.36:1 against the worst pixel — under AA. --brand-deep clears it
   at ~11:1 and keeps the green. Dark theme keeps --present, where
   --brand-deep would be the failing direction. Both are existing tokens. */
.loss-link a { color: var(--brand-deep); text-decoration-color: var(--brand-deep); }
[data-theme='dark'] .loss-link a { color: var(--present); text-decoration-color: var(--present); }
.loss-sourcing {
  margin-top: var(--s-4);
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--ink-muted); max-width: 62ch; line-height: var(--lh-normal);
}

/* --------------------------------------------- statistics band (§4.4) */
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-6); }
.stat { display: flex; flex-direction: column; gap: var(--s-3); }
.stat-num {
  font-family: var(--font-display); font-weight: var(--display-weight);
  font-size: var(--t-num); line-height: .92; letter-spacing: -.03em;
  color: var(--ink); display: block;
}
.stat-claim { color: var(--ink-2); max-width: 30ch; }
.stat-source {
  margin-top: auto; padding-top: var(--s-3); border-top: 1px solid var(--rule);
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted);
}
.stat-source a {
  color: var(--ink-2); text-decoration: none; display: inline-flex; align-items: center; gap: 4px;
  border-bottom: 1px solid var(--rule-strong);
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.stat-source a:hover { color: var(--present); border-color: var(--present); }
.stat-source svg { width: 10px; height: 10px; flex: 0 0 auto; }

/* Hierarchy pass, stage 2.2 — the hero's method line. Quieter than the sub
   (t-sm, muted) so it reads as method rather than slogan; width capped to
   the sub's own measure. Existing tokens only. */
.hero-method { margin: 0 auto var(--s-6); font-size: var(--t-sm); color: var(--ink-muted); max-width: 52ch; }

/* Hierarchy pass, stage 3 — the proof block's line and label spacing.
   Existing card treatment carries the box; these only set measure and rhythm. */
.proof-line { margin-top: var(--s-3); font-size: var(--t-md); max-width: 60ch; }
.proof-line + .u-provenance { display: block; margin-top: var(--s-3); }

/* The forwardable line in the mini-audit panel (moved from the hero at the
   Session-A stop). Same quiet register as the capture notes it lived among. */
.cta-forward { margin-top: var(--s-4); font-size: var(--t-sm); color: var(--ink-2); }

/* Hierarchy pass, stage 4 — progressive disclosure. The FAQ's measured-height
   idiom generalized: a 0fr grid row that exists only under `.js`, so no-JS
   visitors and machines get everything expanded and no text ever leaves the
   DOM. The global reduced-motion kill zeroes the transition. */
.disclose { display: grid; grid-template-rows: 1fr; transition: grid-template-rows var(--dur-2) var(--ease); }
.js .disclose:not(.is-open) { grid-template-rows: 0fr; }
.disclose > div { overflow: hidden; min-height: 0; }
.disclose-btn {
  display: flex; align-items: center; gap: var(--s-2); width: 100%;
  padding: var(--s-3) 0; background: none; border: 0; border-top: 1px solid var(--rule);
  color: var(--ink-muted); font-size: var(--t-sm); font-weight: 400; text-align: left; cursor: pointer;
  transition: color var(--dur-1) var(--ease);
}
.disclose-btn:hover { color: var(--ink); }
.disclose-sign { display: inline-block; font-family: var(--font-mono); color: var(--present); transition: transform var(--dur-1) var(--ease); }
.disclose-btn[aria-expanded='true'] .disclose-sign { transform: rotate(45deg); }
/* The methodology's compact layer: the six gate names, readable, one line
   that wraps where it must. */
.gate-names { font-family: var(--font-mono); font-size: var(--t-sm); color: var(--ink-2); margin-bottom: var(--s-4); }
/* The contents strip's lead row lives inside its summary now. */
.toc > summary { flex-wrap: wrap; }
.toc-list--lead { flex: 1 1 14rem; padding: 0; }
.toc-list--lead .toc-row { border-top: 0; padding-block: 0; }
.toc > summary .toc-sum { font-family: var(--font-body); font-weight: 400; font-size: var(--t-sm); letter-spacing: 0; text-transform: none; color: var(--ink-muted); }

/* ------------------------------------------- the calculator, one source */
/* Business-case pass. These rules were the calculator page's local <style>;
   they moved here when the landing page gained the compact card, so both
   surfaces render one component. Page-specific context (the /what-ai-answers
   document scale and margins) stays local to that page. Every value is an
   existing token. */
.calc { border: 1px solid var(--rule); border-radius: var(--r-3); background: var(--paper-card); padding: clamp(var(--s-5), 4vw, var(--s-6)); }
.calc-field { display: grid; gap: var(--s-2); }
.calc-field + .calc-field { margin-top: var(--s-5); }
.calc-field label { font-weight: 600; }
.calc-field input {
  font: inherit; color: var(--ink); background: var(--paper);
  border: 1px solid var(--rule-strong); border-radius: var(--r-2);
  padding: .6em .8em; width: 100%; max-width: 16rem;
  font-variant-numeric: tabular-nums;
}
.calc-field input:hover { border-color: var(--ink-muted); }
.calc-hint { font-size: var(--t-sm); color: var(--ink-muted); max-width: 56ch; }
.calc-hint a { color: var(--present); }
/* The third input's helper is the conversion hook — it must render in full at
   every width. In the card's grid it sits in a track that can be narrower
   than its text: min-width:0 lets it wrap instead of overflowing, and
   overflow-wrap catches the long unbroken case. Nothing here truncates:
   no fixed height, no line-clamp, no ellipsis anywhere in this component. */
.calc--card .calc-field { min-width: 0; }
.calc--card .calc-hint { max-width: none; overflow-wrap: anywhere; }
.calc-eg {
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--ink-muted);
}
.calc-out { margin-top: var(--s-6); padding-top: var(--s-5); border-top: 1px solid var(--rule); }
.calc-out-label {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--ink-muted);
}
.calc-figure {
  font-family: var(--font-display); font-size: var(--t-3xl); line-height: 1;
  margin-top: var(--s-3); font-variant-numeric: tabular-nums;
}
/* Reserve the restate's tallest state in em, so live recalculation cannot
   move anything below it at any width — the calculator page's contract,
   measured again for the card (check-card.mjs). */
.calc-restate { margin-top: var(--s-3); color: var(--ink-2); max-width: 56ch; min-height: 5.4em; }
.calc-caveat {
  margin-top: var(--s-5); padding: var(--s-4);
  border: 1px solid var(--rule-strong); border-radius: var(--r-2);
  background: var(--paper-band);
  font-size: var(--t-sm); color: var(--ink-2);
}
.calc-caveat b { color: var(--ink); }
/* The landing-page card variant. */
.calc--card .calc-card-title { margin-top: var(--s-4); }
.calc-card-title { font-size: var(--t-xl); }
.calc-framing { margin-top: var(--s-3); color: var(--ink-2); max-width: 62ch; }
.calc-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-5); margin-top: var(--s-5); }
.calc-grid .calc-field + .calc-field { margin-top: 0; }
.calc--card .calc-field input { max-width: 100%; }
@media (max-width: 900px) {
  /* Stacked, the grid's own gap provides the rhythm — the sibling margin
     stays zeroed or it would double against the gap. */
  .calc-grid { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .calc-restate { min-height: 9em; }
}

/* ------------------------------------------------- the return projection */
/* The #roi block, on the vertical and paid pages. Existing tokens only — no
   new colour, no new spacing step, no new radius.

   ON PLAIN PAPER, NOT A BAND, and that is a contrast decision rather than a
   layout preference. The variants' mid-page capture already paid for this
   lesson: --present on a band's wash measured 4.12:1 on developer-tools light,
   under the AA floor, and .loss-link carries the same note one component up.
   This block leans on --present harder than either of them, so it never sits
   on the wash at all. The card inside supplies the separation the band would
   have.

   Two columns at desk width — inputs left, the answer right — because the
   whole point is that editing the left column moves the right one, and a
   reader who has to scroll between the two cannot see that happen. */
.roi {
  display: grid; grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: clamp(var(--s-5), 4vw, var(--s-7)); align-items: start;
  border: 1px solid var(--rule); border-radius: var(--r-3);
  background: var(--paper-card); padding: clamp(var(--s-5), 4vw, var(--s-6));
}
.roi-inputs { display: grid; gap: var(--s-5); min-width: 0; }
.roi-field { display: grid; gap: var(--s-2); min-width: 0; }
.roi-field label { font-weight: 600; }
.roi-field input {
  font: inherit; color: var(--ink); background: var(--paper);
  border: 1px solid var(--rule-strong); border-radius: var(--r-2);
  padding: .6em .8em; width: 100%;
  font-variant-numeric: tabular-nums;
}
.roi-field input:hover { border-color: var(--ink-muted); }
/* Nothing in this component truncates: no fixed height, no line-clamp, no
   ellipsis. The hint wraps, at every width. */
.roi-hint { font-size: var(--t-sm); color: var(--ink-muted); overflow-wrap: anywhere; }

.roi-out { min-width: 0; }
.roi-out-label {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--ink-muted);
}

/* The movement, as two bars stacked on one scale. Same 10px track, same
   scaleX fill and same transition as .bar-track/.bar-fill in the exhibits —
   this is that idiom at a larger type size, not a second bar component. */
.roi-bars { display: grid; gap: var(--s-3); margin-top: var(--s-4); }
.roi-bar {
  display: grid; grid-template-columns: minmax(5.5rem, auto) 1fr auto;
  gap: var(--s-3); align-items: center; font-size: var(--t-sm);
}
.roi-bar-label { color: var(--ink-2); }
.roi-bar-track {
  display: block; height: 14px; background: var(--paper-band);
  border: 1px solid var(--rule); border-radius: var(--r-1); overflow: hidden;
}
.roi-bar-fill {
  display: block; height: 100%; background: var(--ink-2);
  transform-origin: left center; transform: scaleX(var(--fill, 1));
  transition: transform var(--dur-3) var(--ease);
}
.roi-bar-val { font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
/* The pair carries the argument in colour: where you are, and where the work
   puts you. --absent and --present are the product's own state tokens and are
   used here exactly as the exhibits use them. */
.roi-bar[data-tone='today'] .roi-bar-fill { background: var(--absent); }
.roi-bar[data-tone='today'] .roi-bar-val { color: var(--absent); }
.roi-bar[data-tone='after'] .roi-bar-fill { background: var(--present); }
.roi-bar[data-tone='after'] .roi-bar-val { color: var(--brand-deep); }
[data-theme='dark'] .roi-bar[data-tone='after'] .roi-bar-val { color: var(--present); }

.roi-measured {
  display: block; margin-top: var(--s-3);
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--ink-muted); line-height: var(--lh-normal);
}

/* Two columns, and the lead figure spans both on the row above them. It first
   shipped as three equal columns with the lead in the middle, and at 1440 the
   value broke across two lines mid-number — "+362" over ",880" — which reads
   as two figures rather than one. A display-sized number does not fit a third
   of this container at any width worth having, so it gets the full row. */
.roi-stats {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-5) var(--s-4); margin-top: var(--s-6);
  padding-top: var(--s-5); border-top: 1px solid var(--rule);
}
.roi-stat { min-width: 0; }
.roi-stat-val {
  font-family: var(--font-display); font-weight: var(--display-weight);
  font-size: var(--t-2xl); line-height: 1; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
/* The figure the section exists to state: the statistics band's display size,
   the colour that says "present", and a row to itself.
   NO overflow-wrap here, deliberately — `anywhere` is what allowed the break
   inside the number in the first place. A grouped figure must wrap at a space
   or not at all, and with the full row it has no need to wrap. */
.roi-stat--lead { grid-column: 1 / -1; }
.roi-stat--lead .roi-stat-val { font-size: var(--t-num); color: var(--brand-deep); }
[data-theme='dark'] .roi-stat--lead .roi-stat-val { color: var(--present); }
.roi-stat-label { margin-top: var(--s-2); font-size: var(--t-sm); color: var(--ink-2); }

.roi-method {
  margin-top: var(--s-5);
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--ink-muted); line-height: var(--lh-normal); max-width: 66ch;
}

.roi-cta {
  margin-top: var(--s-6); display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center; gap: var(--s-4);
}
.roi-cta-note { font-size: var(--t-sm); color: var(--ink-2); }

@media (max-width: 900px) {
  /* Stacked, the inputs above the answer they move. */
  .roi { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  /* Even the two supporting figures will not sit side by side at 390 without
     shrinking below the type scale. Stacked, each keeps its size and its
     label, and nothing wraps mid-number. */
  .roi-stats { grid-template-columns: 1fr; gap: var(--s-5); }
  .roi-bar { grid-template-columns: minmax(4.5rem, auto) 1fr auto; }
  .roi-cta { justify-content: flex-start; }
}

/* ------------------------------------------------------------- founder */
.founder-grid { display: grid; grid-template-columns: minmax(0, 260px) minmax(0, 1fr); gap: clamp(var(--s-5), 4vw, var(--s-8)); align-items: start; }
.portrait {
  aspect-ratio: 4 / 5; border: 1px solid var(--rule); border-radius: var(--r-3);
  background: var(--paper-band); display: grid; place-items: center; text-align: center;
  color: var(--ink-muted); font-family: var(--font-mono); font-size: var(--t-xs);
  padding: var(--s-4);
}
.founder-body > * + * { margin-top: var(--s-4); }
.founder-body p { color: var(--ink-2); }
.analyst-identity {
  min-height: 2rem;
  font-family: var(--font-display);
  font-size: var(--t-xl);
  line-height: var(--lh-snug);
}
.analyst-facts {
  display: grid;
  margin: var(--s-5) 0 0;
  border-top: 1px solid var(--rule);
}
.analyst-fact {
  display: grid;
  grid-template-columns: minmax(10rem, .36fr) minmax(0, 1fr);
  gap: var(--s-5);
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--rule);
}
.analyst-fact dt {
  padding-top: .15em;
  color: var(--present);
  font-family: var(--font-mono);
  font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;   /* tier 2 */
}
.analyst-fact dd { margin: 0; color: var(--ink-2); font-size: var(--t-sm); }
/* Two columns again — but the right one is NOT a portrait. The owner's decision
   is anonymous, so the section shows the WORK instead of the person.

   The slot holds its final shape before the artifact exists. That is a reversal
   of the earlier rule and a deliberate one: refusing to reserve space is right
   for a portrait that may never arrive (an empty frame reads as a broken image),
   and wrong for a slot whose content is known to be coming, where reserving is
   the only way to guarantee zero reflow when it lands.

   aspect-ratio rather than a fixed height, so the box reserves its shape at
   every width instead of only at the one it was measured on. */
.analyst-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: clamp(var(--s-5), 4vw, var(--s-7)); align-items: start;
}
.analyst-body > * + * { margin-top: var(--s-4); }
.analyst-body p { color: var(--ink-2); max-width: 60ch; }
.analyst-anchor { margin: 0; }
.analyst-anchor--reserved {
  display: grid; place-items: center;
  aspect-ratio: 4 / 5;
  border: 1px dashed var(--rule-strong); border-radius: var(--r-3);
  background: var(--paper-card);
}
.analyst-anchor--reserved span {
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--ink-muted);
}
.analyst-anchor figcaption { margin-top: var(--s-3); }

/* The review note. Same document chrome as the report exhibits, because it IS
   an artifact from the same system — reading as an illustration would defeat
   the purpose. */
.anchor-doc {
  border: 1px solid var(--rule); border-radius: var(--r-3);
  background: var(--paper-card); overflow: hidden;
}
.anchor-chrome {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--paper-band); border-bottom: 1px solid var(--rule);
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted);
}
.anchor-chrome b { color: var(--ink-2); font-weight: 600; }
.anchor-body { padding: var(--s-5) var(--s-4) var(--s-4); }
.anchor-lbl {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--ink-muted);
}
.anchor-score { display: flex; align-items: baseline; gap: var(--s-2); margin-top: var(--s-2); }
.anchor-score b { font-family: var(--font-display); font-size: var(--t-3xl); line-height: 1; }
.anchor-score s { text-decoration: none; font-size: var(--t-sm); color: var(--ink-muted); }

/* Full 0–100 axis on purpose: the band has to look small, because that is the
   entire point of the judgement it illustrates. */
.anchor-scale {
  position: relative; height: 10px; margin-top: var(--s-4);
  background: var(--paper-band); border-radius: 5px;
}
.anchor-band {
  position: absolute; inset-block: 0; left: var(--lo); width: var(--w);
  background: var(--present-soft); border-radius: 5px;
  border-inline: 1px solid var(--present);
}
.anchor-pin {
  position: absolute; top: -3px; bottom: -3px; left: var(--at); width: 2px;
  background: var(--ink); border-radius: 1px;
}
.anchor-range { margin-top: var(--s-3); font-size: var(--t-xs); color: var(--ink-muted); }
.anchor-range b { font-family: var(--font-mono); color: var(--present); }
.anchor-note {
  margin-top: var(--s-4); padding-top: var(--s-3);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm); color: var(--ink-2);
}
/* .todo is a BUILD-TIME affordance only. Nothing may render it into the live
   page: build-analyst.mjs omits unsupplied fields instead, and a guard fails
   if placeholder text appears in the markup. The rule stays defined so a
   local scratch page can still use it. */
.todo {
  display: inline-block; font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--absent); border: 1px dashed var(--absent); border-radius: var(--r-2);
  padding: .3em .6em;
}

/* --------------------------------------------- service card grid (§4.7) */
.card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4); }
.card {
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-3);
  padding: var(--s-5); box-shadow: var(--shadow-1);
  transition: transform var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-1) var(--ease);
}
.card:hover {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--ink) 20%, transparent);
  box-shadow: var(--shadow-3);
}
.card-icon { width: 30px; height: 30px; color: var(--present); margin-bottom: var(--s-4); }
.card-icon [stroke] { stroke: currentColor; fill: none; stroke-width: 1.4; }
.card h3 { margin-bottom: var(--s-3); }
.card p { color: var(--ink-2); font-size: var(--t-sm); }

/* The step number. The grid was unnumbered while the heading promised six jobs
   AND a loop, so a reader could not see there was an order at all. */
.card-step {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3);
  margin-bottom: var(--s-3);
}
.card-n {
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide); color: var(--ink-muted);
}
/* Only on the sixth card: names where the sequence goes next. */
.card-loop {
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide); color: var(--present);
}

/* ------------------------------------------------------------- the loop */
/* The heading claims a loop and the closing line explains it; until now
   nothing drew it. Six stops on a closed circuit — five on the track, one
   larger at the return point. */
.track-loop {
  margin-top: var(--s-6); padding-top: var(--s-4); border-top: 1px solid var(--rule);
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s-5); align-items: center;
}
.track-foot-copy { color: var(--ink-2); font-size: var(--t-sm); max-width: 62ch; }
.loop-mark { width: 132px; height: 44px; flex: 0 0 auto; color: var(--present); }
/* Was --rule-strong: at 1.4px on a 44px mark the track all but disappeared,
   so the dots read as scattered specks rather than stops on a circuit. */
.loop-track { stroke: currentColor; fill: none; stroke-width: 1.4; opacity: .35; }
.loop-arrow { stroke: currentColor; fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.loop-dot { fill: currentColor; }

/* Transform/opacity only, existing duration and easing tokens, and the dots
   never move the box — so this cannot touch CLS. Each dot brightens in turn,
   which reads as travel around the circuit without animating position. */
.js [data-reveal] .loop-dot { opacity: 0; }
.js [data-reveal].in-view .loop-dot {
  opacity: 1;
  transition: opacity var(--dur-2) var(--ease);
}
/* Markup order follows travel order, so the stagger traces the circuit. */
.js [data-reveal].in-view .loop-dot:nth-of-type(1) { transition-delay: 0ms; }
.js [data-reveal].in-view .loop-dot:nth-of-type(2) { transition-delay: 90ms; }
.js [data-reveal].in-view .loop-dot:nth-of-type(3) { transition-delay: 180ms; }
.js [data-reveal].in-view .loop-dot:nth-of-type(4) { transition-delay: 270ms; }
.js [data-reveal].in-view .loop-dot:nth-of-type(5) { transition-delay: 360ms; }
.js [data-reveal].in-view .loop-dot:nth-of-type(6) { transition-delay: 450ms; }

/* Reduced motion renders the settled frame: everything already at rest. */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] .loop-dot,
  .js [data-reveal].in-view .loop-dot { opacity: 1; transition: none; }
}

/* --------------------------------------------------- exhibits (§5 row 5) */
.exhibit-tabs { display: flex; flex-wrap: wrap; gap: var(--s-1); margin-bottom: var(--s-5); border-bottom: 1px solid var(--rule); }

/* ------------------------------------------ report contents strip (21 rows) */
/* The strip exists to be COUNTED. It renders every navigable section so a
   reader can check "six of 21" against the list, which means the titles have
   to be read rather than skimmed as texture — hence --t-sm, not the --t-xs
   used for other mono labels, and a real row height.
   Collapsed by default: 21 rows above five exhibit pages would bury the
   exhibits, which are the thing being sold. Open is one click and the summary
   states the count, so nothing is hidden. */
.toc {
  margin: calc(var(--s-5) * -1) 0 var(--s-5);
  border: 1px solid var(--rule); border-radius: var(--r-3);
  background: var(--paper-card);
}
.toc > summary {
  cursor: pointer; list-style: none;
  padding: var(--s-3) var(--s-4);
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--ink-2);
  display: flex; align-items: center; gap: var(--s-3);
}
.toc > summary::-webkit-details-marker { display: none; }
.toc > summary::before {
  content: '+'; font-size: var(--t-sm); line-height: 1; color: var(--present);
}
.toc[open] > summary::before { content: '–'; }
.toc > summary:hover { color: var(--ink); }
.toc-list { padding: 0 var(--s-4) var(--s-4); }
.toc-row {
  display: grid; grid-template-columns: 2.75rem minmax(0, 1fr) auto;
  gap: var(--s-3); align-items: baseline;
  padding-block: var(--s-2);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm);
}
.toc-n {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--ink-muted); font-variant-numeric: tabular-nums;
}
.toc-t { color: var(--ink-2); }
/* Marked, not styled differently: the six shown sections have to be countable
   or the claim cannot be checked. Everything else about the row is identical —
   the strip reads as a faithful table of contents, not a highlight reel. */
.toc-mark {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--present); white-space: nowrap;
}
.toc-row[data-shown='true'] .toc-t { color: var(--ink); font-weight: 600; }
.exhibit-tab {
  background: transparent; border: 0; cursor: pointer;
  font-family: var(--font-mono); font-size: var(--t-xs);
  padding: var(--s-3) var(--s-4); color: var(--ink-muted); position: relative;
  transition: color var(--dur-1) var(--ease);
}
.exhibit-tab::after {
  content: ''; position: absolute; inset-inline: var(--s-3); bottom: -1px; height: 2px;
  background: var(--ink); transform: scaleX(0); transform-origin: center;
  transition: transform var(--dur-2) var(--ease);
}
.exhibit-tab[aria-selected='true'] { color: var(--ink); }
.exhibit-tab[aria-selected='true']::after { transform: scaleX(1); }
.exhibit-tab:hover { color: var(--ink); }

.exhibit-stack { display: grid; }
.exhibit {
  grid-area: 1 / 1;
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-3);
  box-shadow: var(--shadow-3); overflow: hidden;
  /* page-turn: the outgoing sheet lifts and fades, the incoming settles down */
  opacity: 0; transform: translateY(8px) scale(.994);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
  pointer-events: none;
}
.exhibit[hidden] { display: block; }        /* stacked, not removed — keeps height stable */
.exhibit.is-current { opacity: 1; transform: none; pointer-events: auto; }

/* No JS: the tabs are dead buttons and four of the five pages were opacity:0
   in a stack — invisible and unreachable, which fails the promise that the
   page reads completely without scripts. The panels flow vertically instead,
   each under its own chrome bar, and the tab strip (which cannot do anything)
   goes away. .js is stamped on <html> before first paint, so this cannot
   flash on JS-enabled loads. */
html:not(.js) .exhibit-tabs { display: none; }
html:not(.js) .exhibit {
  opacity: 1; transform: none; pointer-events: auto; grid-area: auto;
}
html:not(.js) .exhibit + .exhibit { margin-top: var(--s-5); }

.exhibit-chrome {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3);
  flex-wrap: wrap;
  padding: var(--s-3) var(--s-5); border-bottom: 1px solid var(--rule);
  background: var(--paper-band);
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted);
}
.exhibit-chrome b { color: var(--ink); font-weight: 500; }
.exhibit-body { padding: clamp(var(--s-5), 3vw, var(--s-7)); }
.exhibit-body > * + * { margin-top: var(--s-5); }
.exhibit-page { font-variant-numeric: tabular-nums; }

.metric-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--s-5); }
.metric b { display: block; font-family: var(--font-display); font-size: var(--t-2xl); line-height: 1; }
.metric span { display: block; margin-top: var(--s-2); font-size: var(--t-xs); color: var(--ink-muted); }
.metric[data-tone='warn'] b { color: var(--absent); }

.kv { display: grid; gap: var(--s-2); }
.kv-row { display: grid; grid-template-columns: 1fr auto; gap: var(--s-4); align-items: baseline; padding-block: var(--s-2); border-bottom: 1px solid var(--rule); font-size: var(--t-sm); }
.kv-row:last-child { border-bottom: 0; }

.query-list { display: grid; gap: var(--s-2); }
.query-list li { font-family: var(--font-mono); font-size: var(--t-sm); color: var(--ink-2); }

.table-lite { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
.table-lite th, .table-lite td { text-align: left; padding: var(--s-3) var(--s-3); border-bottom: 1px solid var(--rule); }
.table-lite th { font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 500; color: var(--ink-muted); text-transform: lowercase; letter-spacing: var(--tracking-wide); }

/* ------------------------------------------------------ product visual --- */
/* Our own research flagged ZERO images as the single biggest gap against the
   category (Rankscale 644, Athena 298, Brandlight 156). This is the fix.
   width/height are set on the element so the aspect ratio is reserved and the
   lazy load cannot shift layout. */
.shotband { padding-top: 0; }
.shot { margin: 0; }
.shot img {
  display: block; width: 100%; height: auto; max-width: 68rem; margin-inline: auto;
  border: 1px solid var(--rule); border-radius: var(--r-4);
  box-shadow: var(--shadow-3);
}
.shot figcaption { margin-top: var(--s-4); text-align: center; }
/* A light product shot on the dark theme reads as a hole in the page. Two
   images, swapped by theme — the dark one is aria-hidden and alt-empty so the
   text equivalent is announced exactly once. */
/* The two-img display swap that lived here is retired: the shot is one
   <picture> whose dark sources are gated on prefers-color-scheme in markup
   and rewritten to follow data-theme by initTheme. Theme selection happens
   in source negotiation now, not in CSS. */

/* ------------------------------------------------- provider marquee (§4.8) */
.marquee { overflow: hidden; position: relative; }
.marquee::before, .marquee::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 5rem; z-index: 2; pointer-events: none;
}
.marquee::before { left: 0; background: linear-gradient(to right, var(--paper-band), transparent); }
.marquee::after { right: 0; background: linear-gradient(to left, var(--paper-band), transparent); }
.marquee-track {
  display: flex; width: max-content; gap: var(--s-8);
  animation: slide var(--marquee-dur, 32s) linear infinite;
}
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track,
.marquee.is-paused .marquee-track { animation-play-state: paused; }
@keyframes slide { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }
.marquee-item {
  display: flex; align-items: center; gap: var(--s-3);
  font-family: var(--font-display); font-size: var(--t-xl);
  color: var(--ink-2); white-space: nowrap;
}
.marquee-item .dot { width: 5px; height: 5px; border-radius: var(--r-pill); background: var(--present); flex: 0 0 auto; }
.marquee-ctrl {
  position: absolute; right: var(--s-4); bottom: var(--s-2); z-index: 3;
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted);
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-2);
  padding: .2em .5em; cursor: pointer;
}

/* Static under reduced motion. The edge fades must go too — with the track
   parked at translateX(0) they would permanently clip the first item. */
@media (prefers-reduced-motion: reduce) {
  .marquee::before, .marquee::after { display: none; }
  .marquee-track { animation: none !important; flex-wrap: wrap; justify-content: center; width: auto; row-gap: var(--s-4); }
  .marquee-ctrl { display: none; }
}

/* ----------------------------------------- three-column comparison (§5.7) */
.compare { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4); align-items: stretch; }
.compare-col {
  display: flex; flex-direction: column; gap: var(--s-4);
  padding: var(--s-5); border: 1px solid var(--rule); border-radius: var(--r-3);
  background: var(--paper-card);
}
.compare-col[data-tone='ours'] { border-color: var(--present); box-shadow: var(--shadow-2); }
.compare-kicker { font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--ink-muted); }
.compare-col[data-tone='ours'] .compare-kicker { color: var(--present); }
.compare-points { display: grid; gap: var(--s-3); font-size: var(--t-sm); color: var(--ink-2); }
.compare-points li { display: grid; grid-template-columns: 14px 1fr; gap: var(--s-3); }
.compare-points li::before { content: ''; width: 8px; height: 1px; background: var(--rule-strong); margin-top: .62em; }
.compare-col[data-tone='ours'] .compare-points li::before { width: 8px; height: 8px; border-radius: var(--r-pill); background: var(--present); margin-top: .42em; }
.compare-goal { margin-top: auto; padding-top: var(--s-4); border-top: 1px solid var(--rule); font-size: var(--t-sm); font-weight: 600; }

/* ------------------------------------------ methodology gate funnel (§5.8) */
.funnel { display: grid; gap: var(--s-2); }
.gate { display: grid; grid-template-columns: 2.2rem 1fr; gap: var(--s-4); align-items: center; }
.gate-n { font-family: var(--font-mono); font-size: var(--t-xs); color: var(--ink-muted); }
/* The narrowing is expressed by each bar's own width, not by a scale transform —
   scaling the box would distort the label text inside it. */
/* Why the gate exists, set below its bar. Only gate 5 carries one: a rule
   with a stated failure mode is credible, and this is the gate whose claim the
   rest of the methodology leans on hardest. */
/* grid-column 2 — .gate is a two-column grid (number, bar). Dropped in without
   a column it landed in the 2.2rem number track and wrapped to one word per
   line, about thirty lines tall. It belongs under the bar, aligned with it. */
.gate-why {
  grid-column: 2;
  margin-top: calc(var(--s-2) * -1);
  font-size: var(--t-xs); color: var(--ink-muted);
  max-width: 62ch; line-height: var(--lh-normal);
}
.gate-bar {
  position: relative; padding: var(--s-3) var(--s-4);
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-2);
  width: var(--w);
}
.gate-bar > * { display: block; }
.gate-title { font-size: var(--t-sm); font-weight: 600; }
.gate-note { font-size: var(--t-xs); color: var(--ink-muted); margin-top: 2px; }
.gate--out .gate-bar { border-style: dashed; color: var(--ink-muted); }
.gate--final .gate-bar { border-color: var(--present); background: var(--present-soft); }
.funnel-caveat { margin-top: var(--s-4); }

/* ---------------------------------------- numbered process + spine (§4.9) */
.process { position: relative; display: grid; gap: var(--s-6); }
.spine { position: absolute; left: 1.15rem; top: .5rem; bottom: 3.5rem; width: 2px; background: var(--rule); }
.spine-fill {
  position: absolute; inset: 0 0 auto 0; background: var(--present);
  transform-origin: top center; transform: scaleY(var(--progress, 0));
  transition: transform var(--dur-2) var(--ease-linear);
}
.step { position: relative; display: grid; grid-template-columns: 2.4rem 1fr; gap: var(--s-5); align-items: start; }
.step-n {
  display: grid; place-items: center; width: 2.4rem; height: 2.4rem;
  font-family: var(--font-display); font-size: var(--t-lg); line-height: 1;
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-2);
  position: relative; z-index: 1;
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.step.is-active .step-n { border-color: var(--present); color: var(--present); }
.step-body h3 { margin-bottom: var(--s-2); }
.step-body p { color: var(--ink-2); font-size: var(--t-sm); max-width: 52ch; }

/* the re-audit loop: an SVG arc drawn back from step 4 to step 2 */
.loop { position: relative; margin-left: 3.6rem; margin-top: var(--s-2); }
.loop-svg { width: 100%; height: 56px; color: var(--present); overflow: visible; }
.loop-svg path { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-dasharray: 420; stroke-dashoffset: 420; transition: stroke-dashoffset var(--dur-4) var(--ease); }
.in-view .loop-svg path { stroke-dashoffset: 0; }
.loop-label {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-mono); font-size: var(--t-xs); color: var(--present);
  background: var(--present-soft); border: 1px solid var(--present);
  border-radius: var(--r-2); padding: .25em .6em;
}
.loop-note { margin-top: var(--s-3); font-size: var(--t-sm); color: var(--ink-2); max-width: 50ch; }

/* ------------------------------------------- numbered FAQ accordion (§4.10) */
.faq { display: grid; }
.faq-item { border-top: 1px solid var(--rule); }
.faq-item:last-child { border-bottom: 1px solid var(--rule); }
.faq-q {
  display: grid; grid-template-columns: 2.6rem 1fr 1.5rem; gap: var(--s-3);
  align-items: baseline; width: 100%; text-align: left;
  background: transparent; border: 0; cursor: pointer;
  padding: var(--s-5) 0; font-family: var(--font-display);
  font-size: var(--t-lg); font-weight: var(--display-weight); line-height: var(--lh-snug);
  letter-spacing: var(--tracking-tight);
  transition: color var(--dur-1) var(--ease);
}
.faq-q:hover { color: var(--present); }
.faq-n { font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 400; color: var(--ink-muted); }
.faq-sign { position: relative; width: 14px; height: 14px; justify-self: end; align-self: center; }
.faq-sign::before, .faq-sign::after {
  content: ''; position: absolute; inset: 50% 0 auto 0; height: 1.5px; background: currentColor;
  transition: transform var(--dur-2) var(--ease);
}
.faq-sign::after { transform: rotate(90deg); }
.faq-item.is-open .faq-sign::after { transform: rotate(0deg); }
/* grid-template-rows animation — no max-height guessing (§4.10).
   Answers are OPEN by default so that with JS disabled (and for any crawler that
   renders CSS) every answer is visible text. site.js collapses them on init and
   takes over as an accordion. */
.faq-a { display: grid; grid-template-rows: 1fr; transition: grid-template-rows var(--dur-2) var(--ease); }
.js .faq-item:not(.is-open) .faq-a { grid-template-rows: 0fr; }
.faq-a > div { overflow: hidden; }
.faq-a p { padding: 0 0 var(--s-5) 2.6rem; color: var(--ink-2); max-width: 62ch; }

/* -------------------------------------------------------------- pricing */
/* The lowest-commitment audit leads, followed by the three ongoing tiers. */
/* Single column, not two. The two-column form was sized for a one-phrase
   assurance ("14-day money-back.") beside a short note. With real sentences in
   both cells the `auto` track resolved to the first line's min-content width,
   the second column collapsed to zero, and the block pushed the document 36px
   wider than the viewport between roughly 760 and 860px. Stacking removes the
   failure mode rather than re-tuning a track that only fits one copy length. */
.pricing-assurance {
  display: grid;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
  padding: var(--s-4);
  border: 1px solid var(--present);
  border-radius: var(--r-3);
  background: var(--present-soft);
}
.pricing-assurance p { color: var(--ink-2); font-size: var(--t-sm); }
/* display:block — the lead-in is display type at --t-lg while the sentence
   after it is --t-sm, and sharing a line made the size jump read as a mistake.
   On its own line it reads as what it is: the heading of the offer. */
.pricing-assurance strong {
  display: block;
  margin-bottom: var(--s-2);
  color: var(--present);
  font-family: var(--font-display);
  font-size: var(--t-lg);
  line-height: var(--lh-snug);
}
.pricing-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4); align-items: stretch; }
.plan--wide { margin-bottom: var(--s-5); }
.plan--entry { border-color: var(--present); box-shadow: var(--shadow-1); }
.plan-wide-head { display: flex; gap: var(--s-6); justify-content: space-between; align-items: center; flex-wrap: wrap; }
.plan-wide-copy { flex: 1 1 26rem; min-width: 0; }
.plan-wide-copy > p:last-child { color: var(--ink-2); font-size: var(--t-sm); margin-top: var(--s-3); max-width: 60ch; }
.plan-wide-buy { display: flex; align-items: center; gap: var(--s-5); flex-wrap: wrap; }
.plan-wide-buy .plan-price { margin: 0; }
.pricing-start {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin: 0 0 var(--s-6);
  border-block: 1px solid var(--rule);
}
.pricing-start > div { padding: var(--s-4); }
.pricing-start > div + div { border-left: 1px solid var(--rule); }
.pricing-start dt {
  margin-bottom: var(--s-2);
  color: var(--ink-muted);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: lowercase;
}
.pricing-start dd { margin: 0; color: var(--ink-2); font-size: var(--t-sm); }
.pricing-divider {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
  color: var(--ink-muted);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: lowercase;
}
.pricing-divider::after { content: ''; flex: 1; height: 1px; background: var(--rule); }
.pricing-grid { display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr); gap: var(--s-5); align-items: start; }
.plan {
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-3);
  padding: clamp(var(--s-5), 3vw, var(--s-7));
}
.plan--featured { border-color: var(--brand); box-shadow: var(--shadow-3); position: relative; }
.plan-badge {
  position: absolute; top: calc(-1 * var(--s-3)); left: var(--s-5);
  font-family: var(--font-mono); font-size: var(--t-xs);
  background: var(--brand); color: var(--paper-card);
  padding: .2em .6em; border-radius: var(--r-2);
}
.plan-name { font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--ink-muted); }
.plan-price { display: flex; align-items: baseline; gap: var(--s-2); margin-block: var(--s-3) var(--s-4); }
.plan-price b { font-family: var(--font-display); font-size: clamp(2.4rem, 1.6rem + 2.4vw, 3.4rem); line-height: 1; letter-spacing: -.03em; }
.plan-price span { color: var(--ink-muted); }
.plan p:not(.plan-name) { color: var(--ink-2); font-size: var(--t-sm); }
.plan-features { display: grid; gap: var(--s-3); margin-block: var(--s-5); font-size: var(--t-sm); }
.plan-features li { display: grid; grid-template-columns: 16px 1fr; gap: var(--s-3); align-items: start; }

/* Access is deliberately quieter than the deliverables above it: the dashboard
   is what you get IN ADDITION to the reporting, not a peer to it. Separated by
   a rule, labelled, muted, and never first. */
.plan-access-label {
  margin-top: var(--s-5); padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  font-family: var(--font-mono); font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide); text-transform: lowercase;
  color: var(--ink-muted);
}
.plan-features--access { margin-top: var(--s-3); color: var(--ink-2); }
.plan-features--access .tick { color: var(--ink-muted); }

.plan-features--out { margin-top: var(--s-4); color: var(--ink-muted); }
.plan-features--out li { grid-template-columns: 16px 1fr; }
.cross { color: var(--absent); font-size: .8em; line-height: 1.5; }
.tick { width: 14px; height: 14px; color: var(--present); margin-top: .28em; }
.tick [stroke] { stroke: currentColor; fill: none; stroke-width: 2; }
.plan-foot { margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--rule); font-size: var(--t-sm); color: var(--ink-muted); }
.ladder { display: grid; gap: var(--s-4); }
.ladder .plan { padding: var(--s-5); }
.ladder .plan-price b { font-size: var(--t-xl); }

.deliver-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-5); }
.deliver-col h3 { font-size: var(--t-base); font-family: var(--font-body); font-weight: 600; margin-bottom: var(--s-4); display: flex; align-items: center; gap: var(--s-2); }
.deliver-col ul { display: grid; gap: var(--s-3); font-size: var(--t-sm); color: var(--ink-2); }
.deliver-col--out li { color: var(--ink-muted); }
.deliver-col--out li::before { content: '\2715'; color: var(--ink-muted); margin-right: var(--s-3); font-size: .8em; }
.honesty {
  margin-top: var(--s-5); padding: var(--s-4);
  border: 1px solid var(--present); border-radius: var(--r-2);
  background: var(--present-soft); color: var(--present);
  font-weight: 600; font-size: var(--t-sm);
}

/* ------------------------------------------------------------- the form */
.cta-panel {
  position: relative; overflow: hidden;
  background: var(--paper-card); border: 1px solid var(--rule); border-radius: var(--r-4);
  padding: clamp(var(--s-5), 4vw, var(--s-8)); box-shadow: var(--shadow-3);
}
.cta-panel::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 70%;
  background: var(--wash-cta); pointer-events: none;
}
.cta-panel > * { position: relative; }
.audit-includes { display: grid; gap: var(--s-3); margin-block: var(--s-5); font-size: var(--t-sm); }
.audit-includes li { display: grid; grid-template-columns: 16px 1fr; gap: var(--s-3); align-items: start; }
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-4); }
.field { display: grid; gap: var(--s-2); }
.field--full { grid-column: 1 / -1; }
.field label { font-size: var(--t-sm); font-weight: 600; }
.field .req { color: var(--absent); }
.field .hint { font-weight: 400; color: var(--ink-muted); }
.field input, .field select, .field textarea {
  font: inherit; color: var(--ink); background: var(--paper);
  border: 1px solid var(--rule-strong); border-radius: var(--r-3);
  padding: .7em .9em; width: 100%;
  transition: border-color var(--dur-1) var(--ease);
}
.field textarea { resize: vertical; min-height: 5.5rem; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--ink-muted); }
.field.has-error input, .field.has-error select { border-color: var(--absent); }
.field-error { font-size: var(--t-xs); color: var(--absent); min-height: 1em; }
.form-disclaimer { margin-top: var(--s-4); font-size: var(--t-xs); color: var(--ink-muted); }

/* --- optional-field disclosure ------------------------------------------
   Reads as a rule with a label rather than a second button competing with
   the submit, which is the only thing in this panel that should look like a
   button. */
.form-more {
  display: flex; align-items: center; gap: var(--s-2);
  width: 100%; margin-top: var(--s-4); padding: var(--s-3) 0;
  background: none; border: 0; border-top: 1px solid var(--rule);
  color: var(--ink-muted); font-size: var(--t-sm); text-align: left; cursor: pointer;
  transition: color var(--dur-1) var(--ease);
}
.form-more:hover { color: var(--ink); }
.form-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.form-more-sign {
  display: inline-block; font-family: var(--font-mono); color: var(--accent);
  transition: transform var(--dur-1) var(--ease);
}
.form-more[aria-expanded='true'] .form-more-sign { transform: rotate(45deg); }
#form-optional { margin-top: var(--s-4); }
/* .form-grid sets display:grid, which outranks the UA [hidden] rule — without
   this the group never hides. */
#form-optional[hidden] { display: none; }
/* This sheet has no blanket transition kill — reduced motion is handled per
   component — so the sign needs its own. It still lands at 45°, just without
   travelling there. */
@media (prefers-reduced-motion: reduce) {
  .form-more-sign { transition: none; }
}
.form-submit-error { margin-top: var(--s-3); font-size: var(--t-sm); color: var(--absent); }
.form-success { text-align: center; }
.form-success h3 { margin-bottom: var(--s-3); }
.form-success p { color: var(--ink-2); }

/* ---- the booking offer, inside the success state ------------------------
   THE LAYOUT RULE, stated because it is the whole design constraint: a
   visitor who reads only the first line must understand their audit is
   coming. So the offer is a THIRD tier, below the h3 and below the delivery
   promise — separated by a rule, dropped to --t-sm, and rendered as a text
   link rather than a button. The precedent is .loss-link, which exists for
   the same reason: a secondary path that must not compete with the primary
   CTA for the same click. Nothing here may suggest the call is required.

   No new tokens. Every colour, size, space and rule below already exists. */
.form-booking {
  margin-top: var(--s-5);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm);
  color: var(--ink-2);
}
.form-booking-cta { margin-top: var(--s-3); font-size: var(--t-sm); }
/* Same tap-target reasoning as .loss-link: a link that is its own paragraph
   is not exempt from the 24px minimum, and this one is a conversion path. */
.form-booking-cta a {
  display: inline-block;
  padding-block: var(--s-2);
  margin-block: calc(-1 * var(--s-2));
  color: var(--brand-deep);
  text-decoration-color: var(--brand-deep);
}
[data-theme='dark'] .form-booking-cta a { color: var(--present); text-decoration-color: var(--present); }

/* NOT fine print, and deliberately NOT quieter than the offer above it.
   This is the sentence that stops the offer reading as a condition of the
   free audit, so it carries the same size and the same ink as the offer —
   --ink-muted or --t-xs here would be softening the promise by stylesheet.
   It is never visually hidden, never collapsed, never behind a disclosure. */
.form-booking-note { margin-top: var(--s-3); font-size: var(--t-sm); color: var(--ink-2); }

/* --------------------------------------------------------------- footer */
.site-footer { background: var(--paper-band); border-top: 1px solid var(--rule); padding-block: var(--s-8) var(--s-6); }
.footer-grid { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: var(--s-6); }
.footer-tag { margin-top: var(--s-3); color: var(--ink-2); font-size: var(--t-sm); max-width: 34ch; }
.footer-nav { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-1) var(--s-3); font-size: var(--t-sm); }
/* padding-block, not height: the links were 22px-tall text with 12px gaps.
   That squeaks past WCAG 2.5.8 on the spacing exception, but nine cramped
   targets at the bottom of a phone screen is exactly where mis-taps happen —
   and the hamburger nav already pads its own links to 54px for this reason.
   The row gap above drops to s-1 so the padded boxes keep the same visual
   rhythm while the tap area grows to ~38px. */
.footer-nav a { text-decoration: none; color: var(--ink-2); padding-block: var(--s-2); }
.footer-nav a:hover { color: var(--ink); }
.footer-bottom { margin-top: var(--s-7); padding-top: var(--s-4); border-top: 1px solid var(--rule); font-size: var(--t-xs); color: var(--ink-muted); display: flex; justify-content: space-between; gap: var(--s-4); flex-wrap: wrap; }

.sticky-cta { display: none; }

/* ----------------------------------------------------------- responsive */
@media (max-width: 1000px) {
  .modes { grid-template-columns: 1fr; }
  /* Label above answer — a 13rem column leaves too little for the sentence. */
  .boundary-row { grid-template-columns: 1fr; gap: var(--s-2); }
  .boundary { padding: var(--s-5); }
  .hero-copy { max-width: 34rem; }
  .hero-stage { grid-template-columns: 1fr; gap: var(--s-4); }
  .hero-stage .float { margin-top: 0 !important; }
  .hero-stage { min-height: 22rem; }
  .card-grid { grid-template-columns: repeat(2, 1fr); }
  .stats { grid-template-columns: 1fr; gap: var(--s-7); }
  .stat-source { margin-top: var(--s-2); }
  .compare { grid-template-columns: 1fr; }
  .pricing-grid { grid-template-columns: 1fr; }
  .pricing-3 { grid-template-columns: 1fr; }
}
/* 1060, measured, not guessed — and moved twice for the same reason: the menu
   text got longer. At 900 the six items wrapped from ~930px down; at 1000 the
   "Why it matters" rename left a wrapped band at 1001–1029. The menu fits from
   1030; 1060 leaves margin for font fallback variance. If a label changes
   again, re-measure — the guard on nav order will not catch a wrap. The
   sticky CTA keeps its own 900px breakpoint below; it is a conversion
   decision, not a layout constraint. */
@media (max-width: 1060px) {
  .nav-toggle { display: grid; }
  .primary-nav {
    position: fixed; inset: var(--header-h) 0 auto 0; z-index: 99;
    flex-direction: column; align-items: stretch; gap: 0;
    margin: 0; padding: var(--s-4) var(--s-5) var(--s-6);
    background: var(--paper); border-bottom: 1px solid var(--rule); box-shadow: var(--shadow-3);
    transform: translateY(-10px); opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease), visibility var(--dur-2);
  }
  .primary-nav.is-open { transform: none; opacity: 1; visibility: visible; pointer-events: auto; }
  .nav-menu { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-menu a { padding: var(--s-4) 0; border-bottom: 1px solid var(--rule); font-size: var(--t-md); }
  .nav-menu a::after { display: none; }
  .primary-nav .btn { margin-top: var(--s-4); }
  .deliver-grid { grid-template-columns: 1fr; }
  /* Two across between 620 and 1000: three columns here is ~230px each, which
     wraps every step title and pushes the query list to one word a line. */
  .chain { grid-template-columns: repeat(2, 1fr); }
  .chain-step:nth-child(3n),
  .chain-step:nth-child(3n + 1) { padding: 0 var(--s-5); }
  .chain-step:nth-child(odd) { border-left: 0; padding-left: 0; }
  .chain-step:nth-child(even) { border-left: 1px solid var(--rule); padding-right: 0; }
}
/* Kept at 900 deliberately when the nav moved to 1000: whether the menu
   collapses is a layout constraint, whether a persistent CTA follows the
   reader is a conversion decision. They were in one block by coincidence. */
@media (max-width: 900px) {
  .sticky-cta {
    display: block; position: fixed; left: var(--s-4); right: var(--s-4); bottom: var(--s-4); z-index: 90;
    text-align: center; text-decoration: none; padding: .9em 1em;
    background: var(--ink); color: var(--paper-card); border-radius: var(--r-3);
    box-shadow: var(--shadow-3);
    transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
  }
  .sticky-cta.is-hidden { opacity: 0; transform: translateY(8px); pointer-events: none; }
}

@media (max-width: 620px) {
  /* Side by side at 390px the button is too narrow and breaks mid-word
     ("Get a free mini- audit"). Stacking keeps both full width and legible. */
  .capture-row { flex-direction: column; }
  .capture-row .btn { width: 100%; }
  .founder-grid { grid-template-columns: 1fr; }
  .portrait { max-width: 220px; }
  .analyst-fact { grid-template-columns: 1fr; gap: var(--s-2); }
  /* .pricing-assurance is single-column at every width now — the override that
     used to live here is redundant. */
  .pricing-start { grid-template-columns: 1fr; }
  .pricing-start > div + div { border-left: 0; border-top: 1px solid var(--rule); }
  .card-grid { grid-template-columns: 1fr; }
  /* The circuit stacks above its sentence rather than shrinking beside it —
     at 132px wide it would otherwise squeeze the copy to a few words a line. */
  .track-loop { grid-template-columns: 1fr; gap: var(--s-4); }
  /* The "shown · page NN" marker drops below its title rather than competing
     with it for a narrow line — the title is the thing being read. */
  .toc-row { grid-template-columns: 2.25rem minmax(0, 1fr); }
  .toc-mark { grid-column: 2; }
  /* The artifact stacks under the copy and stops reserving a tall box on a
     narrow screen, where 4:5 would push the rows most of a viewport down. */
  .analyst-grid { grid-template-columns: 1fr; }
  .analyst-anchor--reserved { aspect-ratio: 16 / 9; max-width: 26rem; }
  /* The chain stacks and its rule moves to the top of each step, so the
     sequence still reads as one run rather than six separate blocks. */
  .chain { grid-template-columns: 1fr; gap: var(--s-5); }
  /* :nth-child(n) matches every step at (0,2,0) — the tablet block above sets
     borders via :nth-child(odd)/(even) at that same specificity, and a bare
     .chain-step reset here (0,1,0) would lose to them. Fifth occurrence of a
     specificity collision on this sheet; matching the weight is the fix. */
  .chain-step:nth-child(n) {
    border-left: 0; padding: var(--s-4) 0 0; border-top: 1px solid var(--rule);
  }
  .chain-step:first-child { padding-top: 0; border-top: 0; }
  .form-grid { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr; }
  .hero-stage { min-height: 0; gap: var(--s-3); }
  /* The dissection stacks: query, connector, then the three measurements in
     reading order. Three across at 390px is ~110px a card, which breaks the
     bar rows into two lines each and loses the comparison the figure exists
     to make. The old `transform: none` and `.float-inner { animation: none }`
     here were for the retired drift and parallax; the sequence is transform
     -driven, so a blanket reset would have fought it. */
  .stage-row { grid-template-columns: 1fr; gap: var(--s-3); }
  .hero-stage .float--q { width: 100%; }
  .marquee-item { font-size: var(--t-lg); }
  .gate { grid-template-columns: 1.6rem 1fr; gap: var(--s-3); }
  .gate-bar { width: auto; transform: none; }
  .gate-bar > * { transform: none; }
}

