/* ═══════════════════════════════════════════════════════════════════════════
   gw-tokens.css — THE TOKEN LAYER, LINKED FROM EVERY PUBLIC ROUTE
   WS-0 · 2026-08-11 · closes F-027 and F-028, and carries the site-wide half
   of F-015.

   WHAT WAS WRONG
   `<style id="gw-sys-tokens">` was emitted by exactly two modules —
   templates/sx_home.py (`_GWE_TOKENS`) and templates/sx_oneshot_editorial.py —
   plus the blog article shell. Counted on the rendered routes, not read from
   source: `/` 1, `/oneshot` 1, `/oneshot/exposed` 1, and 0 on `/pricing`,
   `/features`, `/about`, `/compare`, `/trust`, `/how-it-works`, `/security`,
   `/faq`, `/reviews`, `/register`, `/terms`, `/privacy`, `/login`,
   `/how-removals-work`, `/vs/incogni` and `/coverage`.

   The served HTML on those pages still REFERENCED the layer: `/about` 217
   times, `/features` 73, `/reviews` 45, `/pricing` 40. Every one of them fell
   through to the literal typed beside it, so the design system was in effect
   on three pages and inert on the rest — with no visual symptom, because a
   var() fallback renders exactly like a working token. Changing a token
   changed three pages and looked complete in the diff.

   ═══ WHY THIS FILE DECLARES NOTHING AT :root ═══

   The obvious implementation — one theme at `:root` — was written, linked and
   MEASURED, and it turned /pricing near-black. Recording the failure here
   because it is invisible in review and the next person will reach for it:

     gw-editorial.css declares its paper aliases at :root, reading the tokens:
       :root{ --gw-paper:var(--gw-sys-color-base,#F7F6F4);
              --gw-body:var(--gw-sys-color-text-body,#2E3338); … }
     and then `.gwe{background:var(--gw-paper);color:var(--gw-body)}`.
     A custom property is substituted on the element where it is DECLARED, so
     those aliases resolve against :root and inherit the result downward.
     Declaring the dark theme at :root therefore made --gw-paper #08090A and
     --gw-body #CBD0D6, and the editorial paper wrapper computed
     `background: rgb(8,9,10)` on /pricing. Measured in Chromium, not reasoned
     about.

   The mirror-image failure is just as real. sentinel.css declares
       :root{ --sx-accent:var(--gw-sys-color-text-high, var(--sx-txt)); … }
   and spends --sx-accent on button fills, list markers and the wordmark. The
   same substitution rule means a LIGHT theme at :root would resolve that to
   #111316 and inherit near-black fills into the near-black `.sx` estate.

   So there is no theme that is correct at :root for this site, and both wrong
   answers are silent. The tokens are declared on the two page-family
   WRAPPERS instead — which is where the surfaces actually are, and which
   leaves every :root-resolved alias in both stylesheets computing exactly
   what it computed before this file existed.

     .gwe                      → LIGHT   (editorial paper)
     .gwe <near-black bands>   → DARK    (the bands standing on the paper)
     .sx, .sx-app              → DARK    (Sentinel: blog, legal, auth, /reviews)
     [data-theme=light] .sx    → LIGHT   (the Sentinel theme toggle)

   `.gwe` light is not a new decision: gw-editorial.css already declares the
   eight core colour tokens on that wrapper and the dark ones on the band
   list, for exactly this reason. This completes the set — signal, focus, the
   severity ramp, type, space, radius, motion, measure — which until now fell
   through to whatever literal each component was authored with, and
   components_illustration._resolve() bakes theme='dark' by default. That is
   how .gwl-plate__t came to paint #F3F4F6 on /pricing's #F0EEEA band:
   1.11:1 on a 41.6px headline.

   ONE CONSEQUENCE WORTH STATING, AND IT AMENDS THE CONTRACT.
   DESIGN.md §1.1 gives the acceptance test as
   `getComputedStyle(document.documentElement).getPropertyValue(
   '--gw-sys-color-signal') === '#AF5125'`. That snippet assumes a single
   :root theme and cannot be satisfied without the failure above. Do not
   weaken it in place and do not quietly skip it — the replacement is ratified
   in DESIGN_AMENDMENTS.md A-1, with the falsification of both alternatives
   measured on rendered routes:

       const w = document.querySelector('.gwe, .sx, .sx-app');
       const light = w.matches('.gwe') || !!w.closest('[data-theme="light"]');
       getComputedStyle(w).getPropertyValue('--gw-sys-color-signal').trim()
         === (light ? '#AF5125' : '#D9703F')

   closest(), not w.dataset.theme: the Sentinel theme toggle sets data-theme
   on <html>, not on the .sx wrapper, so reading it off the wrapper fails on
   /register and /login — the two routes that clause exists to cover. Run at
   20 of 20 routes and mutation-checked (abort the request, every route reds).

   Measured per family: `.gwe` → #AF5125 on / /oneshot /oneshot/exposed
   /pricing /features /about /compare; `.sx` → #D9703F on /trust
   /how-it-works /reviews /terms /privacy /how-removals-work /vs/incogni and
   the blog; `.sx[data-theme=light]` → #AF5125 on /register and /login.
   The two clays are not interchangeable — on paper #AF5125 is 4.83:1 and
   #D9703F 3.07:1; on near-black #D9703F is 5.97:1 and #AF5125 3.79:1.

   COVERAGE: 20 of 20 audited public routes, as of 6611c948. It was 16 of 20
   at the commit that added this file — /faq, /security and /contact rendered
   hand-rolled <head>s and never called sx_head(), and /coverage rendered a
   `.gwe` wrapper whose --gw-sys-color-signal computed "", F-027's own
   silent-failure shape. WS-6's 181116fc closed all four. So the guard test
   takes NO route exception list; see DESIGN_AMENDMENTS.md A-2, which also
   records why the exception list it originally carried went stale in two
   commits.

   TWO CORRECTIONS APPLIED ON TOP OF components_tokens.py (F-028)
   `--gw-sys-type-font-sans` is declared there as
   `system-ui, -apple-system, 'Segoe UI', Roboto, …` — no Inter. The canonical
   font token was not the brand font, so a component that correctly honoured
   it got the wrong result: 10 visible elements on `/`, all inside `.gwb-*` —
   the GalaxyWarden / Optery / Incogni comparison bars, the most persuasive
   block on the homepage — computed `fontFamily: system-ui`. It is corrected
   here, and `--gw-sys-type-font-display` (Space Grotesk) is added, which the
   token table never had at all. **The canonical fix belongs in
   templates/components_tokens.py:195**; that file is outside this
   workstream's ownership, so it is corrected here and flagged there.
   Declaring it on the wrappers also means it survives on `/` and `/oneshot`,
   whose inline `_GWE_TOKENS` re-declares the uncorrected family at :root
   after this link: `.gwb-*` lives inside `.gwe`, and a declaration on that
   wrapper wins for its whole subtree regardless of source order.

   HOW TO REGENERATE — do not hand-edit the declaration blocks.
   templates/components_tokens.py remains THE source of truth for values; this
   file is generated from it. The generator is in scratchpad/build/WS-0.md. A
   guard test asserting this file equals `tokens_css()` for all four selectors,
   and that the band list still matches `_GWE_DARK_BANDS`, belongs in WS-10.

   LOAD ORDER — linked BEFORE sentinel.css and gw-editorial.css by sx_head().
   gw-editorial.css re-declares the eight core colour tokens on `.gwe` and on
   the dark bands with identical values; loading it second keeps that a no-op
   rather than a fight.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · .gwe — LIGHT. The editorial pages are printed on paper
   (--gw-sys-color-base #F7F6F4). ──────────────────────────────────────── */
