/* ============================================================================
   SpendCards — design tokens

   One source of truth, loaded before site.css and admin.css.

   Structure:
     1. PRIMITIVES   raw values. Never referenced directly by components.
     2. SEMANTIC     what a thing means (--text-3, --line). Components use these.
     3. SURFACE      [data-surface="admin"] re-points semantic tokens.

   The public site and the admin panel are deliberately different products:
   the site is blue, the admin is green. That difference now lives in one
   place instead of being forked across two conflicting :root blocks.

   Rule: a component must never use a primitive (--blue-500) or a raw hex.
   If a component needs a value that has no semantic token, add one here.
   ========================================================================= */

:root {
  /* ---- 1. PRIMITIVES -------------------------------------------------- */

  /* neutrals */
  --c-ink-900:#0A0E27; --c-ink-800:#0D1330; --c-ink-700:#141C44;
  --c-ink-600:#1E2A5A; --c-ink-500:#2C3B72;
  --c-white:#FFFFFF;
  --c-grey-50:#F7F9FF;  --c-grey-100:#F4F7FE; --c-grey-200:#E6EBF7;
  --c-grey-300:#D5DDF0; --c-grey-500:#6B7590; --c-grey-600:#5A6480;
  --c-slate-900:#0B1020; --c-slate-700:#4A5578; --c-slate-500:#626C88;

  /* brand: public site */
  --c-blue-400:#4D6BFF; --c-blue-500:#3D5AFE; --c-blue-600:#2E4BF0; --c-blue-700:#243BD6;
  --c-blue-50:#EAEEFF;
  --c-cyan-500:#00C2FF; --c-cyan-600:#00A6E0; --c-cyan-50:#E0F7FF;
  --c-violet-500:#7B4DFF; --c-violet-50:#F0EAFF;

  /* brand: admin */
  --c-green-500:#0FB896; --c-green-600:#0AA184; --c-green-400:#14C9A4; --c-green-50:#E4F7F2;
  --c-indigo-500:#5B6EF5;

  /* status */
  --c-amber-500:#FFB020; --c-amber-600:#E89400; --c-amber-50:#FFF4DC;
  --c-green-pos:#12B76A;  --c-green-pos-50:#E3FCEF;
  --c-red-500:#F0546E;    --c-red-50:#FDE9ED;
  --c-red-700:#C0392B;    --c-red-800:#A93226;

  /* ---- 2. SEMANTIC ---------------------------------------------------- */

  /* surfaces */
  --bg:var(--c-white);
  --bg-sunken:var(--c-grey-100);
  --surface:var(--c-white);
  --surface-2:var(--c-grey-50);

  /* borders */
  --line:var(--c-grey-200);
  --line-2:var(--c-grey-300);
  --line-dark:rgba(255,255,255,.10);

  /* text. --muted is the workhorse: captions, timestamps, secondary labels.
     The old --text-3 (#8A93B0) scored 2.90:1 on --surface-2 — below WCAG AA.
     #626C88 keeps the same slate hue and clears 4.5:1 on every surface we
     use (white, --surface-2, and both admin backgrounds). Worst case 4.82:1. */
  --text:var(--c-slate-900);
  --text-2:var(--c-slate-700);
  --text-3:var(--c-slate-500);
  --muted:var(--c-slate-500);
  --text-inv:#F0F4FF;
  --text-inv-2:#A6B2DB;

  /* ink scale (dark backgrounds). --ink is the plain one components reach for. */
  --ink:var(--c-ink-800);
  --ink-900:var(--c-ink-900); --ink-800:var(--c-ink-800); --ink-700:var(--c-ink-700);
  --ink-600:var(--c-ink-600); --ink-500:var(--c-ink-500);

  /* brand. --brand is an alias of --primary so either name resolves. */
  --primary:var(--c-blue-500);
  --primary-600:var(--c-blue-600);
  --primary-700:var(--c-blue-700);
  --primary-tint:var(--c-blue-50);
  --primary-glow:rgba(61,90,254,.35);
  --brand:var(--primary);

  --accent:var(--c-cyan-500);
  --accent-600:var(--c-cyan-600);
  --accent-tint:var(--c-cyan-50);
  --primary-2:var(--accent);            /* legacy alias */

  --violet:var(--c-violet-500);
  --violet-tint:var(--c-violet-50);

  /* status */
  --amber:var(--c-amber-500); --amber-600:var(--c-amber-600); --amber-tint:var(--c-amber-50);
  --warn:var(--c-amber-500);
  --pos:var(--c-green-pos);   --pos-tint:var(--c-green-pos-50);
  --pos-strong:#0C874E;       /* white text on this passes WCAG AA (4.57:1); --pos alone (2.62:1) does not */
  --neg:var(--c-red-500);     --neg-tint:var(--c-red-50);
  --danger:var(--c-red-700);  --danger-600:var(--c-red-800);

  /* focus ring: --accent cyan was only 1.91:1 on white — below the 3:1 that
     WCAG 1.4.11 requires for a focus indicator. Set explicitly per surface so
     each gets a ring in its own hue that still clears 3:1. */
  --focus:var(--c-blue-500);      /* 4.74:1 worst-case on light surfaces */

  /* ---- shape ---------------------------------------------------------- */
  --r-xs:8px; --r-sm:12px; --r-md:16px; --r-lg:22px; --r-xl:28px; --r-pill:999px;

  /* ---- layout --------------------------------------------------------- */
  --nav-h:68px;              /* sticky header height; overridden on mobile */

  /* ---- space ---------------------------------------------------------- */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:24px;
  --s-6:32px; --s-7:48px; --s-8:64px; --s-9:96px; --s-10:128px;

  /* ---- elevation ------------------------------------------------------ */
  --sh-xs:0 1px 2px rgba(11,16,32,.05);
  --sh-sm:0 1px 3px rgba(11,16,32,.06),0 1px 2px rgba(11,16,32,.04);
  --sh-md:0 6px 16px rgba(30,42,90,.08),0 2px 4px rgba(11,16,32,.04);
  --sh-lg:0 16px 40px rgba(30,42,90,.12),0 4px 8px rgba(11,16,32,.05);
  --sh-xl:0 30px 80px rgba(20,28,68,.20),0 8px 16px rgba(11,16,32,.06);
  --sh-primary:0 10px 30px var(--primary-glow);

  /* ---- gradients ------------------------------------------------------ */
  --grad-primary:linear-gradient(135deg,var(--c-blue-400) 0%,var(--c-blue-500) 55%,var(--c-blue-600) 100%);
  --grad-ink:linear-gradient(155deg,var(--c-ink-600) 0%,var(--c-ink-800) 60%,var(--c-ink-900) 100%);
  --grad-accent:linear-gradient(135deg,var(--c-cyan-500),var(--c-blue-500));
  --grad-brand:linear-gradient(120deg,var(--c-cyan-500) 0%,var(--c-blue-500) 45%,var(--c-violet-500) 100%);
  --grad-sheen:linear-gradient(120deg,transparent 30%,rgba(255,255,255,.10) 50%,transparent 70%);
  --grad-hero:
    radial-gradient(900px 600px at 82% 0%,rgba(61,90,254,.55),transparent 60%),
    radial-gradient(700px 500px at 10% 20%,rgba(0,194,255,.30),transparent 62%),
    radial-gradient(600px 600px at 60% 110%,rgba(123,77,255,.35),transparent 60%);

  /* ---- type ----------------------------------------------------------- */
  --font-display:'Space Grotesk',system-ui,sans-serif;
  --font-body:'Inter',system-ui,sans-serif;
  --font-mono:'JetBrains Mono',ui-monospace,monospace;

  /* ---- motion --------------------------------------------------------- */
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-spring:cubic-bezier(.34,1.32,.44,1);
  --dur:.22s;
  --dur-fast:.14s;
}

