/* landing.css — the marketing page, on the app's tokens (WP4.5).
 *
 * WHAT MOVED AND WHY IT IS NOT A RE-SKIN. This page shipped as one 350-line
 * <style> block holding its own 13-name palette: --bg, --bg-soft, --pine,
 * --ink, --body-c, --faint, --line, --green, --rose... Those names are the
 * ANCESTORS of tokens.css's light theme — the light palette was authored from
 * this page's hex list — so the port is a re-pointing, not a re-solve. Where a
 * value differs it is because WP2.5 moved the shared token for a measured
 * contrast reason, and the landing inherits that fix rather than keeping its
 * own copy of the bug:
 *
 *   --body-c #6F7370 -> --ink-body   #4E5253   (4.46 -> 7.32:1 on --surface-2)
 *   --faint  #A6A9A5 -> --ink-faint  #6E716E   (2.20 -> 4.57:1)
 *   --rose   #C4756B -> --data-neg   #8B1E1C   (3.19 -> 8.45:1)
 *
 * --data-neg moved AGAIN in WP5, off the rose entirely and onto a
 * conventional red, because the app's audience reads red as down and a dusty
 * rose reads as a design choice. The landing inherits that too, which is the
 * point of the port: this page's negatives and the product's negatives are
 * one decision.
 *
 * So the captions, the marquee, the big ticker and the pill text are all
 * DARKER than they were. That is the visible cost of the ratified position
 * (tokens.css, WP2.5 note): quiet is carried by size and weight, not by fading
 * text out until it fails a legibility floor.
 *
 * THIS FILE KEEPS ITS OWN TYPE SCALE, and only this file may. R2.2 fixes five
 * sizes for the APP, where every panel is a dense instrument; a landing page
 * whose h1 is --t-display (1.35rem) is not a landing page. The scale lives
 * here as literals rather than as tokens because a token would be reachable
 * from the app, which is the thing R2.2 is protecting. Colour has no such
 * escape hatch — every colour below is a var() into tokens.css (R1.1).
 *
 * THE THREE THINGS THE PINE ACCENT COULD NOT DO IN DARK, and the one rule that
 * fixed all three. --pine is a brand FILL that stays dark in both themes, so
 * anything using it as INK (the stat numbers, the section icons, the arrow
 * links, the wordmark) rendered dark-on-dark. R3.11 independently forbids
 * --pine on a link state, and the fix it dictates — promote the neutral ramp —
 * is the same fix the dark theme needs. So pine survives as a SURFACE (buttons,
 * the footer, the avatar, the send key) with --on-pine on top of it, and every
 * former pine-as-ink site is now on the ink ramp. Nothing was locked to light.
 */

/* --landing-max / --landing-pad are R1.4 pass-throughs: page geometry shared by
   a dozen rules that must stay in step, carrying no colour and no theme. The
   allowlist entry with its trip condition lives in tests/test_web_tokens.py. */
:root {
  --landing-max: 1160px;
  --landing-pad: clamp(20px, 3vw, 48px);
}

* { box-sizing: border-box }
html { scroll-behavior: smooth }
/* font-size stays OFF the root — a rem here re-bases every rem below it, which
   is the defect WP4.4b found on six app sheets. See tokens.css / R2.2. */
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
p { margin: 0; color: var(--ink-body) }
a { color: inherit; text-decoration: none }
img, svg { display: block; max-width: 100% }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px }

/* Editorial display scale — this page only. See the header note. */
h1, h2, h3, h4, .serif {
  font-family: var(--font-display); font-weight: 500;
  font-variation-settings: 'opsz' 60;
  letter-spacing: -.012em; line-height: 1.08; margin: 0; color: var(--ink);
}
h1 { font-size: clamp(2.9rem, 5.6vw, 4.4rem); font-weight: 400; line-height: 1.06 }
h2 { font-size: clamp(2.1rem, 3.6vw, 3rem); font-weight: 400; line-height: 1.12 }
h3 { font-size: clamp(1.5rem, 2.1vw, 1.8rem); line-height: 1.22 }
h4 { font-size: 1.45rem }

.mono-label {
  font-family: var(--font-data); font-size: .72rem; font-weight: 400;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint);
}

