/* ==========================================================================
   LEECOI — Design tokens
   ==========================================================================

   DIRECTION: "instrument panel".

   The visual language is taken from the tooling an engineer actually looks at
   all day: plotting libraries, training dashboards, terminals, CI pipelines.
   Not from course-marketplace convention. That is why corners stay tight,
   data is set in a monospace, and the accent is rationed rather than sprayed.

   ARCHITECTURE — read this before adding a colour anywhere.

   There are two layers, and components may only ever touch the second one.

     1. RAW PALETTE (`--p-*`)
        Literal hex values. Never referenced by a component. Exists so the
        palette can be retuned in one place.

     2. SEMANTIC TOKENS (`--bg`, `--ink`, `--accent`, `--ring`, ...)
        Role names, remapped per surface by `.surface-dark` / `.surface-light`.
        A component says `color: var(--ink)` and is therefore correct on a dark
        hero and on a light content section without a single duplicated rule.
        This is what keeps a mixed dark/light page from doubling the stylesheet.

   CONTRAST: every text pairing below is measured, not estimated. Ratios are
   recorded inline and re-verified on demand by `tools/check-contrast.mjs`,
   which parses THIS FILE so the numbers cannot drift from what ships.
   ========================================================================== */

:root {
  /* ======================================================================
     1. RAW PALETTE — do not reference these outside this file
     ====================================================================== */

  /* ---- Dark field ---------------------------------------------------- */
  --p-void: #070a12;        /* deepest: footer                            */
  --p-base: #0b0f19;        /* dark page and hero field                   */
  --p-surface: #111827;     /* cards on the dark field                    */
  --p-raised: #171f31;      /* panels stacked on a card                   */

  /* ---- Light field --------------------------------------------------- */
  --p-paper: #f6f7f9;       /* light content section                      */
  --p-card: #ffffff;        /* cards on the light field                   */
  --p-sunk: #eef0f4;        /* recessed wells, code strips on light       */

  /* ---- Text ---------------------------------------------------------- */
  --p-white: #ffffff;
  --p-grey: #9ca3af;        /* muted on dark:  7.54:1 base  6.99:1 surface */
  --p-slate: #545c6b;       /* muted on light: 6.28:1 paper 6.73:1 card    */

  /* ---- Accent: gold. The one accent, deliberately rationed ----------- */
  /* Appears in exactly four roles: primary action, active navigation,
     focus ring, and the converged endpoint of the progress curve. If a
     fifth use is proposed, the answer is no. Rationing is what stops it
     reading as an energy dashboard. */
  --p-gold: #d4af37;        /* on dark:  9.11:1 base  8.44:1 surface      */
  --p-gold-ink: #7a6011;    /* on light: 5.58:1 paper 5.99:1 card         */
  --p-gold-deep: #a8842a;   /* pressed state on dark                      */
  --p-gold-wash: #221b08;   /* tinted fill behind gold text on dark       */
  --p-gold-wash-lt: #faf4e2;/* tinted fill on light                       */

  /* ---- Data: blue. Links, plotted lines, diagram strokes ------------- */
  /* Lifted from the briefed #2563EB, which measures 3.71:1 on the dark
     field and therefore cannot legally carry body text. */
  --p-blue: #4c8dff;        /* on dark:  5.98:1 base  5.54:1 surface      */
  --p-blue-ink: #1d4ed8;    /* on light: 6.25:1 paper 6.70:1 card         */
  --p-blue-wash: #0e1a2f;
  --p-blue-wash-lt: #eaf0ff;

  /* ---- Status -------------------------------------------------------- */
  --p-positive: #35d39a;    /* 9.97:1 on dark base                        */
  --p-positive-ink: #0f7a55;/* 5.34:1 on light card                       */
  --p-critical: #ff6b6b;    /* 6.90:1 on dark base                        */
  --p-critical-ink: #c0332b;/* 5.60:1 on light card                       */

  /* ======================================================================
     2. TYPOGRAPHY
     ======================================================================
     One neutral grotesque across display and body, which is how product
     interfaces at Google, Meta and OpenAI are set: weight and size carry the
     hierarchy rather than a second "characterful" display face.

     The monospace is not costume. In a product about engineering, week
     indices, metric labels and phase counts genuinely are data artifacts,
     so they are set as data. */

  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
    system-ui, sans-serif;
  --font-mono: 'Roboto Mono', ui-monospace, SFMono-Regular, 'SF Mono',
    Menlo, Consolas, monospace;

  /* Fluid scale. Inter has tall ascenders and a narrow set width, so large
     steps take looser leading and gentler negative tracking than a true
     display grotesque would want. */
  --step-d1: clamp(2.25rem, 4.6vw, 3.75rem);   /* page headline           */
  --step-d1-lh: 1.06;
  --step-d1-ls: -0.03em;

  --step-d2: clamp(1.75rem, 3.2vw, 2.625rem);  /* section headline        */
  --step-d2-lh: 1.14;
  --step-d2-ls: -0.024em;

  --step-d3: clamp(1.25rem, 1.9vw, 1.5rem);    /* card and block headline */
  --step-d3-lh: 1.3;
  --step-d3-ls: -0.014em;

  --step-lead: clamp(1.125rem, 1.6vw, 1.375rem); /* deck under a headline */
  --step-lead-lh: 1.55;
  --step-lead-ls: -0.011em;

  --step-body: 1rem;
  --step-body-lh: 1.65;

  --step-small: 0.875rem;
  --step-small-lh: 1.6;

  /* Eyebrows and data labels. Mono at small sizes wants open tracking. */
  --step-micro: 0.6875rem;
  --step-micro-lh: 1.4;
  --step-micro-ls: 0.14em;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semi: 600;
  --weight-bold: 700;

  /* ======================================================================
     3. SPACE — 4px base, named by use so intent survives refactors
     ====================================================================== */
  --space-2xs: 0.25rem;   /*  4px */
  --space-xs: 0.5rem;     /*  8px */
  --space-sm: 0.75rem;    /* 12px */
  --space-md: 1rem;       /* 16px */
  --space-lg: 1.5rem;     /* 24px */
  --space-xl: 2rem;       /* 32px */
  --space-2xl: 3rem;      /* 48px */
  --space-3xl: 4rem;      /* 64px */
  --space-4xl: 6rem;      /* 96px */

  /* Vertical rhythm between major sections, and the gutter that keeps
     content off the viewport edge on small screens. */
  --space-section: clamp(4.5rem, 9vw, 7.5rem);
  --gutter: clamp(1.25rem, 4vw, 2.5rem);

  /* ======================================================================
     4. MEASURE — content widths
     ====================================================================== */
  --width-page: 78rem;    /* 1248px: the main content rail               */
  --width-wide: 88rem;    /* full-bleed panels that still need a bound   */
  --width-prose: 42rem;   /* ~68 characters at body size                 */

  /* ======================================================================
     5. RADIUS
     ======================================================================
     Tight. Large radii read consumer-app; this is an instrument. The one
     concession to the brief's 8px ceiling is `--radius-xl`, reserved for
     panels over ~500px wide, where 8px reads as an accident rather than a
     decision. */
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;
  --radius-xl: 14px;
  --radius-pill: 999px;

  /* ======================================================================
     6. MOTION — one entrance ease, one interface ease. Two, not five.
     ====================================================================== */
  --ease-entrance: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-ui: cubic-bezier(0.4, 0, 0.2, 1);

  --dur-fast: 140ms;      /* hover, press                                */
  --dur-base: 260ms;      /* menus, disclosure                           */
  --dur-slow: 620ms;      /* scroll entrances                            */
  --dur-draw: 1600ms;     /* the progress curve drawing itself           */

  /* ======================================================================
     7. ELEVATION
     ======================================================================
     On the dark field, shadow is nearly invisible, so lift is carried by a
     lighter border and a raised fill instead. On the light field, shadow does
     the work. Both are exposed under one token name so components stay
     surface-agnostic. */
  --shadow-dark-sm: 0 1px 2px rgb(0 0 0 / 0.4);
  --shadow-dark-md: 0 8px 24px -8px rgb(0 0 0 / 0.6);
  --shadow-dark-lg: 0 24px 60px -16px rgb(0 0 0 / 0.7);

  --shadow-light-sm: 0 1px 2px rgb(11 15 25 / 0.05);
  --shadow-light-md: 0 4px 16px -4px rgb(11 15 25 / 0.09),
    0 1px 3px rgb(11 15 25 / 0.05);
  --shadow-light-lg: 0 18px 48px -12px rgb(11 15 25 / 0.16),
    0 2px 6px rgb(11 15 25 / 0.05);

  /* ======================================================================
     8. LAYERS — every stacking decision in one ordered list
     ====================================================================== */
  --z-behind: -1;
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 100;
  --z-header: 200;
  --z-menu: 300;
  --z-drawer: 400;
  --z-skip: 500;

  /* Header height is read by JS (scroll offset) and by CSS
     (`scroll-margin-top` on anchor targets), so it lives here as the single
     source of truth rather than being written twice. */
  --header-h: 4.5rem;
}

