/* Alongside — webfonts, served from this origin.
   Overpass and Space Grotesk are variable (one file per subset, all weights); 0xProto is two static
   faces. All three are SIL OFL 1.1 — see /fonts/OFL-*.txt. The mirror at src/ds/fonts.css still
   names fonts.googleapis.com and cdn.jsdelivr.net; build.mjs rewrites it, and asserts that no
   external origin survives here. */

/* impeccable-disable overused-font -- Space Grotesk is the brand body face, chosen alongside Overpass
   and 0xProto; owner decision 2026-08-12 on run `8i91`'s D1. This file is inside the design-project
   mirror, so a re-import drops this line — `marketing/build.mjs` records that beside its own caveats. */


@font-face{font-family:'0xProto';font-weight:400;font-style:normal;font-display:swap;src:url(/fonts/0xproto-400.woff2) format('woff2')}
@font-face{font-family:'0xProto';font-weight:700;font-style:normal;font-display:swap;src:url(/fonts/0xproto-700.woff2) format('woff2')}

@font-face{font-family:'Overpass';font-style:normal;font-weight:100 900;font-display:swap;src:url(/fonts/overpass-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Overpass';font-style:normal;font-weight:100 900;font-display:swap;src:url(/fonts/overpass-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:300 700;font-display:swap;src:url(/fonts/space-grotesk-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:300 700;font-display:swap;src:url(/fonts/space-grotesk-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
/* Alongside — color. Values copied from app/src/styles/tokens.css.
   Three of them no longer match, and the divergence is deliberate rather than drift. `--faint`,
   `--success` and `--warn-ink` were each chosen against one surface and then used on a second, where
   they land under WCAG AA. Measured on the live site, foreground on background:

     --faint  #6d6d6d on --surface-2 #ebe6db  4.16:1  →  #666666  4.61:1  (footer, re-audit header)
     --success #1f7a4d on --success-chip      4.42:1  →  #1c7047  5.05:1  ("RESOLVED" tag)
     --warn-ink #8a6d1b on --warn-bg          4.42:1  →  #83671a  4.83:1  ("PERSISTS" tag)

   Each is the smallest step that clears 4.5:1, and none is worse anywhere it was already passing:
   `--faint` goes 4.59 → 5.09 on --bg and 5.17 → 5.74 on --surface, and white on the new `--success`
   goes 5.32 → 6.07. **Taken across on 2026-08-08** — `app/src/styles/tokens.css` carried all three
   failures for as long as this file did, and now carries these values with the measurements beside
   them, so this file is a verbatim copy again and the divergence above is closed rather than
   deliberate. */

:root{
  /* base palette */
  --bg:#f4f1ea;
  --surface:#ffffff;
  --surface-2:#ebe6db;
  --ink:#0c0c0c;
  --muted:#4a4a4a;
  --faint:#666666;
  --line:#0c0c0c;

  /* brand */
  --acid:#c6ff00;
  --chartreuse:#45600a;
  --teal:oklch(0.62 0.14 213);
  --hotpink:#ff2e88;
  --pink-text:#c2185b;

  /* semantic aliases */
  --surface-page:var(--bg);
  --surface-card:var(--surface);
  --surface-inset:var(--surface-2);
  --text-primary:var(--ink);
  --text-muted:var(--muted);
  --text-faint:var(--faint);
  --border:var(--line);
  --accent:var(--acid);
  --accent-text:var(--chartreuse);
  /* Literal rather than `var(--ink)`: the acid does not move, so what reads on it does not either. As an
     alias it flipped to cream under the dark theme — 1.3:1 on the primary CTA. */
  --accent-ink:#0c0c0c;
  --accent-2:var(--teal);
  --on-accent-2:#ffffff;
  /* What reads on a saturated fill (`--pink-text`, `--success`). Both are dark here and light on the dark
     palette, so neither white nor ink works for both. Third case after `--bg` and `--accent-ink`. */
  --on-fill:#ffffff;

  /* findings, badges and rules */
  --success:#1c7047;
  --success-bg:#f2faec;
  --success-chip:#d8f0df;
  --warn-ink:#83671a;
  --warn-bg:#fbf3d9;
  --warn-line:#e4d9a8;
  --danger-bg:#f6dede;
  --hairline:#ddd9cf;
  --hairline-soft:#e8e4da;
  --disabled-bg:#efece4;
  --disabled-line:#b8b4a8;
  --disabled-ink:#b3b0a6;
  --ghost-ink:#9a988f;

  /* the acid marker-pen sweep behind active nav labels and hovered rows */
  --highlighter:linear-gradient(to top,color-mix(in oklab,var(--acid) 52%,transparent) 58%,transparent 58%);
}

/* THE DARK PALETTE — a restoration, not a new design.

   A 27-token `html[data-theme="dark"]` block stood in `site.css` and was deleted, correctly, because
   nothing ever set the attribute (`site.css:6-15` has the note). `build.mjs` injects the switch and a
   pre-paint script now, so it comes back — out of that commit rather than reinvented, and here rather than
   in `site.css`, which is layout only.

   Three tokens the deleted block predates: `--on-fill` and `--accent-ink` (declared above; a fill whose
   legible foreground flips) and `--shadow-hard`, which is `2px 2px 0 var(--ink)` in `form.css` and would
   paint a cream block shadow on a dark page. `--highlighter` derives from `--acid` and still needs a value —
   see its note at the end of the block.

   Measured: ink 17.9:1 · muted 10.7:1 · faint 6.1:1 on --bg, 5.7:1 on --surface · accent-text 15.1:1 (the
   chartreuse it replaces is 1.9:1) · accent-ink on acid 15.5:1 · pink 8.9:1 · success 7.4:1 · warn 9.6:1. */
html[data-theme='dark']{
  --bg:#0c0c0c;
  --surface:#141413;
  --surface-2:#1c1b19;
  --ink:#f4f1ea;
  --muted:#c9c4b8;
  --faint:#9a988f;
  --line:#3a3936;

  --accent-text:#c6ff00;
  --on-fill:#0c0c0c;

  --success:#4ecb8b;
  --success-bg:#15251c;
  --success-chip:#1e3527;
  --warn-ink:#e3c569;
  --warn-bg:#2a2413;
  --warn-line:#4a3f1d;
  --danger-bg:#31171b;
  --hairline:#2b2a27;
  --hairline-soft:#232220;
  --disabled-bg:#1d1c19;
  --disabled-line:#3a3936;
  --disabled-ink:#6d6d6d;
  /* `p2tw` V4: #7d7b74 measured 4.06:1 on `--inv-bg` in dark, under AA, across six elements on the
     `#run` band. 5.66:1 now, against 6.43 in light where it was already fine. */
  --ghost-ink:#96948b;
  --pink-text:#ff6aa8;

  --shadow-hard:2px 2px 0 #45443d;
  --shadow-press:1px 1px 0 #45443d;
  --shadow-float:0 22px 48px -30px #000;

  /* The one recovered value that was then changed. Derived (`--inv-bg:var(--ink)`) it is a cream slab, and
     there are 24 of these bands — too loud. The deleted block said `#000`, a 0.4% luminance step from the
     page, so the band would read as the page. `--surface-2` is the step this palette already uses to lift a
     surface; cream on it is 15.3:1. */
  --inv-bg:#1c1b19;
  --inv-ink:#f4f1ea;

  /* The marker sweep does not survive the flip unchanged, though it derives from `--acid`: 52% acid over
     cream is a bright swipe with dark text, while 52% over #0c0c0c is a muddy olive carrying cream text at
     4.4:1 — a redaction bar rather than a highlight. A background token cannot flip the text, so it goes the
     other way: a quiet acid wash at 26%, which measures 8.1:1 with the gesture unchanged. */
  --highlighter:linear-gradient(to top,color-mix(in oklab,var(--acid) 26%,transparent) 58%,transparent 58%);
}

/* Alongside — typography. Three faces, no more.

   AND, SINCE run `8i91`'s V4, A SCALE — WHICH THIS FILE DECLARED THE FAMILIES OF AND NONE OF THE SIZES.

   Color and spacing were tokenised and type was not: there was no `--font-size-*` or `--text-*` anywhere
   in the repository, and the gap was filled by **24 distinct pixel values**. Six of them — 13, 13.5, 14,
   14.5, 15, 15.5 — sat inside a 3.5px span, which is not six levels of hierarchy; no reader can tell them
   apart, so it is one level that drifted six ways. The single most-used size on the site was `14.5px`,
   appearing fourteen times, and it had no name.

   WHAT COLLAPSED, AND THE ONE RULE THAT DECIDED EACH MERGE

   A merge is justified when the two sizes are not distinguishable *at that size*, and refused when they
   are. So the tight middle of the ladder collapses hard and the display end does not:

     13, 13.5                  → 13     `--text-m`    21 declarations were choosing between two 0.5px apart
     14, 14.5, 15, 15.5        → 14.5   `--text-l`    32 declarations across a 1.5px span
     16, 16.5, 17              → 16.5   `--text-xl`   18 declarations; 16.5 is the middle, so every move is 0.5
     10, 10.5                  → 10     `--text-2xs`
     12, 12.5                  → 12.5   `--text-s`
     29, 30                    → 30     `--text-5xl`
     60, 64                    → 60     `--text-8xl`  the two "big number" displays, 6.7% apart
     19 · 21 · 23 · 38 · 46                            kept — each is one clear level, used once or twice

   Half-pixel steps are already this design system's habit (`--space-1h`, `--space-2h`, and 14.5px being
   the most-used size on the site), so they are kept rather than snapped to integers: snapping would move
   twice as much type to buy a tidiness nobody can see.

   THE FLUID LEVELS, WHERE THE REAL DRIFT WAS

   Thirteen bespoke `clamp()` triples had no shared curve, and three of them differed only in the *third
   decimal of a viewport coefficient* — `5.6vw`, `5.4vw`, `5.2vw` — so the relationship between a section
   heading and the heading below it changed as the window changed, which is drift nobody catches by looking
   at one width. Five levels now, each with one coefficient:

     --text-fluid-hero   44 → 104 @ 8.4vw   the home hero, deliberately alone at the top
     --text-fluid-title  34 →  66 @ 5.6vw   was four levels: 34/68, 34/66, 34/64 and 32/62
     --text-fluid-h2     30 →  46 @ 4vw
     --text-fluid-h3     20 →  29 @ 2.4vw   was five: 20/31, 21/29, 21/27, 19/29 and 19/25
     --text-fluid-lead   17 →  21 @ 1.7vw   was two: 17/21 and 16/20

   Two of those merges move a size by more than a pixel at the wide end — `.h3` gains 2px at its maximum
   and `.quote__t` gains 4 — and they are accepted rather than special-cased, because a pull-quote and a
   sub-heading scaling *together* is the property being bought. The alternative is thirteen curves again
   with two of them exempted, which is the state this replaces. */

:root{
  --font-display:'Overpass',system-ui,sans-serif;
  --font-body:'Space Grotesk',system-ui,sans-serif;
  --font-mono:'0xProto',ui-monospace,monospace;

  /* the static ladder */
  --text-3xs:9px;
  --text-2xs:10px;
  --text-xs:11px;
  --text-s:12.5px;
  --text-m:13px;
  --text-l:14.5px;
  --text-xl:16.5px;
  --text-2xl:19px;
  --text-3xl:21px;
  --text-4xl:23px;
  --text-5xl:30px;
  --text-6xl:38px;
  --text-7xl:46px;
  --text-8xl:60px;

  /* the fluid levels, one coefficient each */
  --text-fluid-lead:clamp(17px,1.7vw,21px);
  --text-fluid-h3:clamp(20px,2.4vw,29px);
  --text-fluid-h2:clamp(30px,4vw,46px);
  --text-fluid-title:clamp(34px,5.6vw,66px);
  --text-fluid-hero:clamp(44px,8.4vw,104px);
}

body{margin:0;background:var(--bg);font-family:var(--font-body);font-size:var(--text-l);line-height:1.4;color:var(--ink);-webkit-font-smoothing:antialiased}
a{color:var(--accent-text);text-decoration:none}
/* `:not(.btn)` because every CTA is an anchor: at (0,1,1) this beat `.btn--acid`'s (0,1,0) and put
   `--ink` — cream under the dark theme — on chartreuse at 1.05:1, on hover, on the primary action. */
a:not(.btn):hover{color:var(--ink)}
::selection{background:var(--acid)}
button{font-family:inherit;color:inherit}
input,textarea,select{font-family:var(--font-body);color:var(--ink)}
.mono{font-family:var(--font-mono)}
.disp{font-family:var(--font-display);font-weight:800;letter-spacing:-0.02em;line-height:1.04}

/* the type ladder, lifted from primitives.css */
.eyebrow{font-family:var(--font-mono);font-size:var(--text-3xs);letter-spacing:0.12em;color:var(--faint)}
.eyebrow--lg{font-size:var(--text-2xs);letter-spacing:0.1em}
.eyebrow--accent{color:var(--accent-text)}
.eyebrow--ink{color:var(--ink)}
.hint{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--faint);line-height:1.55}
.hint--tight{line-height:1.5}
.stat{font-family:var(--font-display);font-weight:800;letter-spacing:-0.02em;line-height:1}
.h-page{font-size:var(--text-3xl);font-weight:700;line-height:1.15}
.h-section{font-size:var(--text-xl);font-weight:700;font-family:var(--font-display);letter-spacing:-0.01em}
.h-card{font-size:var(--text-2xl);font-weight:700;font-family:var(--font-display);letter-spacing:-0.01em}
.h-sub{font-size:var(--text-xl);font-weight:700;font-family:var(--font-display);letter-spacing:-0.01em}
.num{font-size:var(--text-5xl);font-weight:700;font-family:var(--font-display);letter-spacing:-0.01em}

/* `p2tw` V1. The three smallest rungs were fixed px with no media query, so 9px stayed 9px on a phone —
   where it is furthest from the eye and the reader is likeliest to be moving. Lifted at the one breakpoint
   the layout already uses. The TOKENS move, not the call sites: a per-element override would have to find
   every one of them, and `build.mjs`'s TYPE_FLOOR reads the token. */
@media (max-width:640px){
  :root{
    --text-3xs:11px;
    --text-2xs:12px;
    --text-xs:12.5px;
  }
}

/* Alongside — spacing.
   The product spaces on a 4px base but uses the odd 18px / 13.5px / 39px value
   where the wireframe measured them; those are preserved rather than snapped.
   These tokens name what the product already does.

   TWO HALF-STEPS, BECAUSE THE SITE HAD SIX SIZES INSIDE A 7px SPAN.
   `site.css` referenced this scale 205 times and then set 61 raw pixel values beside it — 6, 7, 9,
   10, 11 and 13px, none of them on a 4px base and none reachable by any token. Naming all six would
   have entrenched them; snapping them to the 4px steps would have moved bullets and highlighter
   insets by up to 2px. They collapse to two instead, at 2px granularity where the eye is most
   sensitive and the base is least useful: 6/7 → 6, and 9/10/11 → 10. Every move is 1px.

   Named `-1h` and `-2h` rather than renumbering, because the existing names are ordinal and
   inserting a step would silently redefine `--space-3` everywhere it is already used. */

:root{
  --space-1:4px;
  --space-1h:6px;   /* half-step: bullet offsets, chip padding, the tight gaps between meta lines */
  --space-2:8px;
  --space-2h:10px;  /* half-step: list rhythm, row gaps, the highlighter's left inset */
  --space-3:12px;
  --space-4:14px;
  --space-5:18px;   /* the card padding used everywhere */
  --space-6:20px;
  --space-7:24px;
  --space-8:32px;
  --space-9:44px;
  --space-10:64px;

  /* layout */
  --sidebar-w:232px;
  --topbar-h:56px;
  --content-max:1140px;
  --gap-card:14px;
  --gap-section:24px;
}

/* Alongside — form: borders, radii, shadows, motion constants.
   Named "form" rather than "shape" to match the product's own vocabulary. */

:root{
  --border-keyline:1px solid var(--border);
  --shadow-float:0 22px 48px -30px rgba(12,12,12,0.5);
  --shadow-hard:2px 2px 0 var(--ink);
  /* The pressed form of `--shadow-hard`, a token so the dark theme can override it — the hover rule
     used to inline `var(--ink)` and painted a cream shadow on the acid button. */
  --shadow-press:1px 1px 0 var(--ink);
  --ease-standard:cubic-bezier(0.2,0.7,0.2,1); /* @kind other */
  --dur-state:150ms; /* @kind other */
  --dur-hover:180ms; /* @kind other */
  --dur-reveal:800ms; /* @kind other */
  --radius-control:4px;
  --radius-container:8px;
  --radius-pill:20px;

  /* Phosphor duotone secondary-layer opacity */
  --ph-duotone-secondary-opacity:0.28; /* @kind other */
}

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

/* Alongside — motion. Every keyframe the product actually reaches.
   Grade reveals, finding arrivals, teardown wipes: motion is used to say
   "this really happened", never for decoration. */

@keyframes shimmer{0%{background-position:120% 0}100%{background-position:-120% 0}}
@keyframes checkPop{0%{transform:scale(0)}70%{transform:scale(1.25)}100%{transform:scale(1)}}
@keyframes badgePop{0%{transform:scale(0.5)}65%{transform:scale(1.15)}100%{transform:scale(1)}}
@keyframes findingIn{0%{opacity:0;transform:translateY(-10px);box-shadow:0 0 0 3px var(--acid)}60%{opacity:1}100%{opacity:1;transform:none;box-shadow:0 0 0 0 rgba(198,255,0,0)}}
@keyframes findingInStrong{0%{opacity:0;transform:translateY(-14px) scale(0.96);box-shadow:0 0 0 4px var(--acid)}55%{opacity:1;transform:scale(1.02)}100%{opacity:1;transform:none;box-shadow:0 0 0 0 rgba(198,255,0,0)}}
@keyframes attn{0%,100%{box-shadow:0 0 0 0 rgba(138,43,43,0)}50%{box-shadow:0 0 0 5px rgba(138,43,43,0.16)}}
@keyframes resolveSettle{0%{transform:translateY(-8px);background:var(--acid)}100%{transform:none;background:var(--success-bg)}}
@keyframes shake{0%,100%{transform:translateX(0)}18%{transform:translateX(-5px)}38%{transform:translateX(5px)}58%{transform:translateX(-4px)}78%{transform:translateX(4px)}}
@keyframes dangerPulse{0%,100%{box-shadow:0 0 0 0 rgba(255,46,136,0.65)}55%{box-shadow:0 0 0 5px rgba(255,46,136,0)}}
@keyframes barEq{0%,100%{transform:scaleY(0.35)}50%{transform:scaleY(1)}}
@keyframes barsFade{to{opacity:0;transform:scale(0.6)}}
@keyframes checkReveal{0%{opacity:0;transform:scale(0.4)}70%{transform:scale(1.2)}100%{opacity:1;transform:scale(1)}}
@keyframes boxPop{0%{transform:scale(1)}55%{transform:scale(1.18)}100%{transform:scale(1)}}
@keyframes bannerPulse{0%,100%{box-shadow:0 0 0 0 rgba(198,255,0,0)}45%{box-shadow:0 0 0 4px rgba(198,255,0,0.4)}}
@keyframes wipe{0%{background:linear-gradient(90deg,transparent,rgba(198,255,0,0.6),transparent);background-size:220% 100%;background-position:130% 0}100%{background:linear-gradient(90deg,transparent,rgba(198,255,0,0.6),transparent);background-size:220% 100%;background-position:-130% 0}}
@keyframes wipeReveal{0%{clip-path:inset(0 100% 0 0);opacity:0.2}100%{clip-path:inset(0 0 0 0);opacity:1}}

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

/* Alongside — primitives. Copied verbatim from app/src/styles/primitives.css:
   the repeated inline-style patterns of the product, lifted into classes.
   Anything genuinely computed (heat colors, grade colors, bar widths) stays
   a style object at the call site.

   THE SPACING SCALE REACHES THIS FILE NOW — run `8i91`'s V5.

   `site.css` was close to fully tokenised (245 `var(--space-*)` references against 5 raw values, one
   of them carrying a comment saying it is an alignment sum rather than rhythm). This file had
   **zero** token references and 22 raw padding/margin/gap declarations across 15 distinct values,
   six of which — 3, 5, 7, 9, 15, 39 — no token could reach and three of which were off the 4px base
   the scale is built on. The layer that affects is the one a person touches: a button, a pill and a
   chip sitting in one row had vertical padding of 10, 7 and 7 against horizontal padding of 18, 15
   and 12, so three controls that read as one family were built on three unrelated measurements.

   Every move is 1px, and it is the move `ds/spacing.css` already sanctions in its own header: 7 → 6
   (`--space-1h`) and 9 → 10 (`--space-2h`), at 2px granularity where the eye is least sensitive to
   it. Two values stay raw and say why: `39px` in `.subnavbtn` is an alignment sum, and the `1px`/`2px`
   highlighter insets are hairline nudges rather than rhythm.

   ONE SPELLING OF WHITE, AND WHY IT IS NOT `#fff` — V5's second half, and dark mode's first.

   White was written three ways across the stylesheet (`#fff` here, `#ffffff` in `colors.css`,
   `var(--surface)` elsewhere), so a palette change had to find all three. Every instance here meant
   *"the color that reads on top of `--ink`"*, which is what `--bg` is and what `.slab` below already
   used — so they are `var(--bg)`, and a theme that redefines `--ink` gets a readable pair for free
   instead of cream-on-cream. The one exception is `.btn--danger-solid`, whose background is not
   `--ink`: it takes `--on-fill`, a token `ds/colors.css` flips with the theme, because
   `--pink-text` is dark on the light palette and light on the dark one. */

/* surfaces */
.card{background:var(--surface);border:var(--border-keyline);border-radius:var(--radius-container)}
.card--float{box-shadow:var(--shadow-float)}
.card--hard{box-shadow:var(--shadow-hard)}
.card--pad{padding:var(--space-5)}
.card--pad-lg{padding:var(--space-5) var(--space-6)}
.tile{background:var(--surface);border:var(--border-keyline);border-radius:6px}
.tile--inset{background:var(--bg)}
.tile--dashed{background:var(--surface);border:1px dashed var(--disabled-line);border-radius:var(--radius-container)}
.slab{background:var(--ink);border:var(--border-keyline);border-radius:var(--radius-container);color:var(--bg)}
.notice{background:var(--warn-bg);border:var(--border-keyline);border-radius:6px}

/* buttons */
/* THE 44px MINIMUM IS ON THE PRIMITIVE — run `8i91`'s V9.

   It was set in five deliberate places instead (`.authform .field`, `.authform__go` at 46,
   `.hostbtn` at 46, `.auds .pill`, and `.hero__cta .btn` inside a 640px media block), so the
   convention existed and every new component had to remember it independently. Three did not:
   measured on `/services` at 390×664, `.svcmeta .btn` — *"Buy an audit"*, the purchase action for a
   $149 product, in the price column — was **34px** because its padding came from `.chip`; the header
   CTA was 36px; and the sub-page hero's three buttons were **43px**, one pixel short, because the
   rule granting the minimum names `.hero__cta` rather than `.btn` and `.phero` never received it.
   Nobody finds a missing pixel by looking, which is the argument for putting it here.

   `inline-flex` is required rather than cosmetic: most of these are `<a class="btn">`, and
   `min-height` does nothing to an inline box. Centering comes with it, which is what the `text-align`
   in the 640px block was doing by hand.

   `.btn--bare` opts out, and that is the whole exception: it is a text-shaped control with
   `padding:0` used inside sentences and table cells, where a 44px box would push the line apart. */
.btn{display:inline-flex;align-items:center;justify-content:center;min-height:44px;border:var(--border-keyline);border-radius:var(--radius-control);padding:var(--space-2h) var(--space-5);font-weight:700;font-family:inherit;cursor:pointer;background:var(--surface);color:var(--ink);transition:background var(--dur-hover) var(--ease-standard),box-shadow var(--dur-hover) var(--ease-standard)}
.btn--acid{background:var(--acid);box-shadow:var(--shadow-hard)}
/* `--shadow-press`, not raw `--ink`: the dark theme overrides the shadow token and this bypassed it,
   painting a cream drop shadow on the acid button. */
.btn--acid:hover{box-shadow:var(--shadow-press)}
/* THE FOCUS RING BUTTONS NEVER HAD — V7.
   Nothing on this site sets `outline:none` (the one rule that did, on `.door`, was found and
   removed), so every button fell through to the browser default: `outline:1px rgb(16,16,16)` at
   `outline-offset:1px`. On `.btn` that lands badly — the control already carries
   `border:1px solid #0c0c0c`, so a focused button was a 1px near-black line one pixel outside a 1px
   near-black border, with a single pixel of `--acid` showing between them on the primary CTA. WCAG
   2.2's focus-appearance criterion asks for the area of a 2px perimeter at 3:1 against what it
   replaces; 1px against an identical 1px meets neither. The pattern already existed twelve lines
   below in `.field:focus-visible` and in `.door:focus-visible` — the buttons simply never got it. */
.btn:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.btn--ink{background:var(--ink);color:var(--bg)}
.btn--inset{background:var(--bg)}
.btn--ghost{background:none}
.btn--danger{background:var(--surface);border-color:var(--pink-text);color:var(--pink-text)}
.btn--danger-solid{background:var(--pink-text);color:var(--on-fill);box-shadow:var(--shadow-hard)}
.btn--disabled,.btn:disabled{background:var(--disabled-bg);border-color:var(--disabled-line);color:var(--disabled-ink);box-shadow:none;cursor:not-allowed}
.btn--sm{padding:var(--space-1h) var(--space-3);font-size:var(--text-m)}
.btn--xs{padding:var(--space-1h) var(--space-3);font-size:var(--text-s)}
.btn--mono{font-family:var(--font-mono);font-size:var(--text-m)}
.btn--block{width:100%}
.btn--bare{display:inline;min-height:0;background:none;border:none;padding:0;cursor:pointer;text-align:left;font-weight:inherit}

/* pills, chips, tags, badges */
.pillgroup{display:inline-flex;border:var(--border-keyline);border-radius:var(--radius-pill);overflow:hidden}
.pill{padding:var(--space-1h) var(--space-4);background:transparent;color:var(--faint);border:none;font-weight:700;font-size:var(--text-m);cursor:pointer}
.pill[aria-pressed='true'],.pill--on{background:var(--ink);color:var(--bg)}
.chip{font-family:var(--font-mono);font-size:var(--text-xs);font-weight:700;padding:var(--space-1h) var(--space-3);border:var(--border-keyline);border-radius:var(--radius-pill);cursor:pointer;background:var(--surface);color:var(--ink)}
.chip[aria-pressed='true']{background:var(--acid);color:var(--accent-ink)}
.tag{font-family:var(--font-mono);font-size:var(--text-3xs);font-weight:700;letter-spacing:0.05em;text-transform:uppercase;border:var(--border-keyline);border-radius:var(--radius-pill);padding:var(--space-1) var(--space-2h);white-space:nowrap}
.badge{flex:none;font-family:var(--font-mono);font-size:var(--text-2xs);font-weight:700;letter-spacing:0.04em;border:var(--border-keyline);border-radius:var(--radius-control);padding:var(--space-1) var(--space-2)}

/* the small rotated square that marks Alongside's accents */
.diamond{display:inline-block;width:12px;height:12px;flex:none;background:var(--acid);border:var(--border-keyline);transform:rotate(45deg)}
.diamond--bare{border:none}

/* forms */
.field{width:100%;border:var(--border-keyline);border-radius:var(--radius-control);padding:var(--space-2h) var(--space-3);font-size:var(--text-l);background:var(--surface)}
.field--mono{font-family:var(--font-mono);font-size:var(--text-m)}
.field:focus-visible{outline:2px solid var(--accent-text);outline-offset:1px}
.checkbox{width:20px;height:20px;flex:none;display:grid;place-items:center;border:var(--border-keyline);border-radius:var(--radius-control);font-weight:700;background:var(--surface)}
.checkbox--on{background:var(--acid)}
.checkbox--sm{width:18px;height:18px;font-size:var(--text-xs)}

/* rows and tables */
.divider{border-bottom:1px solid var(--hairline)}
.divider--soft{border-bottom:1px solid var(--hairline-soft)}
.projrow .projname,.reprow .repname{white-space:nowrap}
/* `1px` stays raw: a hairline nudge that keeps the highlighter's sweep off the glyphs, not rhythm. */
.projrow:hover .projname,.reprow:hover .repname{background:var(--highlighter);padding:1px var(--space-1);margin-left:calc(var(--space-1) * -1);-webkit-box-decoration-break:clone;box-decoration-break:clone}

/* sidebar navigation */
.navbtn{display:flex;align-items:center;text-align:left;padding:var(--space-1h) var(--space-2h);font-size:var(--text-l);cursor:pointer;border:none;background:transparent;font-weight:400;color:inherit;text-decoration:none}
.navbtn[data-section='true']{font-weight:700}
.navbtn__label{display:inline-flex;align-items:center;gap:var(--space-2h)}
.navbtn[aria-current='page'] .navbtn__label{background:var(--highlighter);padding:2px var(--space-1h);margin-left:calc(var(--space-1h) * -1);-webkit-box-decoration-break:clone;box-decoration-break:clone}
/* `39px` stays raw and is the file's one deliberate exception: it is an alignment sum — the parent
   row's 10px padding plus its 20px icon plus the 10px gap — so a sub-label lines up under the label
   above it rather than at a rhythm step. Snapping it to 40 or 44 would break the alignment it exists
   for. `site.css` keeps one raw value on the same grounds and says so in the same words. */
.subnavbtn{display:flex;align-items:center;text-align:left;padding:var(--space-1h) var(--space-2h) var(--space-1h) 39px;font-size:var(--text-m);cursor:pointer;border:none;background:transparent;color:inherit;text-decoration:none}
.subnavbtn__label{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--faint);font-weight:400}
.subnavbtn[aria-current='page'] .subnavbtn__label{color:var(--ink);font-weight:700;background:var(--highlighter);padding:2px var(--space-1h);margin-left:calc(var(--space-1h) * -1);-webkit-box-decoration-break:clone;box-decoration-break:clone}

