/* =============================================================================
   tokens.css — the design system. Everything downstream reads from here.
   Owned by the UI agent. Consumed by site.css, base.css and js/game/*.
   =============================================================================

   HOW THIS IS ORGANISED
   ---------------------
   1. PRIMITIVES  Raw colour ramps. Never use these directly in a component.
                  Named after the subject, not the use: --pitch-*, --flare-*,
                  --beam-*, --dial-*, --chalk-*.
   2. SEMANTICS   What a thing IS, not what colour it happens to be:
                  --bg, --surface, --ink, --brand, --accent, --line, --focus.
                  Components use ONLY these. This is the layer that flips
                  between light and dark, so if you style from semantics you
                  get dark mode for free and cannot get it wrong.
   3. SCALES      Type, space, radius, shadow, motion, layout, z-index.

   THE RULE: light is defined in full on bare `:root`. Dark redefines ONLY the
   tokens whose VALUES change — never the scales, never the names. Both modes
   are first class; neither is a filter over the other.

   NAMING CONVENTIONS (the game agent relies on these)
   ---------------------------------------------------
     --x            the base colour of role x            (a fill or a line)
     --x-ink        text colour for role x ON the page   (AA against --bg)
     --x-on         text colour that sits ON a --x fill  (AA against --x)
     --x-tint       a faint wash of x, for panel backgrounds
     --x-edge       a border-strength x, for hairlines on tinted panels
     --x-strong     a heavier x that can carry white/near-white text

   CONTRAST BUDGET
   ---------------
   Every --*-ink token clears 4.5:1 against --bg in its own mode; --ink clears
   16:1. Readability wins every tie — a recruiter reads this on a phone in
   daylight. Vibrancy lives in fills, edges, glows and shapes, not in body text.

   MOTION
   ------
   --motion-ok is 1 normally and 0 under prefers-reduced-motion. Multiply
   distances by it (`translateY(calc(12px * var(--motion-ok)))`) and a single
   media query disables travel everywhere without a second code path.
   ========================================================================== */