/* ---- framed column: full-height hairlines ---- */
.rail { max-width: var(--landing-max); margin: 0 auto;
  border-left: 1px solid var(--line); border-right: 1px solid var(--line) }
.pad { padding-inline: var(--landing-pad) }

/* ---- buttons ----
   The hover moves BRIGHTNESS, not hue. R3.11 bans a hue on an interaction
   state, and the two neutral moves that would pass the lint both break a
   theme: --ink turns a pine button near-white in dark, under --on-pine text.
   brightness() is the same non-colour channel as opacity/weight and is the
   only one that reads as "lighter pine" against paper AND against #0C0F11. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px 26px; border-radius: var(--r-ctl); font-size: .95rem;
  font-weight: 500;
  background: var(--pine); color: var(--on-pine); border: 1px solid var(--pine);
  cursor: pointer; transition: filter var(--dur-ui) var(--ease);
}
.btn:hover { filter: brightness(1.35) }
.btn--quiet { background: transparent; color: var(--ink); border-color: var(--line) }
.btn--quiet:hover { background: var(--surface-2); filter: none }

/* The theme control. mountThemeToggle() writes the label, so it says what you
   will GET, not what you have — and it is the only nav item whose text changes. */
.theme-toggle {
  padding: 10px 16px; font-family: var(--font-data); font-size: var(--t-label);
  letter-spacing: var(--label-tracking); text-transform: uppercase;
}

.arrow-link { display: inline-flex; align-items: center; gap: 7px;
  font-size: .95rem; font-weight: 500; color: var(--ink);
  border-bottom: 1px solid var(--line); padding-bottom: 2px }
.arrow-link:hover { border-color: var(--ink) }

/* ---- eyebrow row: LABEL ..... 001 ---- */
.eyebrow { display: flex; justify-content: space-between; align-items: center;
  padding-block: 22px; border-bottom: 1px solid var(--line) }

/* ---- section header: serif left, gray right ---- */
.sec-head { display: grid; grid-template-columns: 1.15fr .85fr; gap: 48px;
  align-items: start; padding-block: clamp(48px, 6vw, 80px) clamp(36px, 4vw, 56px) }
.sec-head .right { padding-top: 10px; max-width: 40ch; justify-self: end }
.sec-head .right p { font-size: .98rem }
.sec-head .right .arrow-link { margin-top: 18px }

/* ============================================================
   STUDY NOTE
   ============================================================ */
/* The strip that says this page's figures are drawn rather than read.
   It sits ABOVE the sticky nav and is deliberately NOT sticky itself: it is a
   statement about the document, made once, not a warning that has to chase the
   reader down the page.
   --warn for the rule and --surface-2 for the ground, so it reads as a notice
   in both themes without introducing a colour. It is not an ERROR state — the
   page is working exactly as intended — so the amber is a 3px edge rather than
   a fill, which is the same weight `.pill--stale` carries elsewhere. */
.studynote { border-bottom: 1px solid var(--line);
  border-top: 3px solid var(--warn); background: var(--surface-2) }
.studynote p { max-width: var(--landing-max); margin: 0 auto;
  padding: var(--sp-3) var(--landing-pad);
  font-size: var(--t-body); line-height: 1.5; color: var(--ink-body) }
.studynote b { color: var(--ink) }
.studynote a { color: var(--ink); text-decoration: underline;
  text-underline-offset: 2px }

/* ============================================================
   NAV
   ============================================================ */
/* The blur bar is --bg at 92%, mixed rather than declared, so it follows the
   theme instead of pinning paper-white behind a dark page. */
.nav { position: sticky; top: 0; z-index: 60;
  background: color-mix(in oklab, var(--bg) 92%, transparent);
  backdrop-filter: blur(12px); border-bottom: 1px solid var(--line) }
.nav-in { max-width: var(--landing-max); margin: 0 auto;
  padding-inline: var(--landing-pad);
  display: flex; align-items: center; height: 78px; gap: 40px }
.mark { display: flex; align-items: center; gap: 10px; font-weight: 600;
  font-size: 1.1rem; letter-spacing: -.02em; color: var(--ink) }