.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 helpers */
.stack{display:flex;flex-direction:column}
.row{display:flex;align-items:center}
.spread{display:flex;align-items:center;justify-content:space-between}
.grow{flex:1;min-width:0}
.none{flex:none}

/* Alongside marketing site — layout only. Every value from the design system's tokens. */
:root{--inv-bg:var(--ink);--inv-ink:var(--bg)}
/* `--accent-ink` rather than a literal: same value, but it is now a token that says *what reads on the
   acid* instead of a hex nobody could search for. See `ds/colors.css`. */
.btn--acid,.vchip--x2,.tag--acid,.check{color:var(--accent-ink)}
/* The `html[data-theme="dark"]` block that stood here — 27 token overrides plus the body and
   wordmark swaps — was removed, because nothing on this site ever set `data-theme`: `site.js`'s header
   records that the `als.theme` read served the design tool rather than the page, and build.mjs
   strips the markup that wrote it. The palette shipped on every page load and could not render.
   **It is back, and something sets the attribute now** — `build.mjs` injects the switch and the
   pre-paint script, on the same precedent as `HEAD_ICONS` and `NAV_EXTRAS`. The palette itself lives in
   `ds/colors.css`, where the values it overrides are declared; this file is layout only. The two rules
   the *layout* owns are the body swap (below, which `typography.css` already gives us for free through
   `var(--bg)`/`var(--ink)`) and the wordmark swap, which is here because it is markup rather than
   color: `.brand__dark{display:none}` hides the light-on-dark logotype, and the theme un-hides it. */
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{text-wrap:pretty}
img{display:block}
h1,h2,h3,h4,p,ul,blockquote{margin:0}
ul{padding:0;list-style:none}
/* `--wrap-pad` is named rather than inlined because two rules need to draw a hairline at the
   *content* edge rather than the padding-box edge, and a border cannot: it paints where the box
   ends. `.phero` and the build's legal block both overhung the column they were separating by a
   full gutter. Anything insetting to the content column reads this, so the 640px narrowing below
   moves one value instead of three. */