:root {
  color-scheme: light;

  /* == 1. PRIMITIVES ======================================================= */

  /* Pitch — the brand green. Floodlit grass, pushed slightly to emerald so it
     reads as considered rather than as the default "team colour" green. */
  --pitch-50:  #eaf6ef;
  --pitch-100: #cfeadb;
  --pitch-200: #a3d8bc;
  --pitch-300: #6fc199;
  --pitch-400: #3aa274;
  --pitch-500: #178455;
  --pitch-600: #0e6e43;
  --pitch-700: #0a5634;
  --pitch-800: #073f26;
  --pitch-900: #052a1a;
  --pitch-950: #03180f;

  /* Flare — the hot accent. Vermilion, not red: it has to sit next to green
     without turning the page into Christmas. */
  --flare-50:  #fff1ec;
  --flare-100: #ffddd2;
  --flare-200: #ffb69f;
  --flare-300: #ff8c6b;
  --flare-400: #ff6a41;
  --flare-500: #f5562b;
  --flare-600: #d93c15;
  --flare-700: #c3350f;
  --flare-800: #96280b;
  --flare-900: #6b1c07;

  /* Beam — floodlight amber. Signal and celebration. Never body text. */
  --beam-100: #fff3d1;
  --beam-200: #ffe29a;
  --beam-300: #ffd166;
  --beam-400: #ffc043;
  --beam-500: #f0a413;
  --beam-600: #b87a06;
  --beam-700: #7a5200;

  /* Dial — instrument teal. The fourth category colour; reads "measurement",
     which is what the research work actually is. */
  --dial-100: #d6f1f5;
  --dial-200: #9fdde6;
  --dial-300: #4cc9d8;
  --dial-400: #17a6b8;
  --dial-500: #0b8294;
  --dial-600: #0b6e7a;
  --dial-700: #07505a;

  /* Chalk — the neutral ramp. Green-cast rather than pure grey, so white
     surfaces read as touchline paint on grass instead of as office paper. */
  --chalk-0:   #ffffff;
  --chalk-50:  #f5f7f3;
  --chalk-100: #ebefe9;
  --chalk-200: #dce3da;
  --chalk-300: #c2ccc0;
  --chalk-400: #98a69b;
  --chalk-500: #6f8077;
  --chalk-600: #4a5b52;
  --chalk-700: #33423a;
  --chalk-800: #1c2a23;
  --chalk-900: #0c1912;
  --chalk-950: #07100c;

  /* == 2. SEMANTICS — light ================================================ */

  /* Ground and surfaces */
  --bg:           var(--chalk-50);    /* body. Explicit, never transparent.  */
  --bg-sunk:      var(--chalk-100);   /* wells, inset areas, code            */
  --surface:      var(--chalk-0);     /* cards lift off the chalk ground     */
  --surface-2:    var(--chalk-50);    /* nested panel inside a card          */
  --surface-3:    var(--chalk-100);   /* nested panel inside that            */
  --surface-invert: var(--pitch-900);
  --ink-invert:     var(--pitch-50);

  /* Text */
  --ink:        var(--chalk-900);   /* 18.9:1 on --bg                        */
  --ink-muted:  var(--chalk-600);   /*  6.7:1 on --bg                        */
  --ink-faint:  var(--chalk-500);   /*  4.6:1 on --bg — metadata only        */
  --ink-on-brand: var(--chalk-0);

  /* Lines */
  --line:         var(--chalk-200);
  --line-strong:  var(--chalk-300);
  --line-chalk:   color-mix(in oklab, var(--pitch-600) 22%, transparent);

  /* Brand (pitch) */
  --brand:        var(--pitch-600);
  --brand-ink:    var(--pitch-700);   /* 8.1:1 on --bg  — links, headings    */
  --brand-on:     var(--chalk-0);     /* 6.2:1 on --brand                    */
  --brand-tint:   var(--pitch-50);
  --brand-edge:   var(--pitch-200);
  --brand-strong: var(--pitch-700);

  /* Accent (flare) */
  --accent:        var(--flare-500);
  --accent-ink:    var(--flare-700);  /* 6.4:1 on --bg                       */
  --accent-on:     var(--chalk-0);    /* use with --accent-strong only       */
  --accent-tint:   var(--flare-50);
  --accent-edge:   var(--flare-200);
  --accent-strong: var(--flare-700);  /* 5.5:1 against white text            */

  /* Signal (beam) */
  --signal:        var(--beam-300);
  --signal-ink:    var(--beam-700);   /* 6.4:1 on --bg                       */
  --signal-on:     var(--chalk-900);
  --signal-tint:   var(--beam-100);
  --signal-edge:   var(--beam-200);
  --signal-strong: var(--beam-600);

  /* Instrument (dial) */
  --info:        var(--dial-500);
  --info-ink:    var(--dial-600);     /* 5.5:1 on --bg                       */
  --info-on:     var(--chalk-0);
  --info-tint:   var(--dial-100);
  --info-edge:   var(--dial-200);

  /* Timeline / project category colours. Each is a triple so a badge is
     always legible: -ink on -tint, hairline in -edge. */
  --kind-work-ink:      var(--brand-ink);
  --kind-work-tint:     var(--brand-tint);
  --kind-work-edge:     var(--brand-edge);
  --kind-research-ink:  var(--info-ink);
  --kind-research-tint: var(--info-tint);
  --kind-research-edge: var(--info-edge);
  --kind-venture-ink:   var(--accent-ink);
  --kind-venture-tint:  var(--accent-tint);
  --kind-venture-edge:  var(--accent-edge);
  --kind-project-ink:   var(--signal-ink);
  --kind-project-tint:  var(--signal-tint);
  --kind-project-edge:  var(--signal-edge);

  /* Focus. Vermilion in light, amber in dark — both clear 3:1 against every
     surface they can land on, which is the WCAG 2.2 non-text requirement. */
  --focus:        var(--flare-700);
  --focus-offset: var(--bg);

  /* Overlays and glows */
  --overlay:      color-mix(in oklab, var(--pitch-950) 55%, transparent);
  --glow-brand:   color-mix(in oklab, var(--pitch-400) 30%, transparent);
  --glow-accent:  color-mix(in oklab, var(--flare-400) 28%, transparent);
  --glow-signal:  color-mix(in oklab, var(--beam-300) 40%, transparent);

  /* The mown-pitch stripe used on the page ground. Felt, not seen. */
  --turf-stripe:  color-mix(in oklab, var(--pitch-600) 4%, transparent);

  /* == 3a. TYPE ============================================================ */

  /* Self-hosted or system only — no network font, by CSP rule.
     There is no woff2 in assets/ and there is not meant to be: every face
     below ships with the OS, so the first paint is the final paint and there
     is no FOUT, no font budget and nothing to fetch.

     THREE ROLES, and which mode each belongs to:

     BODY is the site's voice. A humanist sans — real text faces first
     (Avenir Next on Apple, Segoe UI on Windows, Roboto/Noto on Android and
     Linux), with the platform UI font only as a late fallback. Ordinary,
     warm, unremarkable letterforms: the page should read as written by a
     person, not issued by a brand system.

     HEADING is what h1-h3 actually resolve to. In read mode it is BODY — one
     family for the whole document, which is what a person writing their own
     site does. In shootout mode it is redefined to DISPLAY, one line, at the
     bottom of this file.

     DISPLAY is the condensed sports-broadcast face. It is the GAME's voice
     and is not used anywhere in read mode. Condensed type is not a body face
     and is never used as one.

     MONO carries periods, counts and tech names, where it reads as instrument
     panel rather than as code. */
  --font-display: "Bahnschrift", "Avenir Next Condensed", "Roboto Condensed",
                  "Liberation Sans Narrow", "DejaVu Sans Condensed",
                  "Segoe UI", system-ui, sans-serif;
  --font-body:    "Avenir Next", Avenir, "Segoe UI", Roboto, "Noto Sans",
                  "DejaVu Sans", "Liberation Sans", -apple-system,
                  BlinkMacSystemFont, system-ui, Arial, sans-serif,
                  "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
  --font-heading: var(--font-body);
  --font-mono:    ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
                  "Liberation Mono", "Roboto Mono", monospace;

  /* Fluid scale, 360px -> 1280px. Ratio ~1.2 small, ~1.25 large. */
  --step--2: clamp(0.75rem,   0.738rem + 0.054vw, 0.78125rem);
  --step--1: clamp(0.8125rem, 0.788rem + 0.109vw, 0.875rem);
  --step-0:  clamp(1rem,      0.976rem + 0.109vw, 1.0625rem);
  --step-1:  clamp(1.125rem,  1.076rem + 0.217vw, 1.25rem);
  --step-2:  clamp(1.3125rem, 1.215rem + 0.435vw, 1.5625rem);
  --step-3:  clamp(1.5rem,    1.324rem + 0.783vw, 1.95rem);
  --step-4:  clamp(1.75rem,   1.476rem + 1.217vw, 2.45rem);
  --step-5:  clamp(2.05rem,   1.659rem + 1.739vw, 3.05rem);
  --step-6:  clamp(2.45rem,   1.922rem + 2.348vw, 3.8rem);
  --step-7:  clamp(2.9rem,    2.176rem + 3.217vw, 4.75rem);

  /* Generous by default. Body copy sits at --leading-normal, and 1.68 is the
     difference between a page that looks typeset and a page that looks
     emitted. Headings stay tight; only running text gets the air. */
  --leading-flat:   1;
  --leading-tight:  1.12;
  --leading-snug:   1.32;
  --leading-normal: 1.68;
  --leading-loose:  1.8;

  --tracking-tighter: -0.03em;
  --tracking-tight:   -0.015em;
  --tracking-normal:  0em;
  --tracking-wide:    0.04em;
  --tracking-wider:   0.09em;
  --tracking-widest:  0.16em;

  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;
  --weight-black:    800;

  --measure:        68ch;   /* body copy                                     */
  --measure-narrow: 48ch;   /* leads, pull quotes                            */
  --measure-wide:   78ch;

  /* == 3b. SPACE =========================================================== */
  --sp-1:  0.25rem;
  --sp-2:  0.375rem;
  --sp-3:  0.5rem;
  --sp-4:  0.75rem;
  --sp-5:  1rem;
  --sp-6:  1.25rem;
  --sp-7:  1.5rem;
  --sp-8:  2rem;
  --sp-9:  2.5rem;
  --sp-10: 3rem;
  --sp-11: 4rem;
  --sp-12: 5.5rem;
  --sp-13: 7rem;

  --gutter:      clamp(1rem, 4.5vw, 2.5rem);   /* page side padding          */
  --section-gap: clamp(3.5rem, 9vw, 7rem);     /* between major sections     */

  /* == 3c. RADIUS ========================================================== */
  --radius-xs: 4px;
  --radius-sm: 7px;
  --radius-md: 11px;
  --radius-lg: 16px;
  --radius-xl: 22px;
  --radius-2xl: 30px;
  --radius-pill: 999px;

  /* == 3d. ELEVATION ======================================================= */
  /* Tinted with pitch, not black — a neutral-black shadow over a green-cast
     ground reads as dirt. */
  --shadow-1: 0 1px 2px rgba(5, 42, 26, 0.06),
              0 1px 1px rgba(5, 42, 26, 0.04);
  --shadow-2: 0 2px 4px rgba(5, 42, 26, 0.05),
              0 10px 22px -8px rgba(5, 42, 26, 0.14);
  --shadow-3: 0 4px 8px rgba(5, 42, 26, 0.06),
              0 26px 50px -14px rgba(5, 42, 26, 0.20);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.6);
  --shadow-lift: 0 3px 6px rgba(5, 42, 26, 0.07),
                 0 18px 38px -12px rgba(5, 42, 26, 0.22);

  /* == 3e. MOTION ========================================================== */
  --motion-ok: 1;                 /* 0 under prefers-reduced-motion          */
  --dur-1: 110ms;                 /* state echo: hover, press                */
  --dur-2: 200ms;                 /* small travel: chips, chevrons           */
  --dur-3: 340ms;                 /* panel and card entrances                */
  --dur-4: 560ms;                 /* scoreboard wipes                        */
  --dur-5: 900ms;                 /* long celebratory sequences              */
  --ease-out:      cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-in:       cubic-bezier(0.55, 0.06, 0.68, 0.19);
  --ease-in-out:   cubic-bezier(0.65, 0.05, 0.36, 1);
  --ease-emphatic: cubic-bezier(0.2, 0.9, 0.24, 1.02);  /* slight overshoot  */
  --ease-snap:     cubic-bezier(0.16, 1, 0.3, 1);

  /* == 3f. LAYOUT & DEPTH ================================================== */
  --wrap:        74rem;
  --wrap-narrow: 54rem;
  --header-h:    3.75rem;
  --rail-w:      1.25rem;   /* timeline rail column                          */
  --gutter-period: 8.5rem;  /* timeline period gutter, desktop               */

  --z-base:    0;
  --z-raised:  10;
  --z-sticky:  100;
  --z-overlay: 500;
  --z-top:     1000;
}