.mark i { width: 19px; height: 19px; border-radius: 50%; background: var(--ink);
  position: relative; flex: none }
.mark i:after { content: ""; position: absolute; inset: 4px 4px 4px 9px;
  background: var(--bg); border-radius: 0 9px 9px 0 }
.nav nav { display: flex; gap: 34px; font-size: .95rem; color: var(--ink-body);
  margin: 0 auto }
.nav nav a:hover { color: var(--ink) }
.nav .btn { padding: 12px 22px }
.nav-actions { display: flex; align-items: center; gap: 10px }

/* ============================================================
   HERO — text left, instrument panel right
   ============================================================ */
.hero { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 4vw, 64px);
  align-items: center; padding-block: clamp(56px, 7vw, 110px) }
.hero .sub { margin: 26px 0 40px; max-width: 44ch; font-size: 1.06rem }

.instrument { position: relative; padding: 34px 26px 40px;
  background:
    radial-gradient(ellipse 65% 55% at 55% 45%,
      color-mix(in oklab, var(--pine) 6%, transparent), transparent 70%),
    radial-gradient(circle, var(--line-strong) 1.1px, transparent 1.3px);
  background-size: auto, 26px 26px;
}
/* corner brackets */
.instrument:before, .instrument:after,
.instrument .bk:before, .instrument .bk:after {
  content: ""; position: absolute; width: 14px; height: 14px;
  border: 0 solid var(--line-strong) }
.instrument:before { top: 0; left: 0; border-top-width: 1px; border-left-width: 1px }
.instrument:after { top: 0; right: 0; border-top-width: 1px; border-right-width: 1px }
.instrument .bk:before { bottom: 0; left: 0; border-bottom-width: 1px; border-left-width: 1px }
.instrument .bk:after { bottom: 0; right: 0; border-bottom-width: 1px; border-right-width: 1px }

.inst-top { display: flex; justify-content: space-between; margin-bottom: 36px }
.live { display: inline-flex; align-items: center; gap: 7px }
/* "Live" means the feed is being observed right now, which is what
   --accent-measured says everywhere else in the product. */
.live i { width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent-measured); animation: pulse 2s ease-in-out infinite }
@keyframes pulse { 0%, 100% { opacity: 1 } 50% { opacity: .3 } }

/* z-index because .inst-cards below is `position:relative`, so it paints over
   an absolutely-positioned sibling that comes EARLIER in the DOM. The lower
   pill — the residual, the one amber signal in the hero — was underneath the
   Exports card. */
.float-pill { position: absolute; z-index: 2; font-family: var(--font-data);
  font-size: .7rem;
  letter-spacing: .08em; padding: 5px 11px; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--line);
  color: var(--ink-body); box-shadow: var(--shadow-panel) }
.float-pill--a { top: 64px; right: 6px }
.float-pill--b { top: 96px; right: -4px }
/* R3.13 — amber, and the selector names the fault. The residual IS the
   unexplained barrel; it is the one number on this mock that is a warning.
   NO TINTED GROUND, and that is an R3.10 measurement, not taste. A
   `color-mix(--warn 10%, --surface)` behind --warn text reads 4.31:1 in light
   — a FAIL — because --warn is fitted to 4.56:1 on --surface-2 and has no
   headroom to spend on decorating its own background. --warn on plain
   --surface is 4.93:1. The border carries the alarm instead: it is non-text,
   so its floor is 3:1, and it clears at the same 4.93. */
.float-pill--resid { color: var(--warn); border-color: var(--warn) }

.inst-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  position: relative }
.icard { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel); padding: 14px 13px; box-shadow: var(--shadow-panel) }
.icard .t { font-family: var(--font-data); font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: 10px }
.icard .r { font-family: var(--font-data); font-size: .75rem; color: var(--ink-body);
  margin-bottom: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.icard .r.matched { color: var(--accent-measured-ink) }
/* "Dock nr. capacity" is the model's own HIGH utilisation flag, so it wears the
   same amber and the class is named after the state (R3.13). */
.icard .r.high { color: var(--warn) }

.ask { margin-top: 22px; display: flex; align-items: center; gap: 12px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-pill);
  padding: 9px 9px 9px 20px; box-shadow: var(--shadow-panel) }