@media (min-width: 60rem) {
  :root {
    --header-h: 5rem;
  }
}

/* ==========================================================================
   SURFACE SCOPES
   --------------------------------------------------------------------------
   The mechanism that lets one component stylesheet serve a dark hero and a
   light content section. Put `.surface-dark` or `.surface-light` on a
   <section>; everything inside resolves to the right role colours.

   Scopes nest correctly: a `.surface-light` band inside a dark page simply
   remaps the tokens again for its own subtree.
   ========================================================================== */

.surface-dark {
  color-scheme: dark;

  --bg: var(--p-base);
  --bg-sunk: var(--p-void);
  --panel: var(--p-surface);
  --panel-raised: var(--p-raised);

  --ink: var(--p-white);
  --muted: var(--p-grey);

  --accent: var(--p-gold);
  --accent-strong: var(--p-gold);
  --accent-press: var(--p-gold-deep);
  --accent-wash: var(--p-gold-wash);
  --on-accent: var(--p-base);      /* text ON a gold fill: 9.11:1        */

  --link: var(--p-blue);
  --link-wash: var(--p-blue-wash);

  --positive: var(--p-positive);
  --critical: var(--p-critical);

  /* Hairlines are decorative separators and are exempt from the 3:1
     non-text rule. Control edges are NOT exempt, which is why they get a
     much stronger token: rgba(255,255,255,.4) measures 3.79:1 on the card
     fill, where the .08 hairline manages only 1.24:1. */
  --line: rgb(255 255 255 / 0.08);
  --line-strong: rgb(255 255 255 / 0.16);
  --control-line: rgb(255 255 255 / 0.4);

  --ring: var(--p-gold);           /* 9.11:1 on this field               */

  --shadow-sm: var(--shadow-dark-sm);
  --shadow-md: var(--shadow-dark-md);
  --shadow-lg: var(--shadow-dark-lg);

  background-color: var(--bg);
  color: var(--ink);
}

