/* =============================================================================
   site-tokens.css  ·  THE TOKEN CONTRACT (shared)
   =============================================================================
   Extracted VERBATIM from landing.html's first inline <style> (2026-07-27,
   WP: site-wide chrome unification). This file is the ONE governing vocabulary
   for the public site: easings, durations, stagger, ambient loop periods, the
   type scale, tracking, radii, z-bands, the single accent, the ink ladder and
   the spacing rhythm. landing.html now <link>s this file instead of inlining
   the block; every other public page links it too, so the shared header and
   footer render from the same numbers everywhere.

   LOAD ORDER (important):
     Link this FIRST, before design-system.css / any page stylesheet.
     Eight names in this contract also exist in design-system.css with
     DIFFERENT values (--space-1..7, --z-header). On pages that load both,
     design-system.css must win those eight, or every base.html-derived page's
     spacing utilities shift. site-chrome.css therefore never reads those eight
     names — it carries chrome-private mirrors (--sh-*) of the three whose
     values actually differ. See the note at the top of site-chrome.css.

   The JS mirror of the MOTION half still lives inline in landing.html
   (window.MOTION) — CSS and JS must never drift.
   ============================================================================= */

/* Global typography tokens (upgrade). Display headlines -> Clash Display;
   UI/body -> General Sans; data/labels stay JetBrains Mono. Per-scope sans
   tokens below are repointed at --font-ui; individual headline selectors opt
   into --font-display, so the split is: big H2s = Clash, everything else UI. */
:root {
  --font-display: 'Clash Display', 'General Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-ui:      'General Sans', 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, Menlo, monospace;
}

/* ========================================================================
   THE TOKEN CONTRACT   ·   Phase A · WP-A2                (2026-07-25)
   ------------------------------------------------------------------------
   ONE governing vocabulary for the whole page. Every act, every fragment,
   every canvas reads from here. Nothing below this block may introduce a
   new curve, duration, type size, radius, z-band or accent — if a value is
   missing from the contract, the contract changes, not the call site.

   Research basis: FUCH-DISSECTION.md (premium reads come from constraint:
   2 fonts, ~6 type sizes, a tight tracking table, 5 radii, 9 z-indices,
   6 easings, ONE accent) + STUDIO-METHODOLOGY.md (a shared motion token
   contract is what makes 50 animations feel like one hand).

   Pre-A2 the page carried the SAME brand curve under four different names
   (--wim-ease / --ac-ease / --a-ease / --act9-e), five stagger step sizes,
   27 durations, 47 type sizes, 15 radii and 3 gradient angles. Full
   inventory + rationale: redesign/deep-research/TOKEN-AUDIT.md
   ------------------------------------------------------------------------
   The JS mirror of the MOTION half of this block lives in window.MOTION
   (see the `THE TOKEN CONTRACT · JS MIRROR` script near </body>). CSS and
   JS must never drift: --ease-inout and MOTION.easeInOut are the same
   curve expressed two ways.
   ======================================================================== */
