/* ---------------------------------------------------------------------------
 * css/styles/tokens.css — every design token in the app, in one file (#2333).
 *
 * MUST be linked BEFORE any stylesheet that consumes these names. A var() with
 * no definition in scope silently falls back to unset rather than erroring, so
 * getting the order wrong fails visually, not loudly. Current consumers:
 * index.php, admin.php (before base-layout.css) and reset-password.php,
 * invite.php (before auth.css).
 *
 * Two palettes live here deliberately:
 *
 *   --clr-*       the app shell. Tailwind's SLATE neutral ramp, and the only
 *                 one with a dark variant (js/core/theme.js sets
 *                 :root[data-theme="dark"]).
 *   --auth-clr-*  the unauthenticated pages (reset-password, invite). Tailwind's
 *                 GRAY ramp — warmer than slate. This is a real design
 *                 difference, not drift, so the ramps are NOT merged; #2333
 *                 measured them and 6 of 16 genuinely differ. Where a value IS
 *                 shared it aliases the --clr-* token, so each literal is
 *                 written exactly once.
 *
 * The auth pages never load js/core/theme.js, so data-theme is never set there
 * and the dark block below cannot apply to them. Giving the auth pages a dark
 * mode is a product decision, not a side effect of this file.
 * ------------------------------------------------------------------------- */