/* `.typed`, not `.q`, AND THAT IS A BUG FIX, NOT A RENAME FOR TIDINESS.
   `.q` named two unrelated things in one sheet — this hero line and the three
   rotating evidence quotes 600 lines down. `.ask .q` (0,2,0) beat `.q` (0,1,0)
   on every property it declared, but it declared no `position` and no
   `opacity`, so #askText silently took `position:absolute; inset:0; opacity:0`
   from the quote rule: the typing animation rendered at 7% over the whole
   instrument panel instead of inside its own pill, overlapping the eyebrow.
   Measured 2026-08-08 — .ask .q's box was 507x343 (the panel) against .ask's
   455x58. Present since the page was written; a collision like this survives
   review because both halves look correct in isolation. */
.ask .typed { flex: 1; font-size: .92rem; color: var(--ink-body); min-height: 1.4em;
  white-space: nowrap; overflow: hidden }
.ask .typed:after { content: ""; display: inline-block; width: 1px; height: 1em;
  background: var(--ink); margin-left: 2px; vertical-align: -2px;
  animation: blink 1.1s step-end infinite }
@keyframes blink { 50% { opacity: 0 } }
.ask .send { width: 38px; height: 38px; border-radius: 50%; background: var(--pine);
  color: var(--on-pine); display: grid; place-items: center; flex: none; font-size: 15px }

/* ============================================================
   SOURCE STRIP — full-bleed marquee
   ============================================================ */
.strip { background: var(--surface-2); border-block: 1px solid var(--line);
  padding-block: 30px; overflow: hidden }
/* The mask needs an OPAQUE stop, not a colour: `#000` here was never painted,
   it was the alpha channel. --ink is opaque in both themes and says so. */
.marq { -webkit-mask-image: linear-gradient(90deg, transparent, var(--ink) 10%,
    var(--ink) 90%, transparent);
  mask-image: linear-gradient(90deg, transparent, var(--ink) 10%,
    var(--ink) 90%, transparent) }
.marq ul { display: flex; gap: 72px; align-items: center; list-style: none;
  margin: 0; padding: 0; width: max-content; animation: slide 36s linear infinite }
.marq li { font-family: var(--font-display); font-size: 1.25rem;
  color: var(--ink-faint); white-space: nowrap; font-weight: 500; letter-spacing: .01em }
@keyframes slide { to { transform: translateX(-50%) } }

/* ============================================================
   CAPABILITIES 001
   ============================================================ */
.flow-panel { background: var(--surface-2); border-block: 1px solid var(--line);
  padding: clamp(48px, 6vw, 84px) var(--landing-pad) }
.flow { display: flex; align-items: center; justify-content: center; gap: 0; flex-wrap: wrap }
.chip { display: inline-flex; align-items: center; gap: 9px; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-panel); padding: 12px 18px;
  font-size: .98rem; color: var(--ink-body); position: relative }
.chip.on { background: var(--surface); color: var(--ink); font-weight: 500;
  box-shadow: var(--shadow-panel) }
/* The glyph is decorative — the chip's LABEL carries the claim — so --bg on the
   measured green is a mark, not a text pair. It inverts with the theme, which a
   literal white could not. */
.chip .ck { width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent-measured); color: var(--bg);
  display: grid; place-items: center; font-size: 10px; flex: none }
.chip .pin { color: var(--ink) }
.chip.dim { color: var(--ink-faint) }
.conn { width: clamp(14px, 3vw, 42px); height: 1px; background: var(--line-strong); flex: none }
.conn.dot { background: none; border-top: 1px dashed var(--line-strong) }
.flow-caps { display: flex; justify-content: center; gap: clamp(28px, 7vw, 110px);
  margin-bottom: 44px; text-align: center }
.flow-caps div b { display: block; font-weight: 500; color: var(--ink); font-size: .92rem }
.flow-caps div span { font-size: .85rem; color: var(--ink-faint) }