:root {
  /* ---- EASING · 6 timing functions, total ---------------------------- */
  --ease-out:     cubic-bezier(.4, 0, .2, 1);    /* THE brand curve. Default for every state
                                                    change, hover and content reveal (~95%). */
  --ease-inout:   cubic-bezier(.65, 0, .35, 1);  /* easeInOutCubic. Symmetric journeys and yoyo
                                                    loops. Analytic twin of MOTION.easeInOut —
                                                    the traveling mark's flourish/travel curve. */
  --ease-drift:   cubic-bezier(0, 0, .58, 1);    /* long single-shot ambient drift (Ken-Burns) */
  --ease-linear:  linear;                        /* constant rate: progress, marquee, blink */
  --steps-grain:  steps(8);                      /* grain texture clock — see --loop-grain */
  --steps-blink:  steps(1);                      /* hard on/off caret */
  /* No spring/overshoot curve: the page has no overshoot micro-interaction today and adding
     one would be a visible change rather than a snap. See TOKEN-AUDIT.md decision note D7. */

  /* ---- DURATIONS · 6 steps ------------------------------------------ */
  --dur-1: 150ms;   /* instant — engine button transform                        */
  --dur-2: 300ms;   /* fast    — hover + state change          (was .25/.28/.3) */
  --dur-3: 400ms;   /* base    — component transitions   (was .35/.38/.4/.42/.45)*/
  --dur-4: 500ms;   /* slow    — card lift, overlay text            (was .5/.6) */
  --dur-5: 700ms;   /* reveal  — content rise                   (was .7/.72/.8) */
  --dur-6: 900ms;   /* section — section reveal + media x-fade  (was .9/1s/1.1s)*/
  /* EXEMPT from this scale: the scroll-SCRUBBED mappings (the hero film's clip time, the mark
     layer's pFlourish/pTravel windows, the helix drift) — they are driven by scroll position,
     not by a clock. Their EASING still joins the contract. */

  /* ---- STAGGER · 3 steps -------------------------------------------- */
  --stagger-lead:  50ms;    /* first child's lead-in                    (was .05s / .06s) */
  --stagger-unit:  50ms;    /* many items (>4): split words, act9 rise, act6-8 cards       */
  --stagger-block: 100ms;   /* short block runs (<=4): eyebrow > title > lede > stage      */

  /* ---- AMBIENT LOOP PERIODS ----------------------------------------- */
  --loop-blink:      1s;
  --loop-pulse:      2s;
  --loop-pulse-slow: 2.4s;
  --loop-scan:       3.6s;
  --loop-twinkle:    5s;
  --loop-kenburns:   9s;
  --loop-glow:       26s;
  --loop-sheen:      14s;   /* WP-A3 T2: slow specular traverse across a glass surface */
  --loop-breath:     11s;   /* WP-A3 T2: the page's ONE background heartbeat (JS clock,
                               mirrored as MOTION.loopBreath, see the JS contract) */
  --breath-tick:    110ms;  /* how often the heartbeat is WRITTEN (~9Hz). Readers
                               transition over exactly this, so the write rate is
                               invisible. Mirrored as MOTION.breathTick. */
  --loop-mark:        7s;   /* BEAT 1: the baked mark's idle float (±6px) */
  --loop-marquee:    42s;
  --loop-grain:      .5s;   /* EXEMPT from --dur-*: 8 steps / .5s == 16 steps/s, which is
                               exactly the GL lens grain clock (floor(uTime*16.) in LENS_FRAG).
                               These two numbers are calibrated together — change both or
                               neither, or the DOM grain and the canvas grain desync. */
  /* wimFloat 6 / 6.5 / 7 / 7.5 / 8s with negative delays -1/-2/-3/-4s is DELIBERATE phase
     decorrelation (four chips must not bob in lockstep). Exempt by design. */

  /* ---- TYPE · display 5 · UI 6 · mono 3 · numerals 3 ----------------
     RULE: Clash Display is DISPLAY ONLY (headlines + the two wordmarks).
           General Sans is everything UI/body. JetBrains Mono is labels,
           data and numerals. No exceptions. */
  --type-d1: clamp(2.25rem, 5.4vw, 3.875rem);   /* 36 > 62px  final CTA headline   */
  --type-d2: clamp(2rem,    5vw,   3.5rem);     /* 32 > 56px  act headline         */
  --type-d3: clamp(1.9rem,  4.2vw, 3.125rem);   /* 30 > 50px  section title        */
  --type-d4: clamp(1.75rem, 3.6vw, 2.875rem);   /* 28 > 46px  act9 title           */
  --type-d5: 1.0625rem;                         /* 17px       display wordmark     */

  --type-u1: clamp(1.5rem, 2.4vw, 2rem);        /* 24 > 32px  feature card title   */
  --type-u2: clamp(1.125rem, 1.5vw, 1.3125rem); /* 18 > 21px  card title/tier name */
  --type-u3: clamp(1rem, 1.4vw, 1.125rem);      /* 16 > 18px  lede / large body    */
  --type-u4: 1rem;                              /* 16px       body                 */
  --type-u5: .875rem;                           /* 14px       small body, buttons  */
  --type-u6: .8125rem;                          /* 13px       fine print, lists    */

  --type-m1: clamp(.9375rem, 1.6vw, 1.0625rem); /* 15 > 17px  mono data / question */
  --type-m2: .75rem;                            /* 12px       eyebrows, chips      */
  --type-m3: .6875rem;                          /* 11px       micro labels         */

  --type-n1: clamp(2.5rem, 4.4vw, 3.625rem);    /* 40 > 58px  act6 index numeral   */
  --type-n2: 2.5rem;                            /* 40px       act9 price amount    */
  --type-n3: 1.25rem;                           /* 20px       act9 currency mark   */

  --track-display: -.02em;   /* every Clash headline           */
  --track-tight:   -.01em;   /* large UI titles                */
  --track-data:     .02em;   /* mono values, chips, tags       */
  --track-label:    .14em;   /* mono micro labels              */
  --track-eyebrow:  .22em;   /* mono eyebrows  (// LABEL)      */
  --track-logo:     .34em;   /* preloader wordmark only        */

  --lh-display: 1.02;
  --lh-tight:   1.3;
  --lh-snug:    1.5;
  --lh-body:    1.6;

  /* ---- RADII · 5 + circle ------------------------------------------- */
  --r-xs:   2px;    /* hairline bars (2-6px tall) */
  --r-sm:   6px;
  --r-md:  12px;
  --r-lg:  16px;
  --r-pill: 999px;  /* replaces the old 100px/999px split */
  --r-full: 50%;    /* circles */

  /* ---- Z-BANDS ·  0-60 belongs to the ENGINE (@layer sw) -------------
     sky 0 · stage 10 · [vignette 15, HOST] · copylayer 20 · hint 30 ·
     topbar 50 · scrollbar/route 60.  Host layers live at 70 and above,
     except --z-film-vignette which is deliberately inside the engine band
     (over the film, under the film's copy). Ordering that must hold:
     content < grain < rail < header < preloader.
     (The old --z-mark:120 band belonged to the fixed traveling-mark canvas.
     The mark is now a baked element INSIDE its section's content, so it needs
     no band of its own — see BEATS 1-4.)
     --z-header is the site header (the page's ONE navigation chrome). It sits
     ABOVE the rail because its mobile drawer is a full-viewport sheet that has
     to cover the rail's dots, and BELOW the preloader because the header is
     not allowed to be visible during the boot scene.

     --z-modal-backdrop is the MODAL band: everything modal (the shared
     disclaimer overlay, css/disclaimer.css) and anything a modal raises above
     itself (validation toasts at +40). It is defined here — at root context —
     rather than left to disclaimer.css's `var(--z-modal-backdrop, 2000)`
     fallback, so the band is visible to anyone adding chrome: a modal takes the
     whole viewport and must outrank grain, rail and header. Nothing but the
     preloader is allowed above it. Full ordering that must hold:
     content < grain < rail < header < modal-backdrop < modal-toast < preloader.
     A modal only gets this authority when it is a direct child of <body>: a
     `position: fixed` overlay nested inside a transformed / filtered /
     will-change ancestor is captured by that ancestor's containing block AND
     its stacking context, and no z-index here can rescue it. */
  --z-film-vignette:   15;
  --z-content:         70;
  --z-grain:          300;
  --z-rail:           500;
  --z-header:         600;
  --z-modal-backdrop: 2000;
  --z-preloader:     9999;

  /* ---- ACCENT · ONE cyan --------------------------------------------- */
  --accent:         #00f2fe;
  --accent-2:       #58b9ff;              /* gradient far end / secondary — never solo */
  --accent-line:    rgba(0,242,254,.24);  /* hairline border      */
  --accent-line-hi: rgba(0,242,254,.5);   /* hover/active border  */
  --accent-wash:    rgba(0,242,254,.06);  /* fill wash            */
  --accent-glow:    rgba(0,242,254,.35);  /* glow / shadow        */
  --accent-2-tint:  #9bd5ff;              /* accent-2 lightened ~40% toward white, gradient tail only */
  --grad-accent:    linear-gradient(120deg, var(--accent) 0%, var(--accent-2) 100%);
  --grad-accent-x:  linear-gradient(90deg,  var(--accent) 0%, var(--accent-2) 100%);

  /* ---- TEXT ALPHA · ONE ladder, four steps -------------------------------
     WP-A3 T3.1. Four fragments each shipped their own near-miss ladder
     (act4/5 .98/.85/.6/.4 · act6-8 .96/.72/.5/.38 · act9 1/.85/.6/.4 ·
     WIM .74/.6/.82). act9 already sat on the brand ladder, so it is the
     reference and everything else snapped to it. Every snap moved UP, so
     contrast strictly improved, nothing needed a legibility exemption. The
     one judgement call is act6-8's .72 body step, which is very slightly
     nearer .6 than .85 numerically but carries an explicit "bumped from .6,
     fixes low contrast" note in its own source; snapping it DOWN would have
     re-broken that fix, so it went up. */
  --ink-1: rgba(255,255,255,1);    /* headings, primary                        */
  --ink-2: rgba(255,255,255,.85);  /* body                                     */
  --ink-3: rgba(255,255,255,.6);   /* secondary / lede on dark                 */
  /* W5.2 — was .4. Measured on the live landing against the page's darkest
     background (#070a1c) every --ink-4 consumer sat at 3.77:1, i.e. below the
     4.5:1 that WCAG 1.4.3 requires for text under 24px: the ABN lines, the
     act9 "/mo" suffix, the act9 disclaimer, the act4 terminal hint, the footer
     column headings and the terminal input's placeholder. .46 is the smallest
     step on this ladder that clears 4.5:1 on BOTH page blacks (#070a1c ->
     4.65:1, #0c0f21 -> 4.65:1); .45 measures 4.49:1 and misses. Fixed at the
     token, not per call site, so the whole fine-print tier moves together and
     nothing here re-introduces a one-off grey. */
  --ink-4: rgba(255,255,255,.46);  /* fine print, disabled                     */
  /* VIOLET RULE: #764ba2 is a MARK colour, not a UI accent. Permitted ONLY inside the Mirror
     mark itself (preloader logo gradient, favicon) and as the data-semantic down-colour on the
     helix's synthetic chart textures. Never a UI accent, border, glow or section atmosphere. */
  --mark-violet:    #764ba2;

  /* ---- SPACING RHYTHM ------------------------------------------------ */
  --section-pad-y: clamp(72px, 9vw, 132px);
  --section-pad-x: clamp(20px, 5vw, 80px);
  --space-1:  4px; --space-2:  8px; --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 40px; --space-7: 64px;
  /* The right gutter the fixed section rail actually occupies: its offset
     (max 26px) + the dot (20px) + the ACTIVE dot's label, which is shown, not
     hovered (up to ~134px at --type-m3 + --track-label) + breathing room.
     Any section whose content reaches the right edge must reserve this or the
     rail label lands on top of it. Measured, not guessed — see the WIM stage. */
  --rail-safe: 216px;

  /* ---- LIVE SIGNALS · written by JS, read by CSS (WP-A3 T2) -------------
     Two numbers, one writer (the `surface life` rAF near </body>), several
     readers. They are the reason the page's ambient layers move as ONE
     thing rather than as a dozen unrelated loops.
       --breath  0..1  the shared background heartbeat, period --loop-breath
       --scrollv 0..1  smoothed scroll speed, decays with MOTION.decayScroll
     Under reduced motion the writer never starts and these initial values
     are what the page renders: a settled, static frame. */
  --breath:  1;
  --scrollv: 0;
}