.wrap{--wrap-pad:var(--space-7);max-width:var(--content-max);margin:0 auto;padding:0 var(--wrap-pad)}
.sec{padding-block:var(--space-10)}
.h2{font-size:var(--text-fluid-h2)}
.h3{font-size:var(--text-fluid-h3);line-height:1.1}
.hl{background:var(--highlighter);-webkit-box-decoration-break:clone;box-decoration-break:clone}

/* auth */
.authbody{min-height:100vh;display:grid;place-items:center;padding:var(--space-7) var(--space-5)}
.auth{width:100%;max-width:404px;display:flex;flex-direction:column;align-items:center;gap:var(--space-6)}
.auth__brand img{height:34px;width:auto}
.authcard{width:100%;padding:var(--space-7)}
.auth__h{font-size:var(--text-5xl);margin:var(--space-2) 0 var(--space-1h)}
.auth__sub{color:var(--muted);font-size:var(--text-l)}
.hosts{display:flex;flex-direction:column;gap:var(--space-2h);margin-top:var(--space-6)}
.hostbtn{display:flex;align-items:center;gap:var(--space-2h);min-height:46px;font-size:var(--text-l);box-shadow:var(--shadow-hard)}
.hostbtn:hover{box-shadow:1px 1px 0 var(--ink)}
.hostbtn:first-child{background:var(--acid)}
.hostbtn__m{display:grid;place-items:center;width:24px;height:24px;flex:none;font-family:var(--font-mono);font-size:var(--text-2xs);font-weight:700;background:var(--ink);color:var(--bg);border-radius:3px}
.hostbtn:first-child .hostbtn__m{background:var(--ink)}
.hostmore>summary{cursor:pointer;list-style:none;font-size:var(--text-m);color:var(--muted);padding:var(--space-1h) 2px}
.hostmore>summary::-webkit-details-marker{display:none}
.hostmore>summary::before{content:"+ ";font-family:var(--font-mono);color:var(--accent-text)}
.hostmore[open]>summary::before{content:"− "}
.hostmore>summary:hover{color:var(--ink)}
.hostmore__b{display:flex;flex-direction:column;gap:var(--space-1h);padding-top:var(--space-1)}
.authsep{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:var(--space-3);margin:var(--space-6) 0 0}
.authsep::before,.authsep::after{content:"";height:1px;background:var(--hairline)}
.authsep span{font-family:var(--font-mono);font-size:var(--text-2xs);color:var(--faint);text-transform:uppercase;letter-spacing:.08em}
.authnote{margin-top:var(--space-5);padding-top:var(--space-5);border-top:1px solid var(--hairline)}
.authform{display:flex;flex-direction:column;gap:var(--space-2h);margin-top:var(--space-5)}
.flabel{font-family:var(--font-display);font-weight:700;font-size:var(--text-m);letter-spacing:-0.01em}
.authform .field{min-height:44px}
.fcheck{display:flex;align-items:center;gap:var(--space-2h);cursor:pointer;margin:2px 0 var(--space-1)}
.fcheck input{width:16px;height:16px;accent-color:var(--acid)}
.authform__go{min-height:46px;font-size:var(--text-l)}
.authswap{margin-top:var(--space-5);font-size:var(--text-l);color:var(--muted)}
.authswap__b{color:var(--accent-text);font-weight:700;font-size:var(--text-l)}
.authswap__b:hover{background:var(--highlighter);color:var(--ink)}
.auth__foot{text-align:center}

