/* Hallmark · tokens.css — FAIRNESS 2027
 *
 * The design system's single source of truth. Loaded by index.html before style.css, and read
 * by js/tailwind-config.js, which maps these onto Tailwind utility names (bg-paper, text-accent,
 * p-lg, text-md, …). Change a value here and both the hand-written CSS and every Tailwind class
 * follow — that is the whole point of this file. Do not hard-code a colour or a font anywhere else.
 *
 * theme: custom · vibe: "river slate, cool paper, concrete arches"
 * accent sampled from the river and sky in images/background_landscape.jpg
 * axes: light / grotesk-sans / cool
 */

:root {
  /* ---- Colour · raw OKLCH triplets.
     Kept as bare triplets (not full oklch() values) so Tailwind's alpha modifiers can compose
     them — js/tailwind-config.js wraps each as `oklch(var(--x-raw) / <alpha-value>)`, which is
     what makes bg-paper/95 work on the sticky masthead.
     Every neutral is tinted cool toward the anchor (hue 240–250). Contrast against paper is
     noted where it constrained the value — these are not free choices. */
  --paper-raw:      97% 0.006 240;   /* cool near-white, never #fff */
  --paper-2-raw:    94% 0.008 240;   /* −3% L · one elevation      */
  --paper-3-raw:    91% 0.008 240;   /* −6% L · code ground        */
  --ink-raw:        21% 0.018 245;   /* 11.8:1 on paper */
  --ink-2-raw:      38% 0.014 245;   /*  6.5:1 — body copy */
  --muted-raw:      45% 0.012 245;   /*  5.0:1 — the naive L52% lands at 3.9:1 and fails body text */
  --neutral-raw:    62% 0.010 245;   /*  2.4:1 — disabled register only; WCAG exempts inactive */
  --rule-raw:       80% 0.010 240;   /* hairlines are this page's divider language; L88% is 1.26:1 and vanishes */
  --rule-2-raw:     87% 0.008 240;
  --accent-raw:     45% 0.130 250;   /*  5.0:1 — slate-blue, from the water */
  --accent-ink-raw: 97% 0.006 240;   /*  5.0:1 on accent — paper, for text on an accent fill */
  --focus-raw:      50% 0.180 250;   /*  4.2:1 — needs 3:1 */

  /* ---- Colour · composed. These are what hand-written CSS in style.css consumes. */
  --color-paper:      oklch(var(--paper-raw));
  --color-paper-2:    oklch(var(--paper-2-raw));
  --color-paper-3:    oklch(var(--paper-3-raw));
  --color-ink:        oklch(var(--ink-raw));
  --color-ink-2:      oklch(var(--ink-2-raw));
  --color-muted:      oklch(var(--muted-raw));
  --color-neutral:    oklch(var(--neutral-raw));
  --color-rule:       oklch(var(--rule-raw));
  --color-rule-2:     oklch(var(--rule-2-raw));
  --color-accent:     oklch(var(--accent-raw));
  --color-accent-ink: oklch(var(--accent-ink-raw));
  --color-focus:      oklch(var(--focus-raw));

  /* No scrim token by design: headline type sits in a paper band beneath the photograph,
     not over it. Text on that image would need a ~0.87-alpha overlay to hold 4.5:1 against
     the bright water, which defeats the point of showing the photograph. */

  /* ---- Type · one family, on purpose. IBM Plex is an institutional/engineering face and this
     is an IEEE workshop, so the single voice IS the design choice. --font-display and
     --font-body resolve to the same stack deliberately: hierarchy is weight (700 vs 400, a
     300-unit step) + tracking + size. Mono is code-only — one slot.
     Reintroducing a display serif is a one-line change to --font-display; no markup moves.
     Weights loaded in index.html: Plex Sans 400/500/700, Plex Mono 400. */
  --font-display: 'IBM Plex Sans', ui-sans-serif, sans-serif;  /* 700 */
  --font-body:    'IBM Plex Sans', ui-sans-serif, sans-serif;  /* 400 · 500 emphasis */
  --font-mono:    'IBM Plex Mono', ui-monospace, monospace;    /* the LaTeX command only */

  /* ---- Type scale · 1.25 major third, six steps in use */
  --text-xs:        0.8rem;    /* 12.8px · tracked label register ONLY, never body copy */
  --text-sm:        0.875rem;  /* 14px   · captions, timeline labels */
  --text-base:      1rem;      /* 16px   · body floor */
  --text-md:        1.25rem;   /* 20px   · lede, timeline dates */
  --text-xl:        1.9531rem; /* 31.3px · section heads, page limits */
  --text-display-s: clamp(2.25rem, 4.2vw + 0.75rem, 3.75rem);

  --measure:      65ch;        /* prose cap — measure lives between 45 and 75ch */
  --measure-wide: 72ch;

  /* ---- Space · 4pt scale */
  --space-3xs: 0.125rem;  --space-2xs: 0.25rem;  --space-xs:  0.5rem;
  --space-sm:  0.75rem;   --space-md:  1rem;     --space-lg:  1.5rem;
  --space-xl:  2.5rem;    --space-2xl: 4rem;     --space-3xl: 6rem;
  --space-4xl: 9rem;

  --page-max:    76rem;
  --page-gutter: clamp(1rem, 4vw, 4rem);

  /* ---- Rules · broadsheet: nothing is rounded */
  --rule-hair:   1px;
  --rule-thick:  2px;
  --radius-flat: 0px;

  /* ---- Motion */
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in:     cubic-bezier(0.7, 0, 0.84, 0);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-micro:   120ms;
  --dur-short:   220ms;
  --dur-long:    420ms;

  /* ---- Layers */
  --z-base:   1;
  --z-raised: 10;
  --z-sticky: 200;
}