/* =============================================================================
   DARK — a floodlit night match. Only values that must change are restated;
   every scale above still applies. Guarded so an explicit light choice wins.
   ========================================================================== */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg:           var(--chalk-950);
    --bg-sunk:      #050c09;
    --surface:      #0e1a14;
    --surface-2:    #152420;
    --surface-3:    #1c2f28;
    --surface-invert: var(--pitch-100);
    --ink-invert:     var(--pitch-950);

    --ink:        #e8f0ea;            /* 16.6:1 on --bg                      */
    --ink-muted:  #9ab0a4;            /*  8.3:1 on --bg                      */
    --ink-faint:  #7a9187;            /*  5.5:1 on --bg                      */
    --ink-on-brand: var(--pitch-950);

    --line:        #23352c;
    --line-strong: #32493d;
    --line-chalk:  color-mix(in oklab, var(--pitch-300) 26%, transparent);

    /* Fills brighten and text-weight colours brighten further: a colour that
       carries text on white cannot carry it on near-black. */
    --brand:        #2fa96f;
    --brand-ink:    #4fd08f;          /*  9.9:1 on --bg                      */
    --brand-on:     var(--pitch-950); /*  9.8:1 on --brand-ink               */
    --brand-tint:   #0d2b1d;
    --brand-edge:   #1d5138;
    --brand-strong: #4fd08f;

    --accent:        #ff7a52;
    --accent-ink:    #ff9270;         /*  8.6:1 on --bg                      */
    --accent-on:     #2a0b02;
    --accent-tint:   #33150c;
    --accent-edge:   #6d2a17;
    --accent-strong: #ff7a52;

    --signal:        var(--beam-300);
    --signal-ink:    var(--beam-300); /* 13.4:1 on --bg                      */
    --signal-on:     #241700;
    --signal-tint:   #2e2308;
    --signal-edge:   #5c4510;

    --info:        var(--dial-300);
    --info-ink:    var(--dial-300);
    --info-on:     #04191d;
    --info-tint:   #0a2a30;
    --info-edge:   #14515c;

    --focus:        var(--beam-300);
    --focus-offset: var(--bg);

    --overlay:      rgba(3, 10, 7, 0.72);
    --glow-brand:   color-mix(in oklab, var(--pitch-400) 34%, transparent);
    --glow-accent:  color-mix(in oklab, var(--flare-400) 30%, transparent);
    --glow-signal:  color-mix(in oklab, var(--beam-300) 26%, transparent);
    --turf-stripe:  color-mix(in oklab, var(--pitch-300) 4%, transparent);

    /* Shadow does almost no work on a dark ground, so elevation is carried by
       a hairline of light along the top edge plus a deeper, softer pool. */
    --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.5);
    --shadow-2: 0 2px 6px rgba(0, 0, 0, 0.45),
                0 12px 26px -10px rgba(0, 0, 0, 0.7);
    --shadow-3: 0 6px 14px rgba(0, 0, 0, 0.5),
                0 30px 60px -18px rgba(0, 0, 0, 0.8);
    --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.055);
    --shadow-lift: 0 4px 10px rgba(0, 0, 0, 0.5),
                   0 22px 44px -14px rgba(0, 0, 0, 0.75);
  }
}