/* two-column features, hairline divider */
.duo { display: grid; grid-template-columns: 1fr 1fr }
.duo > .cell { padding: clamp(40px, 5vw, 64px) var(--landing-pad) }
.duo > .cell + .cell { border-left: 1px solid var(--line) }
.duo-row + .duo-row { border-top: 1px solid var(--line) }
.cell h3 { margin-bottom: 16px }
.cell > p { font-size: .98rem; max-width: 46ch; margin-bottom: 34px }

/* mock panels */
.stage { background: var(--surface-2); border: 1px solid var(--line);
  padding: 26px; min-height: 300px }
.mockcard { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-panel); box-shadow: var(--shadow-panel); padding: 16px }
/* Sits on the stage's own ground, ABOVE the card, not on it: the card is the
   drawing and the tag is the frame's label, and putting it inside would make
   it look like a field of the mock. Faint, uppercase and tracked, exactly as
   `.inst-top` does it in the hero — same device, same weight, so the two read
   as one convention rather than two warnings of different severity. */
.stage-tag { margin: -6px 0 16px }

/* T-1 extraction */
.xrow { display: grid; grid-template-columns: 1fr 1.15fr; gap: 14px }
.email .from { display: flex; gap: 10px; align-items: center; margin-bottom: 12px }
.email .av { width: 30px; height: 30px; border-radius: 50%; background: var(--pine);
  color: var(--on-pine); display: grid; place-items: center; font-size: .7rem;
  font-weight: 600; flex: none }
.email .nm { font-size: .82rem; font-weight: 500; color: var(--ink) }
.email .em { font-size: .75rem; color: var(--ink-faint) }
.email .ln { height: 7px; border-radius: var(--r-ctl); background: var(--line); margin-bottom: 8px }
.email .ln.s { width: 58% } .email .ln.m { width: 82% }
.frow { display: flex; justify-content: space-between; gap: 10px; padding: 8px 0;
  border-bottom: 1px solid var(--line); font-size: .8rem }
.frow:last-of-type { border-bottom: 0 }
.frow span { color: var(--ink-faint) }
.frow b { font-weight: 500; color: var(--ink); font-family: var(--font-data); font-size: .76rem }
.xactions { display: flex; gap: 8px; margin-top: 12px }
.xactions button { flex: 1; padding: 8px; border-radius: var(--r-ctl); font-size: .8rem;
  cursor: pointer; font-family: var(--font-ui); border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-body) }
.xactions .ok { background: var(--pine); border-color: var(--pine);
  color: var(--on-pine); font-weight: 500 }
.conf { margin-top: 14px; font-size: .8rem; color: var(--ink-faint) }

/* revision chart — two VINTAGES of one series, not two categories.
   The live print takes a series slot; the superseded one is de-emphasised
   (--ink-faint, which is tokens.css's declared alias of --series-other) and
   dashed. Both are strokes and swatches, never text (R3.4). */
.revchart { width: 100%; height: 150px; overflow: visible }
.revchart .rule { stroke: var(--line) }
.revchart .first-print { fill: none; stroke: var(--ink-faint); stroke-width: 1.8;
  stroke-dasharray: 5 5 }
.revchart .revised { fill: none; stroke: var(--series-1); stroke-width: 2;
  stroke-linejoin: round }
.revchart .revised-tip { fill: var(--series-1) }
.legend { display: flex; gap: 18px; font-size: .8rem; color: var(--ink-body); margin-top: 14px }
.legend i { width: 8px; height: 8px; border-radius: 50%; display: inline-block;
  margin-right: 6px; background: var(--swatch, var(--series-other)) }
.legend i.k-revised { --swatch: var(--series-1) }
.legend i.k-first-print { --swatch: var(--ink-faint) }
.legend .stat { margin-left: auto; font-family: var(--font-data); font-size: .72rem }
.mkhead { display: flex; align-items: center; gap: 8px; font-size: .82rem;
  font-weight: 500; color: var(--ink); margin-bottom: 14px }

/* activity feed */
.feed .fr { display: flex; align-items: center; gap: 12px; padding: 11px 4px;
  border-bottom: 1px solid var(--line) }
.feed .fr:last-child { border-bottom: 0 }
.feed .doc { width: 26px; height: 26px; border-radius: var(--r-ctl);
  background: var(--surface-2); display: grid; place-items: center;
  font-family: var(--font-data); font-size: .6rem; color: var(--ink-faint); flex: none }