/* sub-pages */
/* The rule is a pseudo-element, not `border-bottom`, because `.phero` also carries `.wrap`: a
   border draws at the padding box, so at 1440 it ran 150→1290 while `.phero h1`, `.sechead` and
   `.isogrid` beneath it all ran 174→1266 — two horizontal rules stacked at different widths on the
   Security page. Inset to `--wrap-pad` so it follows the gutter at every breakpoint. */
.phero{position:relative;padding-block:var(--space-9) var(--space-8)}
.phero::after{content:"";position:absolute;left:var(--wrap-pad);right:var(--wrap-pad);bottom:0;border-bottom:1px solid var(--hairline)}
.phero--flush::after{content:none}
.phero h1{font-size:var(--text-fluid-title);margin:var(--space-4) 0 0}
.phero__sub{font-size:var(--text-fluid-lead);color:var(--muted);max-width:62ch;margin-top:var(--space-5)}
.phero__cta{display:flex;gap:var(--space-3);flex-wrap:wrap;margin-top:var(--space-7)}
/* No `color`: `.btn` already sets `--ink`, and at (0,2,0) this beat `.btn--acid` at every state,
   so both acid CTAs on /services were cream-on-chartreuse in dark WITHOUT hovering. */
.phero__cta .btn{text-decoration:none}
.svcrow{display:grid;grid-template-columns:240px 1fr 210px;gap:var(--space-7);align-items:start;padding:var(--space-7) 0;border-bottom:1px solid var(--hairline)}
.svcrow:first-of-type{border-top:1px solid var(--hairline)}
/* `:is(h2,h3)` rather than `h3`, and `.step :is(h3,h4)` below for the same reason: these headings
   are retagged in build.mjs to close the h1→h3 and h2→h4 skips, so a tag selector would style the
   source and not the shipped page — or the reverse. The visual ladder is unchanged either way. */