.surface-light {
  color-scheme: light;

  --bg: var(--p-paper);
  --bg-sunk: var(--p-sunk);
  --panel: var(--p-card);
  --panel-raised: var(--p-card);

  --ink: var(--p-base);
  --muted: var(--p-slate);

  /* Gold at full chroma measures 1.96:1 on paper, so it cannot carry text
     or act as a focus ring here. The hue is preserved and the value dropped:
     --accent stays available for fills and marks, --accent-strong is the
     text-safe version, and both the ring and on-light text use the latter. */
  --accent: var(--p-gold);
  --accent-strong: var(--p-gold-ink);
  --accent-press: var(--p-gold-deep);
  --accent-wash: var(--p-gold-wash-lt);
  --on-accent: var(--p-base);

  --link: var(--p-blue-ink);
  --link-wash: var(--p-blue-wash-lt);

  --positive: var(--p-positive-ink);
  --critical: var(--p-critical-ink);

  --line: rgb(11 15 25 / 0.09);
  --line-strong: rgb(11 15 25 / 0.16);

  /* Chosen against the DARKEST light backdrop it has to survive, not against
     white. An input's border sits on --bg-sunk (#eef0f4), where a value picked
     for a white card measured only 2.71:1 and failed 1.4.11. This one holds at
     3.22:1 there, 3.42:1 on paper and 3.67:1 on a card. */
  --control-line: #7e8694;

  --ring: var(--p-gold-ink);       /* 5.58:1 on paper, 5.99:1 on a card  */

  --shadow-sm: var(--shadow-light-sm);
  --shadow-md: var(--shadow-light-md);
  --shadow-lg: var(--shadow-light-lg);

  background-color: var(--bg);
  color: var(--ink);
}

/* The deepest dark, used by the footer. Inherits every dark role token and
   only swaps the field, so it is a variant rather than a third scope. */
.surface-void {
  --bg: var(--p-void);
  --panel: var(--p-base);
  background-color: var(--bg);
}

/* A recessed light band, for separating two adjacent light sections without
   introducing a third palette. Cards stay white, so the contrast between a card
   and its field actually increases here.

   `--bg-sunk` is lifted to paper rather than left equal to the new field: a
   recessed well inside an already-recessed section still has to read as
   recessed, and two identical values would collapse the distinction. */
.surface-light--sunk {
  --bg: var(--p-sunk);
  --bg-sunk: var(--p-paper);
  background-color: var(--bg);
}