.gwe{
  --gw-sys-color-base:#F7F6F4;
  --gw-sys-color-surface:#FFFFFF;
  --gw-sys-color-raised:#F0EEEA;
  --gw-sys-color-line:#DDD9D3;
  --gw-sys-color-line-strong:#5D6773;
  --gw-sys-color-text-high:#111316;
  --gw-sys-color-text-body:#2E3338;
  --gw-sys-color-text-mute:#5B636B;
  --gw-sys-color-signal:#AF5125;
  --gw-sys-color-on-signal:#FFFFFF;
  --gw-sys-color-on-high:#F7F6F4;
  --gw-sys-color-focus:#111316;
  --gw-sys-sev-critical:#CF242A;
  --gw-sys-sev-high:#AF5125;
  --gw-sys-sev-medium:#87650F;
  --gw-sys-sev-low:#5B636B;
  --gw-sys-type-d0-size:clamp(3.25rem, 2rem + 5.5vw, 7rem);
  --gw-sys-type-d0-weight:300;
  --gw-sys-type-d0-leading:0.96;
  --gw-sys-type-d0-tracking:-0.03em;
  --gw-sys-type-d1-size:clamp(2.5rem, 1.6rem + 4.2vw, 4.75rem);
  --gw-sys-type-d1-weight:300;
  --gw-sys-type-d1-leading:1.02;
  --gw-sys-type-d1-tracking:-0.03em;
  --gw-sys-type-d2-size:clamp(2.125rem, 1.5rem + 2.6vw, 3.5rem);
  --gw-sys-type-d2-weight:300;
  --gw-sys-type-d2-leading:1.06;
  --gw-sys-type-d2-tracking:-0.025em;
  --gw-sys-type-h1-size:clamp(1.75rem, 1.4rem + 1.5vw, 2.625rem);
  --gw-sys-type-h1-weight:350;
  --gw-sys-type-h1-leading:1.15;
  --gw-sys-type-h1-tracking:-0.02em;
  --gw-sys-type-h2-size:clamp(1.5rem, 1.35rem + 0.6vw, 1.875rem);
  --gw-sys-type-h2-weight:400;
  --gw-sys-type-h2-leading:1.25;
  --gw-sys-type-h2-tracking:-0.01em;
  --gw-sys-type-lead-size:clamp(1.1875rem, 1.1rem + 0.35vw, 1.375rem);
  --gw-sys-type-lead-weight:400;
  --gw-sys-type-lead-leading:1.5;
  --gw-sys-type-lead-tracking:0;
  --gw-sys-type-body-size:clamp(1.0625rem, 1.03rem + 0.12vw, 1.125rem);
  --gw-sys-type-body-weight:400;
  --gw-sys-type-body-leading:1.6;
  --gw-sys-type-body-tracking:0;
  --gw-sys-type-body-s-size:0.9375rem;
  --gw-sys-type-body-s-weight:400;
  --gw-sys-type-body-s-leading:1.55;
  --gw-sys-type-body-s-tracking:0;
  --gw-sys-type-caption-size:0.8125rem;
  --gw-sys-type-caption-weight:400;
  --gw-sys-type-caption-leading:1.45;
  --gw-sys-type-caption-tracking:0.01em;
  --gw-sys-type-micro-size:0.6875rem;
  --gw-sys-type-micro-weight:600;
  --gw-sys-type-micro-leading:1.2;
  --gw-sys-type-micro-tracking:0.09em;
  --gw-sys-type-font-sans:'Inter','Inter Fallback',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --gw-sys-type-numeric:tabular-nums lining-nums;
  --gw-sys-type-num-weight:500;
  --gw-sys-measure-body:66ch;
  --gw-sys-measure-lead:52ch;
  --gw-sys-measure-display:14ch;
  --gw-sys-space-4:4px;
  --gw-sys-space-8:8px;
  --gw-sys-space-12:12px;
  --gw-sys-space-16:16px;
  --gw-sys-space-24:24px;
  --gw-sys-space-32:32px;
  --gw-sys-space-48:48px;
  --gw-sys-space-64:64px;
  --gw-sys-space-96:96px;
  --gw-sys-space-128:128px;
  --gw-sys-space-192:192px;
  --gw-sys-gap-component:12px;
  --gw-sys-gap-block:clamp(3rem, 2.2rem + 2vw, 4rem);
  --gw-sys-gap-section:clamp(4rem, 2rem + 8vw, 8rem);
  --gw-sys-page-margin:clamp(1.25rem, 1rem + 1vw, 1.5rem);
  --gw-sys-gutter:clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
  --gw-sys-container-max:1200px;
  --gw-sys-tap-min:44px;
  --gw-sys-dur-micro:120ms;
  --gw-sys-dur-base:200ms;
  --gw-sys-dur-exit:160ms;
  --gw-sys-dur-signature:320ms;
  --gw-sys-ease-out:cubic-bezier(.2, 0, 0, 1);
  --gw-sys-ease-in:cubic-bezier(.4, 0, 1, 1);
  --gw-sys-radius-sm:4px;
  --gw-sys-radius-md:6px;
  --gw-sys-radius-lg:12px;
  --gw-sys-radius-pill:999px;
  --gw-sys-border-hair:1px;
  --gw-sys-focus-ring:2px;
  --gw-sys-focus-offset:2px;
  --gw-sys-type-font-display:'Space Grotesk','Space Grotesk Fallback','Inter',system-ui,-apple-system,sans-serif;
}
@media (prefers-reduced-motion: reduce){.gwe{--gw-sys-dur-micro:0ms;--gw-sys-dur-base:0ms;--gw-sys-dur-exit:0ms;--gw-sys-dur-signature:0ms;}}