.svcrow :is(h2,h3){font-family:var(--font-display);font-size:var(--text-4xl);letter-spacing:-0.01em;line-height:1.1;margin-top:var(--space-2)}
.svcrow p{color:var(--muted);font-size:var(--text-l)}
.svcrow ul{display:flex;flex-direction:column;gap:var(--space-2);margin-top:var(--space-4);font-size:var(--text-l);color:var(--muted)}
.svcrow ul li{display:grid;grid-template-columns:14px 1fr;gap:var(--space-2h)}
.svcrow ul li::before{content:"";width:7px;height:7px;margin-top:var(--space-1h);background:var(--acid);border:1px solid var(--line);transform:rotate(45deg)}
.svcmeta{display:flex;flex-direction:column;gap:var(--space-1h)}
.svcmeta .stat{font-size:var(--text-5xl)}
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--gap-card);margin-top:var(--space-6)}
.step{background:var(--surface);border:var(--border-keyline);border-radius:var(--radius-container);padding:var(--space-5)}
.step__n{font-family:var(--font-mono);font-size:var(--text-2xs);color:var(--faint)}
.step :is(h3,h4){font-family:var(--font-display);font-size:var(--text-xl);letter-spacing:-0.01em;margin:var(--space-2) 0 var(--space-1h)}
.step p{font-size:var(--text-m);color:var(--faint);line-height:1.5}
.kvrow{display:grid;grid-template-columns:1fr 1.25fr;gap:var(--space-6);padding:var(--space-4) 0;border-bottom:1px solid var(--hairline-soft);align-items:start}
.kvrow b{font-family:var(--font-display);font-size:var(--text-l);letter-spacing:-0.01em}
.kvrow p{color:var(--muted);font-size:var(--text-l)}
.qa{border-top:2px solid var(--ink)}
.qa__hd{display:grid;grid-template-columns:1fr 1.35fr;gap:var(--space-6);padding:var(--space-3) 0}
.qarow{display:grid;grid-template-columns:1fr 1.35fr;gap:var(--space-6);padding:var(--space-5) 0;border-top:1px solid var(--hairline)}
.qarow__q{font-family:var(--font-display);font-weight:700;font-size:var(--text-xl);letter-spacing:-0.01em;line-height:1.25}
.qarow__a{color:var(--muted);font-size:var(--text-l);max-width:62ch}
.qarow--hero{background:var(--acid-wash,var(--surface-2));margin:0 calc(var(--space-5) * -1);padding:var(--space-5);border-radius:var(--radius-container)}
.qarow--hero .qarow__a b{color:var(--ink)}
.sentence{padding:var(--space-8);display:grid;gap:var(--space-4)}
.sentence__t{font-size:var(--text-fluid-h3);line-height:1.18}
.step--dark{background:color-mix(in oklab,var(--bg) 7%,transparent);border-color:color-mix(in oklab,var(--bg) 26%,transparent)}
.step--dark h4{color:var(--bg)}
.step--dark p{color:var(--ghost-ink)}
.facts{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-6)}
.fact{padding-top:var(--space-4);border-top:2px solid var(--ink)}
.fact b{display:block;font-family:var(--font-display);font-size:var(--text-xl);letter-spacing:-0.01em;line-height:1.15;margin-bottom:var(--space-1h)}
.fact p{color:var(--muted);font-size:var(--text-l);max-width:52ch}
.isogrid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gap-card)}
.iso{display:flex;flex-direction:column;gap:var(--space-2h);padding:var(--space-6)}
.iso h3{font-family:var(--font-display);font-size:var(--text-xl);letter-spacing:-0.01em;line-height:1.15}
.iso p{color:var(--muted);font-size:var(--text-l)}
@media (max-width:1000px){.isogrid{grid-template-columns:1fr 1fr}}
@media (max-width:760px){.qa__hd{display:none}.qarow{grid-template-columns:1fr;gap:var(--space-2)}.qarow--hero{margin:0}.facts{grid-template-columns:1fr;gap:var(--space-5)}}
@media (max-width:640px){.isogrid{grid-template-columns:1fr}}
.honest{background:var(--warn-bg);border:var(--border-keyline);border-radius:var(--radius-container);padding:var(--space-6);margin-top:var(--space-7)}
.honest--stand{background:var(--success-bg)}
.honest h3{font-family:var(--font-display);font-size:var(--text-2xl);letter-spacing:-0.01em;margin-bottom:var(--space-2h)}
.honest ul{display:flex;flex-direction:column;gap:var(--space-2h);font-size:var(--text-l);color:var(--muted)}
.honest b{color:var(--ink)}
.pagelinks{display:flex;gap:var(--space-3) var(--space-5);flex-wrap:wrap;margin-top:var(--space-3);font-size:var(--text-m)}
/* `dhpb` V1: 26.2px and 27.4px met WCAG 2.5.8 (AA, 24) and missed 2.5.5 (AAA, 44) — while the mobile
   menu gives the same three destinations 44px. `min-height`, not more padding, so the row spacing the
   footer is laid out on does not move. */
.pagelinks a,.foot__links a{display:inline-flex;align-items:center;min-height:44px;padding-block:var(--space-1)}
/* `p2tw` V2: the legal nav is a `.hint`, so its links measured 17.05px — the other half of `8i91`'s
   26.2px fix. Keyed on the landmark, never on `.hint a`, which is also the copy paragraph. */
nav[aria-label='Legal'] a{display:inline-flex;align-items:center;min-height:44px;padding-block:var(--space-1)}
.foot__links{display:flex;flex-direction:column;gap:var(--space-2)}
@media (max-width:1000px){.svcrow{grid-template-columns:1fr;gap:var(--space-4)}.steps{grid-template-columns:1fr 1fr}.kvrow{grid-template-columns:1fr;gap:var(--space-1h)}}
@media (max-width:640px){.steps{grid-template-columns:1fr}}

/* nav */
/* `p2tw` V3: 88% let 12% of the footer through where the bar comes to rest at maximum scroll — a
   ghost of text under the nav, on every page. Opaque; the blur stays under @supports, where it is
   decoration on a bar that is already opaque rather than the thing making it readable. */
.nav{position:sticky;top:0;z-index:20;background:var(--bg);border-bottom:1px solid var(--hairline)}
@supports (backdrop-filter:blur(8px)){.nav{backdrop-filter:blur(8px)}}
.nav__in{display:flex;align-items:center;gap:var(--space-5);height:var(--topbar-h);min-width:0}
.nav__in>.brand{flex:none}
.nav__in>.brand img{height:32px;width:auto;max-width:100%}
.navr{display:flex;align-items:center;gap:var(--space-5);margin-left:auto;flex:none}
.navr>.btn{white-space:nowrap}
.brand{display:flex;align-items:center;color:var(--ink)}
.brand img{height:32px;width:auto}
.brand__dark{display:none}
html[data-theme='dark'] .brand__light{display:none}
html[data-theme='dark'] .brand__dark{display:block}
.foot .brand img{height:35px}
.nav__links{display:flex;flex-wrap:nowrap;white-space:nowrap;gap:var(--space-6);flex:1;font-size:var(--text-l)}
/* Padded to clear WCAG 2.5.8's 24px floor, which these missed on their line height alone: `Sign in`
   measured 18.2px and the footer links 18.9px. The site already sets `min-height:44px` in four
   deliberate places, so the convention exists — it just stopped before reaching the bar and the
   footer, which is the one navigation a phone has. Padding rather than `min-height` so the
   highlighter sweep still paints the box the text sits in. */
.nav__links a{color:var(--muted);display:inline-flex;align-items:center;padding-block:var(--space-1)}
.nav__signin{font-size:var(--text-l);font-weight:700;color:var(--ink);white-space:nowrap;display:inline-flex;align-items:center;padding-block:var(--space-1)}
.cta__mid,.cta__short{display:none}
.nav__signin:hover{background:var(--highlighter)}
.nav__links a:hover{color:var(--ink);background:var(--highlighter)}

/* hero */
.hero{padding-block:var(--space-10) var(--space-9)}
.hero__h{font-size:var(--text-fluid-hero);margin:var(--space-4) 0 var(--space-6)}
.hero__sub{font-size:var(--text-fluid-lead);max-width:44ch;color:var(--muted)}
.doors{display:grid;grid-template-columns:repeat(4,1fr);grid-template-rows:auto auto auto;gap:var(--gap-card);margin:var(--space-9) 0 var(--space-7)}
.door{display:grid;grid-template-rows:subgrid;grid-row:span 3;align-content:start;row-gap:var(--space-1h);text-align:left;background:var(--surface);border:var(--border-keyline);border-radius:var(--radius-container);padding:var(--space-5);cursor:pointer;font:inherit;transition:box-shadow var(--dur-hover) var(--ease-standard),transform var(--dur-hover) var(--ease-standard)}
.door:hover,.door:focus-visible{box-shadow:var(--shadow-hard);transform:translate(-1px,-1px)}
/* The `outline:none` these two shared meant the only focus signal was `--shadow-hard`, which paints
   the right and bottom edges only and is pixel-identical to hover — so a keyboard user got no
   indicator enclosing the control and nothing distinguishing focus from a mouse passing over. Every
   other control on the site keeps the browser's own outline; this is the one rule that opted out. */
.door:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.door__n{display:block;font-size:var(--text-2xs);color:var(--faint)}
.door__t{display:block;align-self:start}
.door strong{display:inline;font-family:var(--font-display);font-size:var(--text-xl);letter-spacing:-0.01em;line-height:1.15}
.door:hover strong{background:var(--highlighter);padding:0 var(--space-1h) 0 var(--space-2h);margin:0 calc(var(--space-1h) * -1) 0 calc(var(--space-2h) * -1);-webkit-box-decoration-break:clone;box-decoration-break:clone}
.door__d{display:block;align-self:start;font-size:var(--text-m);color:var(--faint);line-height:1.45}
.hero__cta{display:flex;gap:var(--space-3);flex-wrap:wrap}
.hero__fine{max-width:60ch;margin-top:var(--space-6)}

/* proof strip */
.strip{margin-top:var(--space-9);border-top:var(--border-keyline);border-bottom:var(--border-keyline);background:var(--inv-bg);color:var(--inv-ink);overflow:hidden;padding:var(--space-4) 0}
.strip__track{display:flex;width:max-content;animation:slide 34s linear infinite}
.strip__set{display:flex;align-items:center;gap:var(--space-7);padding-right:var(--space-7);font-family:var(--font-mono);font-size:var(--text-s);letter-spacing:0.02em;white-space:nowrap}
.strip .diamond{width:7px;height:7px;background:var(--acid);transform:rotate(45deg)}
@keyframes slide{to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){.strip__track{animation:none}}

/* section heads */
.sechead{display:grid;grid-template-columns:1.15fr 1fr;gap:var(--space-8);align-items:end;margin-bottom:var(--space-8);padding-bottom:var(--space-6);border-bottom:1px solid var(--hairline)}
.sechead h2{margin-top:var(--space-2h)}
.sechead__p{color:var(--muted);font-size:var(--text-xl);max-width:54ch}
.sechead--dark{border-bottom-color:color-mix(in oklab,var(--inv-ink) 22%,transparent)}
.sechead--dark .sechead__p{color:color-mix(in oklab,var(--inv-ink) 80%,transparent)}
.sec--dark{background:var(--inv-bg);color:var(--inv-ink);border-top:var(--border-keyline);border-bottom:var(--border-keyline)}