:root {
  /* --- Primitives -------------------------------------------------------- */
  /* The raw literal for each value the app shell and the auth pages BOTH use.
     Both palettes alias these, so every such colour is written exactly once.
     Critically, the dark block below reassigns --clr-* and never these, so the
     auth tokens cannot follow the app into dark: aliasing --auth-clr-* straight
     to --clr-* would leave a stray data-theme half-flipping the login page —
     7 of its 16 tokens dark, 9 light. */
  --primitive-blue: #2563eb;
  --primitive-blue-hover: #1d4ed8;
  --primitive-white: #ffffff;
  /* Shared by the app's "import row matched" accent and Data Quality's primary
     action colour — same literal, different jobs, so both alias this rather
     than each other (#2344). */
  --primitive-green: #0f7a5d;
  --primitive-red-bg: #fef2f2;
  --primitive-red-text: #991b1b;
  --primitive-green-bg: #f0fdf4;
  --primitive-green-text: #166534;

  /* --- App shell: slate ramp -------------------------------------------- */
  --clr-bg: #f4f6f9;
  --clr-surface: var(--primitive-white);
  --clr-surface-alt: #eef2f7;
  --clr-elevated: var(--primitive-white);
  /* --clr-primary and its hover LIGHTEN in dark (see the dark block). That is
     required for text and borders — #2563eb on a dark card is only 3.43:1 —
     but it is wrong for anything filled with the colour and labelled in white:
     white on the dark-theme #60a5fa was 2.54:1, and on the hover #93c5fd a
     worse 1.80:1 (#2361).
     So solid fills take the -fill tokens instead, which alias the primitives
     directly and are NOT reassigned in dark. White labels stay readable in
     both themes (5.17:1 / 6.70:1) and primary buttons look the same either way.
     Same split as --dq-primary vs --dq-primary-text (#2344), and the same rule:
     if white text sits on it, it is a fill. Pale color-mix() washes are NOT
     fills — they keep --clr-primary and should keep tracking the theme. */
  --clr-primary: var(--primitive-blue);
  --clr-primary-hover: var(--primitive-blue-hover);
  --clr-primary-fill: var(--primitive-blue);
  --clr-primary-fill-hover: var(--primitive-blue-hover);
  --clr-text: #1e293b;
  /* One muted colour, one name (#2352). --clr-text-muted was an alias holding
     this exact value in both themes; it is retired — do not reintroduce it.
     The generic name is deliberate: a dozen sites use it for background,
     border, fill and stroke, not only text.

     Was slate-500 #64748b, which cleared AA only on plain white and failed on
     every tinted surface it lands on — 4.40:1 on --clr-bg, 4.23 on
     --clr-surface-alt, 3.86 on --clr-border (#2351). This value clears 4.5:1
     on all four (6.20 / 5.73 / 5.52 / 5.03) while staying visibly secondary to
     --clr-text; slate-600 would have had more headroom but flattens the
     hierarchy between label and content. If you change --clr-border,
     --clr-bg or --clr-surface-alt, re-check this against all four. */
  --clr-muted: #556274;
  --clr-border: #e2e8f0;
  --clr-active: #eff6ff;
  --clr-hover-soft: #f3f4f6;
  --clr-input-bg: var(--primitive-white);
  --clr-success-bg: var(--primitive-green-bg);
  --clr-success-border: #86efac;
  --clr-success-text: var(--primitive-green-text);
  --clr-error-bg: var(--primitive-red-bg);
  --clr-error-border: #fca5a5;
  --clr-error-text: var(--primitive-red-text);
  --clr-warning-bg: #fffbeb;
  --clr-warning-border: #f59e0b;
  --clr-warning-border-strong: #d97706;
  --clr-warning-text: #b45309;
  --clr-info-bg: #dbeafe;
  --clr-info-text: #1e40af;
  --clr-shadow: 0 18px 40px rgba(15, 23, 42, 0.12);
  --radius: 8px;

  /* Previously undefined: every use was var(--clr-danger, #dc2626) /
     var(--clr-info-border, #bfdbfe), i.e. the literal fallback always won.
     Defined here at exactly those values, so nothing renders differently —
     the fallbacks are now dead code rather than load-bearing. Deliberately
     NOT overridden in the dark block: they resolve to the same value in both
     themes today, and changing that is a design decision, not a refactor. */
  --clr-danger: #dc2626;
  --clr-info-border: #bfdbfe;

  /* --clr-accent is GONE (#2344): it held a duplicate of --clr-primary's light
     value across 7 sites, which now use --clr-primary directly and lighten in
     dark like everything else. Do not reintroduce it.
     The import "row matched" accent, previously 7 raw literals in
     base-layout.css. No dark variant — it renders the same in both themes
     today, and giving it one is a design decision, not a refactor. */
  --clr-match: var(--primitive-green);

  /* --- Auth pages: gray ramp -------------------------------------------- */
  /* Shared with the app — aliased to the primitives above (NOT to --clr-*, see
     the note there), so each literal lives in one place and these stay light
     regardless of the app's theme. */
  --auth-clr-primary: var(--primitive-blue);
  --auth-clr-primary-hover: var(--primitive-blue-hover);
  --auth-clr-surface: var(--primitive-white);
  --auth-clr-error-bg: var(--primitive-red-bg);
  --auth-clr-error-text: var(--primitive-red-text);
  --auth-clr-success-bg: var(--primitive-green-bg);
  --auth-clr-success-text: var(--primitive-green-text);

  /* Genuinely auth-only: gray, not slate. Do not "fix" these to the --clr-*
     equivalents — that would recolour the login and invite pages. */
  --auth-clr-surface-alt: #f9fafb; /* gray-50   (app: #eef2f7) */
  --auth-clr-text: #111827; /* gray-900  (app: #1e293b) */
  --auth-clr-text-soft: #374151; /* gray-700  (no app equivalent) */
  --auth-clr-muted: #6b7280; /* gray-500  (app: #64748b) */
  --auth-clr-border: #d1d5db; /* gray-300  (app: #e2e8f0) */
  --auth-clr-border-soft: #e5e7eb; /* gray-200  (no app equivalent) */
  --auth-clr-disabled-bg: #f3f4f6; /* gray-100 */
  --auth-clr-error-border: #fecaca; /* red-200   (app: #fca5a5) */
  --auth-clr-success-border: #bbf7d0; /* green-200 (app: #86efac) */

  --auth-radius: 8px;
  --auth-radius-card: 12px;
  --auth-shadow-card: 0 8px 24px rgba(0, 0, 0, 0.06);

  /* --- Data Quality module: green accent -------------------------------- */
  /* data-quality.css had its own --color-* namespace: 133 uses, defined
     NOWHERE, so every one silently resolved to its literal fallback (#2341).
     The five names below had a single consistent fallback, so defining them
     changes nothing and finally makes them real.
     Renamed --color-* -> --dq-* deliberately: --color-primary is GREEN and
     --clr-primary is BLUE, and two tokens called "primary" sitting in one file
     with different colours is a trap. The prefix says which surface owns it,
     as --auth-clr-* does.
     The other five --color-* names had inconsistent fallbacks — --color-text-muted
     alone had eight different greys — so defining them would have collapsed
     ~90 sites onto one value. Those are inlined at their own literal in
     data-quality.css instead; unifying them is a design pass, see #2341.
     No dark values: data-quality.css has no dark-mode rules at all today, so
     adding them here would be inventing a theme, not refactoring one. */
  /* Data Quality's surfaces/greys/status colours now come from --clr-* like
     every other module (#2344) — it had none of its own dark rules, so its
     hardcoded white cards met the app's theme-aware text and the "New Check"
     title rendered at 1.17:1 in dark. Only the green identity stays local.

     The green splits by job, because one value cannot do both:
       --dq-primary       fills. White text sits on it, so it must stay dark
                          enough for that in BOTH themes — it is NOT lightened.
       --dq-primary-text  the same green used as text/border/outline. On a dark
                          card #0f7a5d reads at ~2.4:1, so dark lightens it. */
  --dq-primary: var(--primitive-green);
  --dq-primary-dark: #0a5e47;
  --dq-primary-text: var(--primitive-green);
  --dq-primary-soft: #e4f2ed;
  --dq-primary-border: #99cdbf;

  /* Pass/fail bars: saturated status colours that read on either theme, like a
     traffic light. Tokenised for naming, deliberately not themed. */
  --dq-pass: #22c55e;
  --dq-fail: #ef4444;
}

