/**
 * resources/css/tokens.css
 * ApplyRole — design tokens. The single source of every colour, space and shadow.
 *
 * ── CONTRAST, AND WHY FOUR OF THESE MOVED ───────────────────────────────────────
 *
 * An axe-core pass over eighteen pages found 113 elements failing WCAG AA contrast,
 * and all of them traced to four tokens. That is the whole return on the no-hex rule
 * below: an accessibility fault spread across every page in the product was four
 * lines to fix, in one file, with no page touched.
 *
 * What changed, and the measured ratios against the background each is actually used
 * on. Every one is the SMALLEST darkening that clears 4.5:1 — the palette keeps its
 * hue and its character rather than being replaced:
 *
 *   --muted  #71718c → #6e6e88   4.39 → 4.59 on --bg
 *   --faint  #a3a3bd → #707082   2.46 → 4.85 on white   (the worst of them by far;
 *                                at 2.46 this was decorative text, not readable text)
 *   --brand  #6c63ff → #6159e5   4.32 → 5.16 on white, 4.55 on --brand-soft
 *   --ok     #16a34a → #11803a   2.99 → 4.57 on --ok-bg
 *
 * --brand is the identity colour and moving it was not done lightly. The shift is
 * about two percent — indistinguishable side by side — and it was failing as body
 * text on white, which is where most of the product uses it. A brand colour that
 * cannot be read is not serving the brand.
 *
 * WHO THIS IS FOR. A job board's users include people already getting the worst of
 * the labour market. Low-vision and colourblind job seekers are a large share of
 * them, and text at 2.46:1 is text they cannot read at all — on the pages where they
 * are deciding whether to trust us with their employment history.
 *
 * ── THE ORIGINAL NOTE ───────────────────────────────────────────────────────────
 *
 * These values are extracted from what the codebase already used (the purple, the
 * gradient pair, the card radii) and are now defined once instead of retyped in a
 * large inline <style> block on roughly eight pages. Nothing here is a redesign — it
 * is the same language, made editable in one place.
 *
 * RULE: no hex codes anywhere else in the codebase. If a component needs a colour that
 * is not here, the token is missing — add it here rather than inlining it.
 */