/* dossier */
.dossier{overflow:hidden}
.dossier__top{display:grid;grid-template-columns:280px 1fr;border-bottom:var(--border-keyline)}
.grades{padding:var(--space-6);border-right:var(--border-keyline);display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4)}
.gradebox__g{font-size:var(--text-8xl);margin-top:2px}
.gradebox__note{grid-column:1/-1;margin:0}
.cats{display:grid;grid-template-columns:repeat(3,1fr)}
.cat{display:grid;grid-template-columns:1fr 30px;align-items:center;gap:var(--space-2h);padding:var(--space-4) var(--space-5);font-size:var(--text-m);border-bottom:1px solid var(--hairline-soft);border-right:1px solid var(--hairline-soft)}
.cat b{font-family:var(--font-display);font-size:var(--text-xl);text-align:left}
.findings__hd{padding:var(--space-4) var(--space-5);background:var(--surface-2);border-bottom:var(--border-keyline)}
.findings__hd p{margin:0}
.finding{border-bottom:1px solid var(--hairline-soft)}
.finding>summary{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-4) var(--space-5);cursor:pointer;list-style:none}
.finding>summary::-webkit-details-marker{display:none}
.finding>summary:hover .finding__t{background:var(--highlighter);padding:0 var(--space-1h) 0 var(--space-2h);margin:0 auto 0 calc(var(--space-2h) * -1)}
.finding__t{margin-right:auto;min-width:0;font-weight:700;font-size:var(--text-l)}
.finding__b{color:var(--faint)}
/* The one raw spacing value left in this file, and it is an alignment rather than a rhythm: 92px is
   the severity tag's column — its width plus `>summary`'s padding and gap — so the risk paragraph
   starts under the finding title instead of under the tag. A token would have to be the sum of three
   others, and snapping it to 88 or 96 would visibly break the alignment it exists to make. */
.finding__body{padding:0 var(--space-5) var(--space-5) 92px}
.finding__risk{color:var(--muted);font-size:var(--text-l);max-width:78ch}
.prompt{margin-top:var(--space-4);background:var(--bg);border:var(--border-keyline);border-radius:6px;padding:var(--space-4) var(--space-5)}
.prompt__t{font-size:var(--text-m);line-height:1.65;margin:var(--space-2) 0 var(--space-4);max-width:88ch}
.findings__more{padding:var(--space-4) var(--space-5) var(--space-5)}
.finding .mono,.prompt .mono{font-size:0.94em}

/* fix prompt vs */
.vs{display:grid;grid-template-columns:1fr 1.55fr;gap:var(--space-6);align-items:start}
.vs__t{font-size:var(--text-m);line-height:1.6}
.vs__t--dim{color:var(--faint)}
.vs__a{opacity:0.9}
.vs__b{border-width:1px}
.vs .eyebrow{margin-bottom:var(--space-2h)}
.vs__cap{margin-top:var(--space-5)}

/* run screen */
.run{display:grid;grid-template-columns:266px 1fr;gap:var(--space-6);border:1px solid color-mix(in oklab,var(--inv-ink) 28%,transparent);border-radius:var(--radius-container);padding:var(--space-6);background:color-mix(in oklab,var(--inv-ink) 5%,transparent)}
.phases{display:flex;flex-direction:column;gap:var(--space-2h);margin:var(--space-2h) 0 0;font-size:var(--text-m)}
.phases li{display:flex;align-items:center;gap:var(--space-2h);color:var(--ghost-ink)}
.phases li::before{content:"";width:9px;height:9px;flex:none;border:1px solid var(--ghost-ink);border-radius:2px}
.phases li[data-done]{color:var(--inv-ink)}
.phases li[data-done]::before{content:"";background:var(--acid);border-color:var(--acid)}
.phases li[data-run]{color:var(--acid);font-weight:700}
.phases li[data-run]::before{background:none;border-color:var(--acid);animation:bannerPulse 1.6s var(--ease-standard) infinite}
.run__main{display:flex;flex-direction:column;min-height:360px}
.run__feed{flex:1;display:flex;flex-direction:column;gap:var(--space-2)}
.rfind{display:flex;align-items:center;gap:var(--space-2h);padding:var(--space-2h) var(--space-4);background:color-mix(in oklab,var(--inv-ink) 8%,transparent);border:1px solid color-mix(in oklab,var(--inv-ink) 18%,transparent);border-radius:6px;font-size:var(--text-m);animation:findingIn 520ms var(--ease-standard) both}
.rfind__t{flex:1}
.rfind__s{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--ghost-ink)}
.teardown{display:flex;align-items:center;gap:var(--space-2h);margin-top:var(--space-5);padding:var(--space-4) var(--space-5);border:1px solid var(--acid);border-radius:6px;opacity:0;transition:opacity 320ms var(--ease-standard)}
.teardown[data-on]{opacity:1;animation:wipe 900ms var(--ease-standard) 1}
.teardown__t{font-size:var(--text-m);font-weight:700;color:var(--acid)}
.check{display:grid;place-items:center;width:20px;height:20px;flex:none;background:var(--acid);border-radius:3px;font-size:var(--text-m);font-weight:700}
.run__cap{margin-top:var(--space-5);color:var(--ghost-ink)}

/* re-audit */
.regrade{overflow:hidden}
.regrade__hd{display:flex;align-items:center;justify-content:space-between;gap:var(--space-6);flex-wrap:wrap;padding:var(--space-5) var(--space-6);border-bottom:var(--border-keyline);background:var(--surface-2)}
.regrade__from{font-size:var(--text-6xl);color:var(--faint);text-decoration:line-through}
.regrade__to{font-size:var(--text-7xl);color:var(--success)}
.regrade__arrow{color:var(--faint)}
.resolved{display:flex;flex-direction:column}
.rrow{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-4) var(--space-6);border-bottom:1px solid var(--hairline-soft);font-size:var(--text-l);background:var(--success-bg)}
.rrow__t{flex:1;text-decoration:line-through;color:var(--faint)}
.rrow__tag{background:var(--success-chip);color:var(--success);border-color:var(--success)}
.rcheck{display:grid;place-items:center;width:19px;height:19px;flex:none;background:var(--success);color:var(--on-fill);border-radius:3px;font-size:var(--text-s);font-weight:700}
.rrow--open{background:var(--surface)}
.rrow--open .rrow__t{text-decoration:none;color:var(--ink)}
.rrow--open .rrow__tag{background:var(--warn-bg);color:var(--warn-ink);border-color:var(--warn-line)}
.rcheck--open{background:var(--warn-bg);color:var(--warn-ink);border:1px solid var(--warn-line)}
.resolved[data-on] .rrow{animation:resolveSettle 700ms var(--ease-standard) both}
.resolved[data-on] .rrow:nth-child(2){animation-delay:.22s}
.resolved[data-on] .rrow:nth-child(3){animation-delay:.44s}
.resolved[data-on] .rrow:nth-child(4){animation-delay:.66s}
.resolved[data-on] .rrow:nth-child(5){animation-delay:.88s}
.resolved[data-on] .rrow--open{animation:none}
.regrade__cap{padding:var(--space-5) var(--space-6)}

/* services */
.svcs{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-6)}
.svc{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-6)}
.svc__h{line-height:1.12}
.svc p:last-child{color:var(--muted);font-size:var(--text-l);margin-top:var(--space-1)}
.svcs__foot{display:flex;align-items:center;justify-content:space-between;gap:var(--space-6);flex-wrap:wrap;margin-top:var(--space-6);padding-top:var(--space-6);border-top:1px solid var(--hairline)}
.svcs__line{font-family:var(--font-display);font-weight:700;font-size:var(--text-xl);letter-spacing:-0.01em;max-width:52ch}
.svcs__foot .btn{text-decoration:none}

/* audiences */
.auds{flex-wrap:wrap;margin-bottom:var(--space-6);max-width:100%}
.audpanel[hidden]{display:none}
.audpanel{display:grid;grid-template-columns:1.1fr 1fr;gap:var(--space-8);padding:var(--space-8)}
.audpanel__p{margin-top:var(--space-4);color:var(--muted);font-size:var(--text-xl)}
.audpanel__q{position:relative;margin-top:var(--space-5);padding-left:var(--space-4)}
.audpanel__q::before{content:"";position:absolute;left:0;top:0;bottom:0;width:5px;background:var(--acid);border:1px solid var(--line);border-radius:var(--radius-pill)}
.hooks{display:flex;flex-direction:column;gap:var(--space-4);font-size:var(--text-l);color:var(--muted)}
.hooks li{padding-bottom:var(--space-4);border-bottom:1px solid var(--hairline-soft)}
.hooks li:last-child{border:none;padding-bottom:0}
.hooks b{color:var(--ink)}

/* checks */
.checks{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-9)}
.checkcol__hd{padding-bottom:var(--space-3);border-bottom:2px solid var(--ink);margin-bottom:var(--space-6)}
.dims{display:flex;flex-direction:column;gap:var(--space-6)}
.dim p{margin-top:var(--space-1h);color:var(--muted);font-size:var(--text-l);max-width:56ch}
.dim b{color:var(--ink)}
.vgrid{display:flex;flex-wrap:wrap;gap:var(--space-1h)}
.vchip{cursor:default;font-size:var(--text-2xs);padding:var(--space-1h) var(--space-2h)}
.vchip--x2{background:var(--acid)}
.vhooks{margin-top:var(--space-6)}
.quote{margin-top:var(--space-6);padding:var(--space-6) var(--space-6) var(--space-5);background:var(--inv-bg);color:var(--inv-ink);border-color:var(--line)}
.quote__t{font-size:var(--text-fluid-h3);line-height:1.18}
.quote__c{color:color-mix(in oklab,var(--inv-ink) 78%,transparent);margin-top:var(--space-4);max-width:52ch}

/* trust */
.trust{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-6)}
.tcard{display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-6)}
.tcard__h{line-height:1.12}
.tcard p{color:var(--muted);font-size:var(--text-l)}
.tcard b{color:var(--ink)}

/* nothing's gone wrong */
.nogo{max-width:74ch}
.nogo__h{font-size:var(--text-fluid-title);margin:var(--space-4) 0 var(--space-5)}
.nogo__lead{font-family:var(--font-display);font-weight:800;font-size:var(--text-fluid-h3);color:var(--acid);margin-bottom:var(--space-5)}
.nogo__p{color:color-mix(in oklab,var(--inv-ink) 82%,transparent);font-size:var(--text-xl);margin-bottom:var(--space-6);max-width:66ch}
.nogo__kick{font-size:var(--text-fluid-h3);line-height:1.15;margin-bottom:var(--space-6);color:var(--inv-ink)}
.nogo .btn{margin-top:var(--space-3)}