.feed .tt { flex: 1; font-size: .82rem; color: var(--ink); font-weight: 500 }
/* The transparent border is here so the three pill variants share a box: the
   two that carry a signal add a coloured RULE, and a pill that gained 2px of
   width on becoming a warning would reflow its row. */
.pill { font-family: var(--font-data); font-size: .65rem; letter-spacing: .05em;
  padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap;
  border: 1px solid transparent;
  color: var(--ink-body); background: var(--surface-2) }
/* Amber goes on the row that is genuinely behind — filings outstanding — and
   NOWHERE ELSE on this feed (R3.13). "Restated" deliberately stays neutral:
   this page's own thesis two panels up is that revisions are data, not
   embarrassment, and an amber pill would have contradicted it in the same
   viewport.
   BOTH SIGNAL PILLS KEEP THE NEUTRAL GROUND. Tinting the background toward
   the ink is what the first draft did, and it measured 4.20:1 (stale) and
   4.67:1 (measured) in light — one fail and one that only passed by 0.17.
   --warn and --accent-measured-ink are fitted to --surface-2 and read 4.56
   and 4.93 there, which are the pairs tokens.css already gates, so this
   version cannot drift without test_token_pairs.py saying so. The signal is
   carried by ink + rule; a tint bought decoration with contrast. */
.pill--stale { color: var(--warn); border-color: var(--warn) }
.pill--measured { color: var(--accent-measured-ink);
  border-color: var(--accent-measured) }
.feed .who { text-align: right; font-size: .72rem; color: var(--ink-faint);
  line-height: 1.35; flex: none }

/* source tiles */
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px }
.tile { border: 1px solid var(--line); border-radius: var(--r-panel);
  background: var(--surface); padding: 22px 14px 16px; text-align: center }
.tile .lg { font-family: var(--font-display); font-size: 1.35rem;
  color: var(--ink-faint); font-weight: 500; margin-bottom: 14px }
.tile .cap { font-size: .75rem; color: var(--ink-faint) }

/* ============================================================
   USE-CASE TICKER
   ============================================================ */
.ticker-band { border-top: 1px solid var(--line);
  padding: clamp(48px, 6vw, 80px) var(--landing-pad);
  display: grid; grid-template-columns: .8fr 1.2fr; gap: 40px; align-items: center }
.ticker { height: 9.2em; overflow: hidden; position: relative;
  -webkit-mask-image: linear-gradient(180deg, transparent, var(--ink) 28%,
    var(--ink) 72%, transparent);
  mask-image: linear-gradient(180deg, transparent, var(--ink) 28%,
    var(--ink) 72%, transparent) }
.ticker ul { list-style: none; margin: 0; padding: 0; animation: tick 16s linear infinite }
.ticker li { font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.7rem, 3vw, 2.5rem); line-height: 2.3em;
  color: var(--ink-faint); white-space: nowrap }
@keyframes tick { to { transform: translateY(-50%) } }
.ticker-band .lead { font-size: 1rem; max-width: 26ch }

/* ============================================================
   EVIDENCE 002
   ============================================================ */
.stat-tabs { display: grid; grid-template-columns: repeat(3, 1fr);
  border-block: 1px solid var(--line) }
/* `color` is here because this is a <button>, and a button that names no
   colour gets the UA's `buttontext` — measured rgb(0,0,0) in BOTH themes, a
   literal black that follows no theme and appears in no stylesheet, so the
   token lint cannot see it. Nothing renders in it today only because both
   spans inside set their own; the first descendant that forgets would be
   black-on-#0C0F11. Every themed control needs its own `color` for the same
   reason it needs its own `background`. */
.stab { position: relative; padding: 26px var(--landing-pad); background: var(--surface-2);
  color: var(--ink);
  cursor: pointer; border: 0; text-align: left; font-family: var(--font-ui);
  transition: background var(--dur-ui) var(--ease) }
.stab + .stab { border-left: 1px solid var(--line) }
.stab.on { background: var(--bg) }
.stab .n { font-family: var(--font-display); font-size: clamp(1.9rem, 3vw, 2.6rem);
  color: var(--ink); font-weight: 400 }