:root {
  /* ── Ground & ink ───────────────────────────────────────────────────────── */
  --bg:            #f6f6fb;
  --surface:       #ffffff;
  --surface-2:     #fbfbff;   /* inset panels, form fields at rest */
  --ink:           #12121f;
  --ink-2:         #3f3f57;
  --muted:         #6e6e88;
  --faint:         #707082;
  --line:          #ecebf5;
  --line-2:        #e0dff0;

  /* ── Brand ──────────────────────────────────────────────────────────────── */
  --brand:         #6159e5;
  --brand-2:       #9c88ff;
  --brand-3:       #c9b8ff;
  --brand-soft:    #f1efff;
  --brand-line:    #ddd8ff;
  /* --brand-grad IS A SURFACE THAT ALWAYS HAS WHITE TEXT ON IT — every primary
     button in the product, the nav logo, the avatar, the map pin. It used to run
     --brand → --brand-2, and --brand-2 is a decorative lavender: white on it
     measures 2.85:1, so the right-hand half of every primary button was unreadable.
     It now ends on --brand-grad-end, the lightest purple in that hue that still
     carries white (4.63:1), and --brand-2 keeps its decorative job elsewhere. */
  --brand-grad-end: #7357ff;
  --brand-grad:    linear-gradient(140deg, var(--brand), var(--brand-grad-end));

  /* ── Data series ────────────────────────────────────────────────────────────
     Slots 1–3 of the validated categorical palette. Verified all-pairs in light
     mode: CVD ΔE 9.2, normal-vision ΔE 24.0. Assign in this fixed order and never
     cycle — a fourth series folds into "Other" or gets its own chart.
     --s3 sits at 2.74:1 against --surface, so any chart using it ships visible
     labels or a table view. That relief is required, not optional.            */
  --s1:            #2a78d6;   /* blue   */
  --s2:            #eb6834;   /* orange */
  --s3:            #1baf7a;   /* aqua   */

  /* ── Sequential ramp ─────────────────────────────────────────────────────────
     One hue, light → dark, for magnitude-by-colour (heatmaps). Monotonic
     lightness. Do NOT use for categories.                                     */
  --seq-1:         #ded9ff;
  --seq-2:         #c3bbff;
  --seq-3:         #a79cff;
  --seq-4:         #8b7eff;
  --seq-5:         #6c63ff;
  --seq-6:         #4f47c4;

  /* ── Status — RESERVED ───────────────────────────────────────────────────────
     Never reused as a series colour. Always shipped with an icon and a text
     label, so state never depends on colour alone. Users can override the
     tracker's thresholds and hues; these are the defaults.

     MARKER COLOURS AND TEXT COLOURS ARE NOT THE SAME JOB. --ok, --late and --info
     are dark enough to be read as text on every background the product puts them
     on. --due is NOT and never can be — amber legible on a near-white panel is no
     longer amber. That is why --due-ink exists below: --due draws the border, the
     bar and the dot; --due-ink writes the words. Seven rules reached for --due as
     a text colour and measured 2.00:1; they now use --due-ink.

     --late moved #dc2626 → #d22222 (4.23 → 4.61 on --late-bg, 5.26 on white).
     It failed on its own background and on --bg, and it is the colour of every
     form error message in the product — .field__error, .autherror,
     .authflash--error. axe never saw it because no audited page was in an error
     state, which is the reading these numbers were computed by hand to catch:
     a page audit only measures the states the audit happened to render.        */
  --ok:            #11803a;   --ok-bg:    #e7f8ee;
  --due:           #f59e0b;   --due-bg:   #fff6e6;   /* marker only — see --due-ink */
  --late:          #d22222;   --late-bg:  #fdecec;
  --info:          #0369a1;   --info-bg:  #e0f2fe;

  /* ── Pipeline stages ─────────────────────────────────────────────────────────
     A deliberate progression, cool → warm → resolved. These appear ONLY on
     column headers and stage chips; status colours appear only on card edges
     and dots. Separating them by position is what stops them competing.

     EVERY STAGE NOW HAS ITS OWN HUE, AND THREE OF THEM. Until now `final` reused
     the interview orange and `hired` reused the offer green, which made two
     genuinely different columns look like one — and the chips were painted in
     none of these colours at all, because no CSS rule had ever selected on a
     stage. They were grey everywhere.

     The three-part set is what makes a pigmented chip legible rather than
     decorative:

       --st-X        the full-strength hue. Column rules, dots, card edges.
       --st-X-tint   the same hue at ~92% lightness. Chip and column backgrounds.
       --st-X-ink    the same hue darkened until it clears 4.5:1 on BOTH its own
                     tint and white, so the chip is readable on a card and the
                     bare text is readable on the page.

     The ink values are computed, not chosen by eye — every one measures between
     4.58:1 and 4.63:1 on its tint and above 5:1 on white. Adjusting a base hue
     means recomputing its ink; tests/contrast-audit.php will refuse the build if
     you do not.                                                               */
  --st-saved:          #64748b;
  --st-saved-tint:     #e7eaee;
  --st-saved-ink:      #5a697f;

  --st-applied:        #2a78d6;
  --st-applied-tint:   #dde9f8;
  --st-applied-ink:    #2067bc;

  --st-screen:         #7c5cf0;
  --st-screen-tint:    #e1dafb;
  --st-screen-ink:     #613af2;

  --st-interview:      #eb6834;
  --st-interview-tint: #fbe4db;
  --st-interview-ink:  #b83e0e;

  /* Its own pink, no longer borrowing the interview orange. */
  --st-final:          #d94f9a;
  --st-final-tint:     #f7deec;
  --st-final-ink:      #ba2476;

  --st-offer:          #1baf7a;
  --st-offer-tint:     #dcf9ef;
  --st-offer-ink:      #107d56;

  /* Amber: the colour of a held decision, and deliberately not red. */
  --st-waitlist:       #c98a12;
  --st-waitlist-tint:  #fbf0da;
  --st-waitlist-ink:   #92630a;

  /* A deeper green than `offer` — an accepted offer is a different fact. */
  --st-hired:          #0e9f6e;
  --st-hired-tint:     #dafbf0;
  --st-hired-ink:      #087e56;

  /*
   * Closed is grey, not red, and that is a judgement rather than an oversight.
   * A rejection bin painted in alarm red makes the most ordinary action in
   * recruiting feel violent, and the person doing it forty times a day stops
   * reading the colour entirely.
   */
  --st-closed:         #9c9cb5;
  --st-closed-tint:    #e8e8ed;
  --st-closed-ink:     #646488;

  /* ── Elevation ──────────────────────────────────────────────────────────────
     Layered rather than a single blur — this is most of why cards read as
     objects instead of outlined rectangles. Prefer these over 1px borders.    */
  --sh-1: 0 1px 2px rgba(18,18,31,.05), 0 1px 3px rgba(18,18,31,.04);
  --sh-2: 0 2px 4px rgba(18,18,31,.04), 0 6px 16px rgba(18,18,31,.07);
  --sh-3: 0 10px 24px rgba(18,18,31,.10), 0 28px 64px rgba(18,18,31,.14);
  --glow: 0 8px 32px rgba(108,99,255,.34);


  /* ── Surface decoration ──────────────────────────────────────────────────────
     Gradient stops and blur blobs. These were literals in app.css, which broke
     the file's own "no hex outside tokens" rule — a theme could not have changed
     them. Promoted here so it can.                                            */
  --scroll-thumb:  #d6d5e6;
  --hero-from:     #f3f1ff;
  --hero-mid:      #faf9ff;
  --blob-violet:   #cfc7ff;
  --blob-peach:    #ffd9c7;
  /* THE CV PROMO RAN LIGHT-TO-LIGHTER UNDER WHITE TEXT, and it carries a full
     paragraph on the home page — the first block of prose anybody reads here.
     White measured 4.32 / 3.29 / 2.61 across the three stops; at 2.61 the text was
     decoration. It now sweeps deep-to-brand the way the tracker promo already did,
     so the gradient still moves and every stop is safe: 10.09 / 7.27 / 4.64.

     axe reported nothing, and was not wrong to: it cannot evaluate text over a
     gradient, so it files that as INCOMPLETE rather than a violation — and the
     harness only ever collected violations. Both ends of that are now fixed.     */
  --promo-cv-1:    #3a2f9e;
  --promo-cv-2:    #4f3fc9;
  --promo-cv-3:    #655cff;
  --promo-tk-1:    #151428;
  --promo-tk-2:    #221f42;
  --promo-tk-3:    #2c2456;
  --glow-strong:   0 12px 30px rgba(108,99,255,.42);
  --accent-warm:   #d95d14;   /* hero headline gradient tail. Was #f0955f, which is
                                 GRADIENT TEXT via background-clip — it is the
                                 largest thing on the home page and it measured
                                 2.05:1, below even the 3:1 large-text floor. Now
                                 3.41:1 on --hero-from, still unmistakably peach. */

  /* ── Ink variants ────────────────────────────────────────────────────────────
     A colour that identifies a thing and a colour that spells out a word are two
     different jobs, and the second one has a floor the first does not. These are
     the text-grade versions of palette entries that are correct as fills and
     unreadable as letters. The fills are NOT changed — a chart series and a stage
     chip lose their meaning if flattened to ink.                                */
  --due-ink:       #8a5a08;   /* the --due amber, readable: 5.52 on --due-bg     */
  --orange-ink:    #c44613;   /* the --s2 / --st-interview orange, readable:
                                 4.96 on white, 4.61 on --bg, 4.81 on --surface-2 */

  /* ── Radii ──────────────────────────────────────────────────────────────── */
  --r-1: 8px;  --r-2: 12px;  --r-3: 16px;  --r-4: 22px;  --r-5: 30px;  --r-pill: 999px;

  /* ── Space ──────────────────────────────────────────────────────────────── */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 22px; --sp-6: 30px; --sp-7: 42px;  --sp-8: 62px;

  /* ── Type ───────────────────────────────────────────────────────────────── */
  --font: 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --font-serif: Georgia, 'Times New Roman', serif;   /* Executive / Academic CV templates */
  --font-mono: 'SF Mono', 'Courier New', monospace;  /* Tech CV templates */

  --fs-xs: .72rem;  --fs-sm: .79rem;  --fs-base: .87rem;  --fs-md: .95rem;
  --fs-lg: 1.08rem; --fs-xl: 1.35rem; --fs-2xl: 1.75rem;  --fs-3xl: 2.4rem;

  --fw-normal: 400; --fw-med: 600; --fw-bold: 750; --fw-black: 850;

  --lh-tight: 1.2; --lh-snug: 1.45; --lh-base: 1.65;

  /* ── Motion ─────────────────────────────────────────────────────────────── */
  --t-fast: .15s;  --t-base: .22s;  --t-slow: .32s;
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);

  /* ── Layout ─────────────────────────────────────────────────────────────── */
  --nav-h: 56px;
  --rail-w: 58px;
  --panel-w: 322px;
  --wrap: 1180px;

  /* ── The console rail ────────────────────────────────────────────────────
     One dark surface that is never content. Contrast checked against the two
     inks that sit on it: --rail-ink is 13.1:1 on --rail-bg, and --rail-muted
     is 4.8:1 — above AA for the small text it carries, which is the whole
     reason it is not dimmer. A sidebar people cannot read at a glance is a
     sidebar they stop using.                                                */
  --rail-bg:    #12172b;
  --rail-ink:   #e8eaf3;
  --rail-muted: #949bb8;
  --rail-hover: #1e2540;

  /* Soft fills for stat tiles and stage pills. Each is the tint of an existing
     semantic colour, so a pill and its meaning cannot drift apart. */
  --ok-soft:   #e7f6ee;
  --late-soft: #fdeaea;

}

/* Respect the OS setting. Anything that conveys state must not rely on motion. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Dark mode is SELECTED, not flipped — each step is chosen against the dark
   surface and validated separately. Stub only; fill in before shipping dark. */
/*
:root[data-theme="dark"] {
  --bg: #101018; --surface: #17172a; --ink: #ffffff; --muted: #9d9db8;
  --s1: #3987e5; --s2: #d95926; --s3: #199e70;
}
*/