/* ---- 3. SURFACE: admin -----------------------------------------------
   Only the tokens that genuinely differ. Everything else inherits, so a
   change to spacing or shadows lands on both surfaces automatically. */
[data-surface="admin"] {
  --bg:#F3F6FB;
  --surface-2:#F7F9FC;

  --primary:var(--c-green-500);
  --primary-600:var(--c-green-600);
  --primary-tint:var(--c-green-50);
  --brand:var(--primary);
  --accent:var(--c-indigo-500);

  --grad-primary:linear-gradient(135deg,var(--c-green-400),var(--c-green-600));
  --grad-ink:linear-gradient(165deg,var(--c-ink-600),var(--c-ink-800));

  --focus:var(--c-indigo-500);   /* 3.88:1 on admin surfaces; the green primary would fail at 2.33:1 */

  --dur:.2s;
}

/* Respect users who ask for less motion. This runs on every surface that
   loads tokens.css (site AND admin), so no page can forget it.

   Zeroing --dur/--dur-fast handles transitions written with the tokens; the
   universal rule below also catches animations and transitions that hardcode
   their timing, which the token change alone cannot reach. */
@media (prefers-reduced-motion: reduce) {
  :root { --dur:.001s; --dur-fast:.001s; }
  *, *::before, *::after {
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  [data-reveal] { opacity:1; transform:none; }
}

/* ============================================================================
   TYPE SCALE

   Before this, the stylesheets carried 35 distinct font-sizes — including
   drift like 9.5 / 10.5 / 11.5 / 12.5 / 13.5, five near-identical values
   doing one job. That's what made pages feel "almost aligned".

   Two layers, same pattern as the colour tokens:

     --fs-<n>   NUMERIC primitives, one per real pixel size. A component may
                use these directly when no semantic role fits.
     --fs-role  SEMANTIC aliases for the jobs that repeat (body, caption, h2…).
                Prefer these — they say what the text IS, not how big it is.

   Half-pixel values snap to their whole-pixel neighbour (a sub-pixel change).
   A few component numerals stay literal on purpose — see the note at the end.
   ========================================================================= */
:root {
  /* numeric primitives (px value in the name, so there's never ambiguity) */
  --fs-10:10px; --fs-11:11px; --fs-12:12px; --fs-13:13px; --fs-14:14px;
  --fs-15:15px; --fs-16:16px; --fs-17:17px; --fs-18:18px; --fs-19:19px;
  --fs-20:20px; --fs-21:21px; --fs-22:22px; --fs-23:23px; --fs-24:24px;
  --fs-25:25px; --fs-26:26px; --fs-28:28px; --fs-30:30px; --fs-32:32px;
  --fs-34:34px; --fs-40:40px;

  /* semantic roles — what the text is for */
  --fs-micro:var(--fs-11);     /* legal, table sub-text, micro labels */
  --fs-caption:var(--fs-12);   /* captions, timestamps, chips */
  --fs-small:var(--fs-13);     /* secondary UI, dense cells */
  --fs-body:var(--fs-14);      /* default body / UI text */
  --fs-body-lg:var(--fs-15);   /* emphasised body, lead-ins */
  --fs-h4:var(--fs-17);        /* small headings, card titles */
  --fs-h3:var(--fs-20);        /* sub-section headings */
  --fs-h2:var(--fs-24);        /* section headings */
  --fs-h1:var(--fs-30);        /* page titles */
  --fs-display:var(--fs-40);   /* hero */
}

/* Component numerals kept as literal px, NOT part of the text scale:
     .score-ring-inner b, .au-avatar   36px   display digits in a fixed ring
     .verdict-score b                  48px   hero score digit
     .mc-net                           7/6px  network tag on a 46px thumbnail
     .th-arrow                         8px    sort-caret glyph
   Snapping these to the scale would distort the component they live in. */