/* pricing */
.pricing{display:grid;grid-template-columns:1fr 1.25fr;gap:var(--space-6);align-items:start}
.starter{padding:var(--space-7)}
.starter__hd{margin-bottom:var(--space-5)}
.starter__h{font-size:var(--text-5xl)}
.starter__p{font-size:var(--text-8xl);margin:var(--space-1h) 0 var(--space-1)}
.starter__s{font-family:var(--font-display);font-weight:700;font-size:var(--text-xl)}
.starter__d{color:var(--muted);font-size:var(--text-l);margin-top:var(--space-3)}
.starter__cta{margin-top:var(--space-6);text-align:center;display:block;text-decoration:none}
.starter__f{margin-top:var(--space-2h);text-align:center}
.packs{display:flex;flex-direction:column;gap:var(--space-4)}
.packtable .eyebrow{margin-bottom:var(--space-2)}
.prow{display:grid;grid-template-columns:1fr auto 78px;gap:var(--space-4);align-items:center;padding:var(--space-2h) 0;border-bottom:1px solid var(--hairline-soft);font-size:var(--text-l)}
.prow .mono{font-size:var(--text-s);color:var(--faint)}
.prow b{text-align:right;font-family:var(--font-display);font-size:var(--text-xl)}
.packtable .hint{margin-top:var(--space-3)}
.promises{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-6);margin-top:var(--space-7);padding-top:var(--space-7);border-top:1px solid var(--hairline)}
.promise b{display:block;margin:var(--space-3) 0 var(--space-1);font-family:var(--font-display);font-size:var(--text-xl)}
.promise p{color:var(--muted);font-size:var(--text-l)}

/* faq */
.faq{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--space-9)}
.q{border-bottom:1px solid var(--hairline);padding:var(--space-5) 0}
.q>summary{cursor:pointer;list-style:none;font-family:var(--font-display);font-weight:700;font-size:var(--text-xl);letter-spacing:-0.01em;display:flex;gap:var(--space-3);align-items:baseline;padding-block:2px}
.q>summary::-webkit-details-marker{display:none}
.q>summary::before{content:"+";font-family:var(--font-mono);color:var(--accent-text);font-size:var(--text-l)}
.q[open]>summary::before{content:"−"}
.q>summary:hover span{background:var(--highlighter);padding:0 var(--space-1h) 0 var(--space-2h);margin:0 0 0 calc(var(--space-2h) * -1);-webkit-box-decoration-break:clone;box-decoration-break:clone}
.q>div{padding:var(--space-3) 0 0 var(--space-7);display:flex;flex-direction:column;gap:var(--space-2h)}
.q p{color:var(--muted);font-size:var(--text-l);max-width:62ch}
.q b{color:var(--ink)}

/* close + foot */
.close{text-align:center;padding-block:var(--space-10)}
.close__h{font-size:var(--text-fluid-title)}
.close__cta{display:inline-block;margin-top:var(--space-7);text-decoration:none;font-size:var(--text-xl);padding:var(--space-4) var(--space-7)}
.close__f{margin-top:var(--space-4)}
.foot{border-top:var(--border-keyline);background:var(--surface-2);padding:var(--space-8) 0 var(--space-8)}
.foot__in{display:grid;grid-template-columns:1fr 1.3fr;gap:var(--space-9)}
.foot__brand .hint{margin-top:var(--space-3);max-width:40ch}
.foot__soonl{margin-top:var(--space-2h);max-width:70ch}

/* Coming soon — links to surfaces that exist but are not open yet. Deliberately a real page
   rather than a dead `#`, so a click explains itself instead of doing nothing. */
.soon{padding-block:var(--space-10)}
.soon__in{max-width:60ch;margin:0 auto;text-align:center;display:flex;flex-direction:column;align-items:center;gap:var(--space-5)}
.soon__h{font-size:var(--text-fluid-title)}
.soon__p{color:var(--muted);font-size:var(--text-xl)}
.soon__list{display:flex;flex-direction:column;gap:var(--space-2h);text-align:left;width:100%;margin-top:var(--space-3)}
/* Marker positioned rather than tracked, because these `li` carry a `<b>` followed by a bare text
   node: in a two-track grid the element takes (1,2) and the anonymous text run auto-places onto
   (2,1) — the 14px track — wrapping one word per line. Every sentence here rendered as a vertical
   ribbon at every width. Do not restore `display:grid` without wrapping the content in one element. */
.soon__list li{display:block;position:relative;padding-left:var(--space-7);font-size:var(--text-l);line-height:1.55;color:var(--muted)}
.soon__list li::before{content:"";position:absolute;left:0;top:7px;width:8px;height:8px;background:var(--acid);border:1px solid var(--line);transform:rotate(45deg)}
.soon__list b{color:var(--ink)}

@media (max-width:1000px){
.doors{grid-template-columns:1fr 1fr}
/* `.svcs` joined this list. It was the one `repeat(3,1fr)` grid in the file with no rule at any
   width, so the three service cards stayed three abreast down to 320px: a `1fr` track has
   `min-width:auto` and bottomed out at 137px of content, putting the document at 479px against a
   320px viewport and the third card entirely off-screen. The overflow was on `documentElement`, so
   the whole page scrolled sideways, hero included. `.trust` eight lines below is the same
   declaration and was already here. */
.dossier__top,.vs,.checks,.trust,.svcs,.pricing,.promises,.faq,.foot__in,.audpanel,.run{grid-template-columns:1fr;gap:var(--space-6)}
.cats{grid-template-columns:1fr 1fr}
.grades{border-right:none;border-bottom:var(--border-keyline)}
.sechead{grid-template-columns:1fr;align-items:start;gap:var(--space-5)}
.checks{gap:var(--space-9)}
.finding__body{padding-left:var(--space-5)}
}
@media (min-width:700px) and (max-width:1000px){.dims{display:grid;grid-template-columns:1fr 1fr;column-gap:var(--space-8)}.dim p{max-width:none}.vhooks{columns:2;column-gap:var(--space-8)}.vhooks li{break-inside:avoid}}
@media (max-width:1000px){.nav__in{gap:var(--space-5)}.nav__links{gap:var(--space-5);font-size:var(--text-m)}.cta__full{display:none}.cta__mid{display:inline}}
/* THE HEADER HELD 22% OF A SMALL PHONE AND NEVER GAVE IT BACK — run `8i91`'s V3 and V2.

   Third answer to the same question. The links were once hidden below 700px with nothing in their place, so
   a phone had no navigation at all; the fix wrapped them onto a second row, recording *"five links at 13px
   fit two rows at 320px"*. Optimistic by a row — the audit measured **124px, three rows**, `Pricing`
   orphaned, on a sticky bar. V2 measured the same links at **26px** against a 44px minimum, and the two
   findings pull against each other in a wrapping layout. A disclosure answers both: measured after at 320px,
   57px and 10% of the viewport, with 44px rows in the panel.

   **The base rule comes first, and the first version had it second.** Both `display` declarations are
   specificity 0,1,0, so the later wins at every width: reversed, the menu was `display:none` everywhere, the
   header measured a very healthy 57px, and it contained no navigation at all. */
.navmenu{display:none;position:relative;flex:none;order:3}
.navmenu>summary{display:flex;align-items:center;justify-content:center;gap:var(--space-2);min-height:44px;min-width:44px;padding:0 var(--space-3);list-style:none;cursor:pointer;font-size:var(--text-m);font-weight:700;color:var(--ink);border:var(--border-keyline);border-radius:var(--radius-control);background:var(--surface)}
.navmenu>summary::-webkit-details-marker{display:none}
.navmenu>summary:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
/* The two bars, drawn rather than typed: an icon font is a network dependency for six pixels, and the
   glyph would arrive after first paint on the one control a phone needs immediately. */
.navmenu__bars{display:inline-flex;flex-direction:column;gap:3px;width:16px}
.navmenu__bars::before,.navmenu__bars::after{content:'';display:block;height:2px;background:var(--ink)}
/* THE OPEN STATE IS NOT ACID, AND A SCREENSHOT IS WHY.

   It was, and at 390px the result is two acid-filled buttons side by side in a 57px bar: the purchase CTA
   and a disclosure. On this site acid means *the thing we want you to press* — `.btn--acid` is the one
   button in the hero, and `.hostbtn:first-child` is the recommended host — so spending it on a menu makes
   the header say two things are primary and neither is. `--surface-2` is the same signal one register
   quieter, and it is what `.navmenu__list a:hover` already uses inside the panel. */
.navmenu[open]>summary{background:var(--surface-2)}
/* Positioned against the bar rather than the summary, so the panel spans the header's full width and
   its rows are wide enough to read. `100%` of `.nav` plus the page gutter would overflow, so it insets
   by the same `--wrap-pad` the content column uses. */
.navmenu__list{position:absolute;right:0;top:calc(100% + var(--space-2));z-index:30;min-width:220px;display:flex;flex-direction:column;background:var(--surface);border:var(--border-keyline);border-radius:var(--radius-container);box-shadow:var(--shadow-float);overflow:hidden}
.navmenu__list a{display:flex;align-items:center;min-height:44px;padding:0 var(--space-5);font-size:var(--text-l);color:var(--ink);border-bottom:1px solid var(--hairline-soft)}
.navmenu__list a:last-child{border-bottom:none}
.navmenu__list a:hover{background:var(--surface-2)}
.navmenu__theme{display:flex;padding:var(--space-2h) var(--space-5);border-top:1px solid var(--hairline)}
@media (max-width:800px){
.nav__links{display:none}
.navmenu{display:block}
}

/* THE THEME SWITCH.

   Rendered twice — in the bar at wide widths and as the menu's last row below 700px — because three 44px
   controls beside a wordmark at 320px is how the header got to 124px in the first place (V3). One piece of
   state, two controls, and `build.mjs`'s handler keeps their `aria-pressed` in step so they cannot disagree.

   The dot is drawn rather than iconised: a glyph from a font host is a network dependency for fourteen
   pixels, and it would arrive after first paint on the one control whose whole job is that the page does
   not flash. Outline in light, crescent in dark — `box-shadow: inset` with a diagonal offset takes a bite
   out of a filled circle, which is a moon without a second element. */