/* ── 2 · the near-black bands INSIDE .gwe — DARK again. The band answers for
   the component, so a card does not have to know which section it is in.

   !! KEEP IDENTICAL to `_GWE_DARK_BANDS` in templates/sx_home.py and to the
   !! dark-surface selector list in gw-editorial.css. Three copies now, no
   !! error if they diverge, and the failure mode is near-black ink on a
   !! near-black card — measured at 1.04:1 the last two times it happened.
   !! Verified identical, all three, on 2026-08-11. ─────────────────────── */
.gwe .herodark,
.gwe .pipeband,
.gwe .inkband,
.gwe .tfoot.dark,
.gwe .scanbox,
.gwe .scanpanel,
.gwe .ocard,
.gwe .pcell,
.gwe .tl .tstep,
.gwe .rev,
.gwe .outcome,
.gwe details,
.gwe .masthead,
.gwe .mutil,
.gwe .mnav .mnav-m,
.gwe .mnav-d .mnav-dl,
.gwe .mnav-d[open] summary,
.gwe .ticker,
.gwe .outwrap.gamer{
  --gw-sys-color-base:#08090A;
  --gw-sys-color-surface:#101215;
  --gw-sys-color-raised:#181B1F;
  --gw-sys-color-line:#262A2F;
  --gw-sys-color-line-strong:#5D6773;
  --gw-sys-color-text-high:#F3F4F6;
  --gw-sys-color-text-body:#CBD0D6;
  --gw-sys-color-text-mute:#8B929A;
  --gw-sys-color-signal:#D9703F;
  --gw-sys-color-on-signal:#08090A;
  --gw-sys-color-on-high:#08090A;
  --gw-sys-color-focus:#F3F4F6;
  --gw-sys-sev-critical:#E4666A;
  --gw-sys-sev-high:#D9703F;
  --gw-sys-sev-medium:#B48714;
  --gw-sys-sev-low:#8B929A;
  --gw-sys-type-d0-size:clamp(3.25rem, 2rem + 5.5vw, 7rem);
  --gw-sys-type-d0-weight:300;
  --gw-sys-type-d0-leading:0.96;
  --gw-sys-type-d0-tracking:-0.03em;
  --gw-sys-type-d1-size:clamp(2.5rem, 1.6rem + 4.2vw, 4.75rem);
  --gw-sys-type-d1-weight:300;
  --gw-sys-type-d1-leading:1.02;
  --gw-sys-type-d1-tracking:-0.03em;
  --gw-sys-type-d2-size:clamp(2.125rem, 1.5rem + 2.6vw, 3.5rem);
  --gw-sys-type-d2-weight:300;
  --gw-sys-type-d2-leading:1.06;
  --gw-sys-type-d2-tracking:-0.025em;
  --gw-sys-type-h1-size:clamp(1.75rem, 1.4rem + 1.5vw, 2.625rem);
  --gw-sys-type-h1-weight:350;
  --gw-sys-type-h1-leading:1.15;
  --gw-sys-type-h1-tracking:-0.02em;
  --gw-sys-type-h2-size:clamp(1.5rem, 1.35rem + 0.6vw, 1.875rem);
  --gw-sys-type-h2-weight:400;
  --gw-sys-type-h2-leading:1.25;
  --gw-sys-type-h2-tracking:-0.01em;
  --gw-sys-type-lead-size:clamp(1.1875rem, 1.1rem + 0.35vw, 1.375rem);
  --gw-sys-type-lead-weight:400;
  --gw-sys-type-lead-leading:1.5;
  --gw-sys-type-lead-tracking:0;
  --gw-sys-type-body-size:clamp(1.0625rem, 1.03rem + 0.12vw, 1.125rem);
  --gw-sys-type-body-weight:400;
  --gw-sys-type-body-leading:1.6;
  --gw-sys-type-body-tracking:0;
  --gw-sys-type-body-s-size:0.9375rem;
  --gw-sys-type-body-s-weight:400;
  --gw-sys-type-body-s-leading:1.55;
  --gw-sys-type-body-s-tracking:0;
  --gw-sys-type-caption-size:0.8125rem;
  --gw-sys-type-caption-weight:400;
  --gw-sys-type-caption-leading:1.45;
  --gw-sys-type-caption-tracking:0.01em;
  --gw-sys-type-micro-size:0.6875rem;
  --gw-sys-type-micro-weight:600;
  --gw-sys-type-micro-leading:1.2;
  --gw-sys-type-micro-tracking:0.09em;
  --gw-sys-type-font-sans:'Inter','Inter Fallback',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --gw-sys-type-numeric:tabular-nums lining-nums;
  --gw-sys-type-num-weight:500;
  --gw-sys-measure-body:66ch;
  --gw-sys-measure-lead:52ch;
  --gw-sys-measure-display:14ch;
  --gw-sys-space-4:4px;
  --gw-sys-space-8:8px;
  --gw-sys-space-12:12px;
  --gw-sys-space-16:16px;
  --gw-sys-space-24:24px;
  --gw-sys-space-32:32px;
  --gw-sys-space-48:48px;
  --gw-sys-space-64:64px;
  --gw-sys-space-96:96px;
  --gw-sys-space-128:128px;
  --gw-sys-space-192:192px;
  --gw-sys-gap-component:12px;
  --gw-sys-gap-block:clamp(3rem, 2.2rem + 2vw, 4rem);
  --gw-sys-gap-section:clamp(4rem, 2rem + 8vw, 8rem);
  --gw-sys-page-margin:clamp(1.25rem, 1rem + 1vw, 1.5rem);
  --gw-sys-gutter:clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
  --gw-sys-container-max:1200px;
  --gw-sys-tap-min:44px;
  --gw-sys-dur-micro:120ms;
  --gw-sys-dur-base:200ms;
  --gw-sys-dur-exit:160ms;
  --gw-sys-dur-signature:320ms;
  --gw-sys-ease-out:cubic-bezier(.2, 0, 0, 1);
  --gw-sys-ease-in:cubic-bezier(.4, 0, 1, 1);
  --gw-sys-radius-sm:4px;
  --gw-sys-radius-md:6px;
  --gw-sys-radius-lg:12px;
  --gw-sys-radius-pill:999px;
  --gw-sys-border-hair:1px;
  --gw-sys-focus-ring:2px;
  --gw-sys-focus-offset:2px;
  --gw-sys-type-font-display:'Space Grotesk','Space Grotesk Fallback','Inter',system-ui,-apple-system,sans-serif;
}
@media (prefers-reduced-motion: reduce){.gwe .herodark,
.gwe .pipeband,
.gwe .inkband,
.gwe .tfoot.dark,
.gwe .scanbox,
.gwe .scanpanel,
.gwe .ocard,
.gwe .pcell,
.gwe .tl .tstep,
.gwe .rev,
.gwe .outcome,
.gwe details,
.gwe .masthead,
.gwe .mutil,
.gwe .mnav .mnav-m,
.gwe .mnav-d .mnav-dl,
.gwe .mnav-d[open] summary,
.gwe .ticker,
.gwe .outwrap.gamer{--gw-sys-dur-micro:0ms;--gw-sys-dur-base:0ms;--gw-sys-dur-exit:0ms;--gw-sys-dur-signature:0ms;}}