/* =============================================================================
   MODE — the one place the two personalities diverge at the token layer.

   Read mode is a quiet personal document: humanist type, no stadium. Shootout
   mode is a broadcast: the condensed display face comes back here, and every
   piece of pitch decor is re-enabled alongside it in base.css and site.css
   under the same `html[data-mode="shootout"]` selector.

   The palette itself does NOT change between modes. The green is the brand in
   both — read mode keeps a confident accent, it just stops pretending to be a
   football ground.
   ========================================================================== */
html[data-mode="shootout"] {
  --font-heading: var(--font-display);
}

/* Motion budget. One switch, honoured by every component and by the game. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-ok: 0;
    --dur-1: 1ms;
    --dur-2: 1ms;
    --dur-3: 1ms;
    --dur-4: 1ms;
    --dur-5: 1ms;
  }
}

/* =========================================================================
   READ-MODE THEME OVERRIDE
   ------------------------------------------------------------------------
   Off-white paper with golden branches in light, greyish-black with the same
   branches in dark. Scoped to [data-mode="site"] so the shootout keeps its
   pitch palette untouched.

   Theme resolution order, and why it is this order:
     :root                                  -> light is the base
     @media (prefers-color-scheme: dark)    -> follow the OS when unset
     [data-theme="dark"] / ="light"         -> an explicit choice wins both
   Defining the light values only inside a media query is the usual mistake:
   it leaves the explicit toggle with nothing to override.
   ========================================================================= */