.themebtn{display:inline-flex;align-items:center;gap:var(--space-2);min-height:44px;padding:0 var(--space-3);flex:none;font-family:inherit;font-size:var(--text-m);font-weight:700;color:var(--ink);background:var(--surface);border:var(--border-keyline);border-radius:var(--radius-control);cursor:pointer}
.themebtn:hover{background:var(--surface-2)}
.themebtn:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.themebtn__dot{width:14px;height:14px;flex:none;border-radius:50%;border:2px solid var(--ink)}
html[data-theme='dark'] .themebtn__dot{border-color:var(--acid);box-shadow:inset -4px 3px 0 0 var(--acid)}
/* The word names the theme you are in, so it agrees with the dot beside it. It read `Dark` in both modes for
   as long as the switch existed, which made the same word an action in one theme and a state in the other.
   Two spans rather than one word set by script: `data-theme` lands before first paint and the script does not. */
.themebtn__t--dark{display:none}
html[data-theme='dark'] .themebtn__t--light{display:none}
html[data-theme='dark'] .themebtn__t--dark{display:inline}
/* In the panel the row is the control, so it fills the width and loses the box that would sit inside a box.
   No `justify-content`: `space-between` across a 182px row put the dot 139.3px from the word it labels, at
   every width the panel exists. The base rule's 8px gap is the relationship, and it starts at the links' edge. */
.themebtn--row{flex:1;min-height:44px;padding:0;border:none;background:none}
.themebtn--row:hover{background:none;color:var(--accent-text)}
/* THE LABEL GOES BEFORE THE CONTROL DOES — where the breakpoint's headroom comes from.

   With the label the bar needs **801px**, so a breakpoint at 800 has one pixel of margin: enough to pass a
   check, not enough to survive the next nav item. The dot alone recovers ~35px. Not a bug I introduced but a
   band I widened — without the switch the bar needed ~706px against a breakpoint of 700, so master overflowed
   between 701 and 706px, which nothing measured because the audit sampled 320, 390, 768 and 1440. */
/* `.navr>` and `.nav__in>` scope this to the copy **in the bar** — the first version named `.themebtn`
   and reached the panel copy too, where there is 182px of room and no reason to hide anything. The result
   was a menu row that was a lone circle with no label: a control saying nothing about what it does, found
   in a screenshot rather than in any number. */
@media (max-width:1000px){
.navr>.themebtn .themebtn__t,.nav__in>.themebtn .themebtn__t{display:none}
.navr>.themebtn,.nav__in>.themebtn{padding:0 var(--space-2h);min-width:44px;justify-content:center}
}
@media (max-width:800px){
/* Row one keeps the wordmark, the CTA and the menu. `Sign in` and the switch are inside the panel — see
   `injectNavMenu`, which copies the first and renders the second.

   Both parents are named, and that is not belt-and-braces: three pages (`coming-soon`, `privacy`, `terms`)
   have a bar with no `.navr`, so on those the switch is a child of `.nav__in`. A rule naming only `.navr`
   would leave two switches visible beside each other on exactly those pages. */
.nav__signin,.navr>.themebtn,.nav__in>.themebtn{display:none}
}
@media (max-width:760px){
.auds{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-2);border:none;border-radius:0;overflow:visible;width:100%}
.auds .pill{border:var(--border-keyline);border-radius:var(--radius-control);background:var(--surface);min-height:44px;font-size:var(--text-m);padding:var(--space-2h) var(--space-3);text-align:center}
.auds .pill--on{background:var(--ink);color:var(--bg)}
.auds .pill:last-child{grid-column:1/-1}
}
@media (max-width:560px){
.navr{gap:var(--space-3)}
.nav__signin{font-size:var(--text-m)}
.navr>.btn{font-size:var(--text-s);padding:var(--space-2) var(--space-2h)}
.cta__full,.cta__mid{display:none}
.cta__short{display:inline}
}
@media (max-width:640px){
.doors{grid-template-columns:1fr}
.wrap{--wrap-pad:var(--space-5)}
.sec{padding-block:var(--space-9)}
.cats{grid-template-columns:1fr}
.hero__cta .btn{flex:1;text-align:center;min-height:44px}
.finding>summary{flex-wrap:wrap}
}


::selection { background: var(--acid); color: #0c0c0c; }

:where(p, li, dd, blockquote) a:not(.btn):not(.brand) {
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}
:where(p, li, dd, blockquote) a:not(.btn):not(.brand):hover,
:where(p, li, dd, blockquote) a:not(.btn):not(.brand):focus-visible {
  text-decoration-thickness: 2px;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
@media (max-width: 699px) { .soon__p, .soon__in > .hint { text-align: left; width: 100%; } }

html { scroll-padding-top: calc(var(--topbar-h) + 1px + var(--space-4)); }

.tag { font-size: var(--text-xs); }
.eyebrow { font-size: var(--text-2xs); }
.eyebrow--lg { font-size: var(--text-xs); }

/* Four tracks on a pack row, three on a plan row. The plan rows used to carry an empty 50px span to hold
   the pack rows' button track open; it aligned the two price columns at 1183 and left every plan row
   stopping 65px short of its own card. Dropping the track lands them on 1247, where the Buy buttons end. */
.prow { grid-template-columns: minmax(0, 1fr) auto minmax(78px, max-content) auto; }
.prow--plan { grid-template-columns: minmax(0, 1fr) auto minmax(78px, max-content); }
/* The pack's own rate, under its name, rather than a second mono cell: a fifth track would put the
   price column in a different place on the two tables sitting one above the other. */
.prow__note { display: block; font-style: normal; font-size: var(--text-s); color: var(--faint); }
.packtable > .btn { margin-top: var(--space-3); }
.prow > .btn { min-width: 50px; }
@media (max-width: 560px) {
  .prow, .prow--plan { grid-template-columns: minmax(0, 1fr) auto; row-gap: var(--space-2); }
  /* The rate takes max-content off the second track — 162.8px of "3 credits · $133 each" against a
     320px viewport, which left the plan name 69.3px and wrapped the Starter Pack's note to five lines.
     Its own row instead: the name reads at 182px, and the row is 30px shorter than the wrapped one. */
  .prow .mono { grid-column: 1 / -1; }
  .prow > .btn { grid-column: 2; justify-self: end; }
}
.q > summary { min-height: 44px; }
@media (min-width: 641px) { .finding > summary > .tag { min-width: 84px; text-align: center; } }
@media (max-width: 640px) { .phero__cta .btn { flex: 1 1 100%; text-align: center; min-height: 44px; } }

.honest ul { max-width: 56ch; }
:where(.hint) { max-width: 72ch; }

.nav__links a:focus-visible,
.nav__signin:focus-visible,
.auds .pill:focus-visible,
.q > summary:focus-visible,
/* 0bz0 V5: the seven finding rows and the two brand links matched none of these and fell back to
   Chrome's auto 1px ring at zero offset — half the thickness, tight inside an already-bordered card. */
.finding > summary:focus-visible,
.brand:focus-visible,
.foot .pagelinks a:focus-visible,
nav[aria-label='Legal'] a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
.navmenu__list a:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }

@media (max-width: 560px) { .nav__in { gap: var(--space-2); } }
@media (min-width: 1001px) { .tcard__h { min-height: 2.24em; } }
.doors { grid-template-rows: auto auto auto auto; }
.door { grid-row: span 4; box-shadow: 1px 1px 0 var(--hairline); }
.door__go { font-size: var(--text-xs); color: var(--accent-text); margin-top: var(--space-2); align-self: end; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 30;
  padding: var(--space-2) var(--space-4);
  background: var(--bg); color: var(--ink);
  border: 1px solid var(--ink); border-radius: 6px;
  font-family: var(--font-body); font-size: var(--text-m); text-decoration: none;
}
.skip:focus { left: var(--space-3); top: var(--space-3); }

@media (prefers-color-scheme: dark) {
  html:not([data-theme='light']) {
  --bg:#0c0c0c;
  --surface:#141413;
  --surface-2:#1c1b19;
  --ink:#f4f1ea;
  --muted:#c9c4b8;
  --faint:#9a988f;
  --line:#3a3936;

  --accent-text:#c6ff00;
  --on-fill:#0c0c0c;

  --success:#4ecb8b;
  --success-bg:#15251c;
  --success-chip:#1e3527;
  --warn-ink:#e3c569;
  --warn-bg:#2a2413;
  --warn-line:#4a3f1d;
  --danger-bg:#31171b;
  --hairline:#2b2a27;
  --hairline-soft:#232220;
  --disabled-bg:#1d1c19;
  --disabled-line:#3a3936;
  --disabled-ink:#6d6d6d;
  /* `p2tw` V4: #7d7b74 measured 4.06:1 on `--inv-bg` in dark, under AA, across six elements on the
     `#run` band. 5.66:1 now, against 6.43 in light where it was already fine. */
  --ghost-ink:#96948b;
  --pink-text:#ff6aa8;

  --shadow-hard:2px 2px 0 #45443d;
  --shadow-press:1px 1px 0 #45443d;
  --shadow-float:0 22px 48px -30px #000;

  /* The one recovered value that was then changed. Derived (`--inv-bg:var(--ink)`) it is a cream slab, and
     there are 24 of these bands — too loud. The deleted block said `#000`, a 0.4% luminance step from the
     page, so the band would read as the page. `--surface-2` is the step this palette already uses to lift a
     surface; cream on it is 15.3:1. */
  --inv-bg:#1c1b19;
  --inv-ink:#f4f1ea;

  /* The marker sweep does not survive the flip unchanged, though it derives from `--acid`: 52% acid over
     cream is a bright swipe with dark text, while 52% over #0c0c0c is a muddy olive carrying cream text at
     4.4:1 — a redaction bar rather than a highlight. A background token cannot flip the text, so it goes the
     other way: a quiet acid wash at 26%, which measures 8.1:1 with the gesture unchanged. */
  --highlighter:linear-gradient(to top,color-mix(in oklab,var(--acid) 26%,transparent) 58%,transparent 58%);
  }
}