/* ── 3 · .sx / .sx-app — DARK. The Sentinel family: the ~25k blog article
   pages, /reviews, /terms, /privacy, /register, /login, /trust,
   /how-it-works, /how-removals-work, /vs/incogni and the app shell.
   Every var(--gw-sys-*) reference on those pages is authored with the DARK
   literal as its fallback — 45 of 45 on /reviews, 7 of 7 on /terms — so this
   block resolves them to the identical value and the rendered result does not
   move. What it adds is that they are now TOKENS: a change to
   components_tokens.py finally reaches them.

   It also arms routes/blog.py:14636's shell bridge, which binds ~25 --sx-*
   variables to --gw-sys-* with `!important` and NO fallback. On a page where
   the tokens are undefined those declarations are invalid at computed-value
   time, so the bridge silently does nothing; the blog article shell emits its
   own tokens_css('dark', ':root') and is the reason it works there. ──── */
.sx,
.sx-app{
  --gw-sys-color-base:#08090A;
  --gw-sys-color-surface:#101215;
  --gw-sys-color-raised:#181B1F;
  --gw-sys-color-line:#262A2F;
  --gw-sys-color-line-strong:#5D6773;
  --gw-sys-color-text-high:#F3F4F6;
  --gw-sys-color-text-body:#CBD0D6;
  --gw-sys-color-text-mute:#8B929A;
  --gw-sys-color-signal:#D9703F;
  --gw-sys-color-on-signal:#08090A;
  --gw-sys-color-on-high:#08090A;
  --gw-sys-color-focus:#F3F4F6;
  --gw-sys-sev-critical:#E4666A;
  --gw-sys-sev-high:#D9703F;
  --gw-sys-sev-medium:#B48714;
  --gw-sys-sev-low:#8B929A;
  --gw-sys-type-d0-size:clamp(3.25rem, 2rem + 5.5vw, 7rem);
  --gw-sys-type-d0-weight:300;
  --gw-sys-type-d0-leading:0.96;
  --gw-sys-type-d0-tracking:-0.03em;
  --gw-sys-type-d1-size:clamp(2.5rem, 1.6rem + 4.2vw, 4.75rem);
  --gw-sys-type-d1-weight:300;
  --gw-sys-type-d1-leading:1.02;
  --gw-sys-type-d1-tracking:-0.03em;
  --gw-sys-type-d2-size:clamp(2.125rem, 1.5rem + 2.6vw, 3.5rem);
  --gw-sys-type-d2-weight:300;
  --gw-sys-type-d2-leading:1.06;
  --gw-sys-type-d2-tracking:-0.025em;
  --gw-sys-type-h1-size:clamp(1.75rem, 1.4rem + 1.5vw, 2.625rem);
  --gw-sys-type-h1-weight:350;
  --gw-sys-type-h1-leading:1.15;
  --gw-sys-type-h1-tracking:-0.02em;
  --gw-sys-type-h2-size:clamp(1.5rem, 1.35rem + 0.6vw, 1.875rem);
  --gw-sys-type-h2-weight:400;
  --gw-sys-type-h2-leading:1.25;
  --gw-sys-type-h2-tracking:-0.01em;
  --gw-sys-type-lead-size:clamp(1.1875rem, 1.1rem + 0.35vw, 1.375rem);
  --gw-sys-type-lead-weight:400;
  --gw-sys-type-lead-leading:1.5;
  --gw-sys-type-lead-tracking:0;
  --gw-sys-type-body-size:clamp(1.0625rem, 1.03rem + 0.12vw, 1.125rem);
  --gw-sys-type-body-weight:400;
  --gw-sys-type-body-leading:1.6;
  --gw-sys-type-body-tracking:0;
  --gw-sys-type-body-s-size:0.9375rem;
  --gw-sys-type-body-s-weight:400;
  --gw-sys-type-body-s-leading:1.55;
  --gw-sys-type-body-s-tracking:0;
  --gw-sys-type-caption-size:0.8125rem;
  --gw-sys-type-caption-weight:400;
  --gw-sys-type-caption-leading:1.45;
  --gw-sys-type-caption-tracking:0.01em;
  --gw-sys-type-micro-size:0.6875rem;
  --gw-sys-type-micro-weight:600;
  --gw-sys-type-micro-leading:1.2;
  --gw-sys-type-micro-tracking:0.09em;
  --gw-sys-type-font-sans:'Inter','Inter Fallback',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --gw-sys-type-numeric:tabular-nums lining-nums;
  --gw-sys-type-num-weight:500;
  --gw-sys-measure-body:66ch;
  --gw-sys-measure-lead:52ch;
  --gw-sys-measure-display:14ch;
  --gw-sys-space-4:4px;
  --gw-sys-space-8:8px;
  --gw-sys-space-12:12px;
  --gw-sys-space-16:16px;
  --gw-sys-space-24:24px;
  --gw-sys-space-32:32px;
  --gw-sys-space-48:48px;
  --gw-sys-space-64:64px;
  --gw-sys-space-96:96px;
  --gw-sys-space-128:128px;
  --gw-sys-space-192:192px;
  --gw-sys-gap-component:12px;
  --gw-sys-gap-block:clamp(3rem, 2.2rem + 2vw, 4rem);
  --gw-sys-gap-section:clamp(4rem, 2rem + 8vw, 8rem);
  --gw-sys-page-margin:clamp(1.25rem, 1rem + 1vw, 1.5rem);
  --gw-sys-gutter:clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
  --gw-sys-container-max:1200px;
  --gw-sys-tap-min:44px;
  --gw-sys-dur-micro:120ms;
  --gw-sys-dur-base:200ms;
  --gw-sys-dur-exit:160ms;
  --gw-sys-dur-signature:320ms;
  --gw-sys-ease-out:cubic-bezier(.2, 0, 0, 1);
  --gw-sys-ease-in:cubic-bezier(.4, 0, 1, 1);
  --gw-sys-radius-sm:4px;
  --gw-sys-radius-md:6px;
  --gw-sys-radius-lg:12px;
  --gw-sys-radius-pill:999px;
  --gw-sys-border-hair:1px;
  --gw-sys-focus-ring:2px;
  --gw-sys-focus-offset:2px;
  --gw-sys-type-font-display:'Space Grotesk','Space Grotesk Fallback','Inter',system-ui,-apple-system,sans-serif;
}
@media (prefers-reduced-motion: reduce){.sx,
.sx-app{--gw-sys-dur-micro:0ms;--gw-sys-dur-base:0ms;--gw-sys-dur-exit:0ms;--gw-sys-dur-signature:0ms;}}