.stab .l { font-size: .9rem; color: var(--ink-body); margin-left: 10px }
.stab .bar { position: absolute; left: 0; bottom: -1px; height: 2px; width: 0;
  background: var(--ink) }
.stab.on .bar { width: 100%; transition: width 6s linear }

.quote-stage { position: relative; min-height: 330px; border-bottom: 1px solid var(--line) }
.q { position: absolute; inset: 0; padding: clamp(40px, 5vw, 64px) var(--landing-pad);
  display: flex; flex-direction: column; justify-content: space-between;
  opacity: 0; transition: opacity .6s ease; pointer-events: none }
.q.on { opacity: 1; pointer-events: auto }
.q blockquote { margin: 0; font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.4rem, 2.5vw, 2rem); line-height: 1.42; color: var(--ink); max-width: 30em }
/* `.attrib`, not `.foot` — THE SECOND CLASS COLLISION ON THIS PAGE, and the
   same shape as the `.q` one 200 lines up: two unrelated things share a name,
   each half looks right on its own, and the loser is whichever one the other
   rule reaches first. `.foot` is the PAGE FOOTER (line ~456) and carries
   `background: var(--pine); color: var(--on-pine); padding: 96px 0 0`. The
   quote card's attribution row wore the same class, so it inherited all three:
   a 1071x141 pine slab across the testimonial with 96px of dead space above
   it.
   The colours are the part that matters. `.q .nm` is (0,2,0) and wins over
   `.foot`'s `color`, so the speaker's NAME stayed on --ink and landed on pine
   — measured 2026-08-08 in light: name 1.15:1, role 1.92:1, firm 3.07:1.
   1.15:1 is not "low contrast", it is not rendered. Dark hid it completely,
   because there --ink and --on-pine are near-identical and the slab reads as
   a deliberate band. A defect that is invisible in one theme and unreadable
   in the other is exactly what a two-theme sweep is for. */
.q .attrib { display: flex; justify-content: space-between; align-items: flex-end; margin-top: 36px }
.q .who { display: flex; gap: 12px; align-items: center }
.q .av { width: 44px; height: 44px; border-radius: 50%; background: var(--surface-2);
  border: 1px solid var(--line) }
.q .nm { font-size: .9rem; font-weight: 500; color: var(--ink) }
.q .rl { font-size: .85rem; color: var(--ink-body) }
.q .brand { font-family: var(--font-display); font-size: 1.5rem; color: var(--ink-faint) }

/* ============================================================
   COVERAGE 003 / METHOD 004
   ============================================================ */
.grid-cells { display: grid; grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--line) }
.grid-cells--flush { border-top: 0 }
.gcell { padding: clamp(34px, 4vw, 52px) var(--landing-pad); border-bottom: 1px solid var(--line) }
.gcell:not(:nth-child(3n+1)) { border-left: 1px solid var(--line) }
/* Was pine. Pine is a fill that stays dark in both themes, so a 52px pine
   stroke on #0C0F11 was a blank cell. See the header note. */
.gcell .ic { color: var(--ink-body); margin-bottom: clamp(40px, 5vw, 72px) }
.gcell .ic svg { width: 52px; height: 52px; stroke: currentColor; fill: none; stroke-width: 1.1 }
.gcell h4 { margin-bottom: 14px }
.gcell p { font-size: .92rem }
.grid-cells--two { grid-template-columns: 1fr 1fr }
.grid-cells--two .gcell:not(:nth-child(3n+1)) { border-left: 0 }
.grid-cells--two .gcell:nth-child(2n) { border-left: 1px solid var(--line) }

/* ============================================================
   CTA + FOOTER
   ============================================================ */
.cta-band { background: var(--surface-2); border-top: 1px solid var(--line);
  text-align: center; padding: clamp(90px, 12vw, 160px) var(--landing-pad) }
.cta-band .mono-label { display: block; margin-bottom: 26px }
.cta-band h2 { font-size: clamp(2.4rem, 4.6vw, 3.7rem); max-width: 16ch; margin: 0 auto 22px }
.cta-band p { max-width: 48ch; margin: 0 auto 38px }