:root {
  --paper: #faf7f0;
  --paper-raised: #fffdf8;
  --ink: #23201a;
  --ink-soft: #554f44;
  --ink-faint: #8a8275;
  --rule: #e4dccb;
  --gold: #b8892b;
  --gold-soft: #d8b25e;
  --gold-wash: rgba(184, 137, 43, 0.13);
  --branch: rgba(184, 137, 43, 0.20);
  --branch-thick: rgba(184, 137, 43, 0.30);
}

:root:not([data-theme="light"]) {
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #17181a;
    --paper-raised: #202225;
    --ink: #ece7dc;
    --ink-soft: #b3aca0;
    --ink-faint: #7d776d;
    --rule: #2f3134;
    --gold: #e0b558;
    --gold-soft: #c69a43;
    --gold-wash: rgba(224, 181, 88, 0.12);
    --branch: rgba(224, 181, 88, 0.20);
    --branch-thick: rgba(224, 181, 88, 0.30);
  }
}

[data-theme="dark"] {
  --paper: #17181a;
  --paper-raised: #202225;
  --ink: #ece7dc;
  --ink-soft: #b3aca0;
  --ink-faint: #7d776d;
  --rule: #2f3134;
  --gold: #e0b558;
  --gold-soft: #c69a43;
  --gold-wash: rgba(224, 181, 88, 0.12);
  --branch: rgba(224, 181, 88, 0.20);
  --branch-thick: rgba(224, 181, 88, 0.30);
}