/* ── 4 · the Sentinel theme toggle. html[data-theme="light"] is set by
   SX_THEME_FOUC (templates/shared.py) and by sentinel.css:968. Specificity
   (0,2,1) beats the `.sx` block above without depending on source order.
   Without it, a reader who picks Light gets the dark token values inside a
   paper shell — and on a blog article, where the bridge in §3 binds --sx-bg
   and --sx-txt straight to the tokens, that is the whole page. ─────────── */
html[data-theme="light"] .sx,
html[data-theme="light"] .sx-app{
  --gw-sys-color-base:#F7F6F4;
  --gw-sys-color-surface:#FFFFFF;
  --gw-sys-color-raised:#F0EEEA;
  --gw-sys-color-line:#DDD9D3;
  --gw-sys-color-line-strong:#5D6773;
  --gw-sys-color-text-high:#111316;
  --gw-sys-color-text-body:#2E3338;
  --gw-sys-color-text-mute:#5B636B;
  --gw-sys-color-signal:#AF5125;
  --gw-sys-color-on-signal:#FFFFFF;
  --gw-sys-color-on-high:#F7F6F4;
  --gw-sys-color-focus:#111316;
  --gw-sys-sev-critical:#CF242A;
  --gw-sys-sev-high:#AF5125;
  --gw-sys-sev-medium:#87650F;
  --gw-sys-sev-low:#5B636B;
  --gw-sys-type-d0-size:clamp(3.25rem, 2rem + 5.5vw, 7rem);
  --gw-sys-type-d0-weight:300;
  --gw-sys-type-d0-leading:0.96;
  --gw-sys-type-d0-tracking:-0.03em;
  --gw-sys-type-d1-size:clamp(2.5rem, 1.6rem + 4.2vw, 4.75rem);
  --gw-sys-type-d1-weight:300;
  --gw-sys-type-d1-leading:1.02;
  --gw-sys-type-d1-tracking:-0.03em;
  --gw-sys-type-d2-size:clamp(2.125rem, 1.5rem + 2.6vw, 3.5rem);
  --gw-sys-type-d2-weight:300;
  --gw-sys-type-d2-leading:1.06;
  --gw-sys-type-d2-tracking:-0.025em;
  --gw-sys-type-h1-size:clamp(1.75rem, 1.4rem + 1.5vw, 2.625rem);
  --gw-sys-type-h1-weight:350;
  --gw-sys-type-h1-leading:1.15;
  --gw-sys-type-h1-tracking:-0.02em;
  --gw-sys-type-h2-size:clamp(1.5rem, 1.35rem + 0.6vw, 1.875rem);
  --gw-sys-type-h2-weight:400;
  --gw-sys-type-h2-leading:1.25;
  --gw-sys-type-h2-tracking:-0.01em;
  --gw-sys-type-lead-size:clamp(1.1875rem, 1.1rem + 0.35vw, 1.375rem);
  --gw-sys-type-lead-weight:400;
  --gw-sys-type-lead-leading:1.5;
  --gw-sys-type-lead-tracking:0;
  --gw-sys-type-body-size:clamp(1.0625rem, 1.03rem + 0.12vw, 1.125rem);
  --gw-sys-type-body-weight:400;
  --gw-sys-type-body-leading:1.6;
  --gw-sys-type-body-tracking:0;
  --gw-sys-type-body-s-size:0.9375rem;
  --gw-sys-type-body-s-weight:400;
  --gw-sys-type-body-s-leading:1.55;
  --gw-sys-type-body-s-tracking:0;
  --gw-sys-type-caption-size:0.8125rem;
  --gw-sys-type-caption-weight:400;
  --gw-sys-type-caption-leading:1.45;
  --gw-sys-type-caption-tracking:0.01em;
  --gw-sys-type-micro-size:0.6875rem;
  --gw-sys-type-micro-weight:600;
  --gw-sys-type-micro-leading:1.2;
  --gw-sys-type-micro-tracking:0.09em;
  --gw-sys-type-font-sans:'Inter','Inter Fallback',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --gw-sys-type-numeric:tabular-nums lining-nums;
  --gw-sys-type-num-weight:500;
  --gw-sys-measure-body:66ch;
  --gw-sys-measure-lead:52ch;
  --gw-sys-measure-display:14ch;
  --gw-sys-space-4:4px;
  --gw-sys-space-8:8px;
  --gw-sys-space-12:12px;
  --gw-sys-space-16:16px;
  --gw-sys-space-24:24px;
  --gw-sys-space-32:32px;
  --gw-sys-space-48:48px;
  --gw-sys-space-64:64px;
  --gw-sys-space-96:96px;
  --gw-sys-space-128:128px;
  --gw-sys-space-192:192px;
  --gw-sys-gap-component:12px;
  --gw-sys-gap-block:clamp(3rem, 2.2rem + 2vw, 4rem);
  --gw-sys-gap-section:clamp(4rem, 2rem + 8vw, 8rem);
  --gw-sys-page-margin:clamp(1.25rem, 1rem + 1vw, 1.5rem);
  --gw-sys-gutter:clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
  --gw-sys-container-max:1200px;
  --gw-sys-tap-min:44px;
  --gw-sys-dur-micro:120ms;
  --gw-sys-dur-base:200ms;
  --gw-sys-dur-exit:160ms;
  --gw-sys-dur-signature:320ms;
  --gw-sys-ease-out:cubic-bezier(.2, 0, 0, 1);
  --gw-sys-ease-in:cubic-bezier(.4, 0, 1, 1);
  --gw-sys-radius-sm:4px;
  --gw-sys-radius-md:6px;
  --gw-sys-radius-lg:12px;
  --gw-sys-radius-pill:999px;
  --gw-sys-border-hair:1px;
  --gw-sys-focus-ring:2px;
  --gw-sys-focus-offset:2px;
  --gw-sys-type-font-display:'Space Grotesk','Space Grotesk Fallback','Inter',system-ui,-apple-system,sans-serif;
}
@media (prefers-reduced-motion: reduce){html[data-theme="light"] .sx,
html[data-theme="light"] .sx-app{--gw-sys-dur-micro:0ms;--gw-sys-dur-base:0ms;--gw-sys-dur-exit:0ms;--gw-sys-dur-signature:0ms;}}