.foot { background: var(--pine); color: var(--on-pine); padding: clamp(64px, 8vw, 96px) 0 0 }
.foot-in { max-width: var(--landing-max); margin: 0 auto; padding-inline: var(--landing-pad) }
.foot-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 40px; padding-bottom: 64px }
.foot .mark { color: var(--on-pine) }
.foot .mark i { background: var(--on-pine) }
.foot .mark i:after { background: var(--pine) }
.foot h5 { font-size: .9rem; font-weight: 500; color: var(--on-pine); margin: 0 0 22px }
/* Secondary footer text is --on-pine MIXED TOWARD the pine it sits on, which
   deletes the old --sage (#93A79E) entirely: a hand-picked third green existed
   only to be "on-pine, quieter", and that is a mix, not a colour. It also
   follows the dark theme, where --on-pine and --pine both move.
   Links then hover by UNDERLINE — R3.11's sanctioned channel — because every
   colour move available here is either a hue (banned) or --on-pine itself,
   which is not in the lint's neutral set for the good reason that it is only
   neutral ON PINE. */
.foot ul, .foot-mid, .foot-btm { color: color-mix(in oklab, var(--on-pine) 70%, var(--pine)) }
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; font-size: .92rem }
.foot ul a:hover, .foot-btm nav a:hover { text-decoration: underline }
.foot-mid { display: flex; justify-content: space-between; align-items: center; gap: 20px;
  padding-block: 22px; font-size: .8rem;
  border-top: 1px solid color-mix(in oklab, var(--on-pine) 12%, transparent) }
.foot-mid b { font-family: var(--font-data); font-size: .68rem; letter-spacing: .12em; font-weight: 400 }
.foot-btm { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  padding-block: 26px 34px; font-size: .85rem;
  border-top: 1px solid color-mix(in oklab, var(--on-pine) 12%, transparent) }
.foot-btm nav { display: flex; gap: 28px }

/* ============================================================
   SCROLL REVEAL
   ============================================================ */
/* THE DIMMED RESTING STATE IS GATED ON A CLASS JAVASCRIPT SETS, and that is
   not defensiveness for its own sake — it was measured. Ungated, `.rv` holds
   16 elements (every section head, both feature columns, the whole coverage
   and method grid) at opacity .07, and the ONLY thing that ever raises them
   is an IntersectionObserver callback. If that callback does not arrive the
   page is blank-looking with no error anywhere: nothing throws, the HTML is
   all present, and a snapshot of the DOM reads perfectly.
   It does not arrive here. This preview renderer never delivers an IO
   callback at all — a control observer created by hand on a visibly
   intersecting element logged 0 hits — so every screenshot this task owes
   would have been taken of a 7%-opacity page. The same hole is open to a
   reader with JS off, a text-mode crawler, and print.
   The invariant: the dim is an ENHANCEMENT and must be applied by the thing
   that can also undo it. */
.js-reveal .rv { opacity: .07; transform: translateY(14px);
  transition: opacity .9s var(--ease), transform .9s var(--ease) }
.js-reveal .rv.in { opacity: 1; transform: none }

/* ============================================================
   RESPONSIVE + MOTION
   ============================================================ */
@media (max-width: 920px) {
  .nav nav { display: none }
  .hero, .sec-head, .duo, .ticker-band, .xrow { grid-template-columns: 1fr }
  .sec-head .right { justify-self: start }
  .duo > .cell + .cell { border-left: 0; border-top: 1px solid var(--line) }
  .stat-tabs { grid-template-columns: 1fr }
  .stab + .stab { border-left: 0; border-top: 1px solid var(--line) }
  .grid-cells, .grid-cells--two { grid-template-columns: 1fr }
  .gcell:not(:nth-child(3n+1)), .grid-cells--two .gcell:nth-child(2n) { border-left: 0 }
  .foot-grid { grid-template-columns: 1fr 1fr }
  .quote-stage { min-height: 420px }
  .inst-cards { grid-template-columns: 1fr }
}
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important }
  .js-reveal .rv { opacity: 1; transform: none }
  html { scroll-behavior: auto }
}