/* Applies to the app shell only — set by js/core/theme.js, which the auth
   pages do not load. */
:root[data-theme="dark"] {
  --clr-bg: #0f172a;
  --clr-surface: #111827;
  --clr-surface-alt: #1f2937;
  --clr-elevated: #172033;
  --clr-primary: #60a5fa;
  --clr-primary-hover: #93c5fd;
  --clr-text: #e5eefb;
  /* Was #94a3b8, which passed on every dark surface except --clr-border
     (4.04:1). This clears it at 5.02:1 (#2351). */
  --clr-muted: #a8b6c8;
  --clr-border: #334155;
  --clr-active: rgba(96, 165, 250, 0.15);
  --clr-hover-soft: #223047;
  --clr-input-bg: #0f172a;
  --clr-success-bg: rgba(22, 101, 52, 0.24);
  --clr-success-border: #4ade80;
  --clr-success-text: #bbf7d0;
  --clr-error-bg: rgba(153, 27, 27, 0.28);
  --clr-error-border: #f87171;
  --clr-error-text: #fecaca;
  --clr-warning-bg: rgba(180, 83, 9, 0.22);
  --clr-warning-border: #f59e0b;
  --clr-warning-border-strong: #fbbf24;
  --clr-warning-text: #fde68a;
  --clr-info-bg: rgba(30, 64, 175, 0.28);
  --clr-info-text: #bfdbfe;
  --clr-shadow: 0 20px 48px rgba(2, 6, 23, 0.45);

  /* Data Quality's green, dark half (#2344). --dq-primary is absent on purpose:
     it fills buttons that carry white text, so lightening it would drop that
     text's contrast. Only the text/border/soft roles adapt. */
  --dq-primary-text: #6ee7b7;
  --dq-primary-soft: rgba(15, 122, 93, 0.28);
  --dq-primary-border: #2f8f74;
}