/* ── 5 · the two font aliases the codebase already reaches for, as literals
   rather than as var(--gw-sys-type-font-*): they are declared at :root, and
   :root deliberately carries no tokens (see the header). gw-editorial.css
   declares --gw-sans/--gw-disp itself with the same faces and loads after
   this file, so on the pages that link it these are a no-op; on the ones that
   do not — /reviews, /terms, /privacy, /register, /login, /trust,
   /how-it-works, /how-removals-work, /vs/incogni — they are what makes the
   rule below work. ─────────────────────────────────────────────────────── */
:root{
  --gw-sans:'Inter','Inter Fallback',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --gw-display:'Space Grotesk','Space Grotesk Fallback','Inter',system-ui,-apple-system,sans-serif;
}

/* ── 6 · THE BODY FONT (F-015), for the routes gw-editorial.css never reaches.
   Neither sentinel.css nor gw-editorial.css carried an `html`/`body`
   font-family until today: brand type reached glyphs only through `.gwe` and
   `.sx` descendant rules, so anything emitted outside those containers fell
   to the browser default serif. Measured on the rendered routes: the fixed
   $29 buy bar on /oneshot/exposed computed `fontFamily: "Times"`; `.gwsb-btn`
   computed Arial on /features and /vs/incogni; `.gwfilm__play` Arial on
   /about; 25-37 further system-font elements on /terms, /privacy, /faq and
   /contact. The twin rule in gw-editorial.css covers the pages that link it;
   this one covers the rest.

   THE FORM CONTROLS NEED THEIR OWN LINE, and this is the half of F-015 that a
   body rule cannot reach. Buttons and inputs do not inherit font-family: the
   UA stylesheet gives them `font: 400 13.333px Arial` and that beats
   inheritance, so declaring the body font fixes prose and leaves every control
   in Arial. Measured after the body rule landed and before this one:
   `.gwsb-btn` still computed Arial on /features, /vs/incogni and the blog
   article shell — the scan box's own submit button, i.e. the primary action on
   three surfaces. That is the Arial half of F-062, and it is fixed here rather
   than per-component. ──────────────────────────────────────────────────────── */
html,body{font-family:var(--gw-sans);}
button,input,select,textarea,optgroup{font-family:inherit;}
