/* One source for Next.js and Django allauth surfaces. */
:root {
  color-scheme: light;

  /* Layer 1: structure. A deliberately COOL near-neutral ramp (Plan 013,
     Option E · Cool steel), not the true neutral it was: every step carries a
     slight blue cast so light mode stops reading flat and stops reading as
     dark mode's twin. The cast is capped low — structure is *tinted*, never
     coloured — because MASTER §3 records what happens when it is not: the
     all-blue first pass, where brand-tinted text, rules and surfaces left the
     brand signalling nothing and the console reading as a Microsoft surface.
     Teal remains the only action/identity colour. */
  --n-0: #ffffff; /* true white: the login panel's text, the TOTP QR plate */
  --n-25: #fbfdff; /* card */
  --n-50: #f5f8fb; /* table zebra row */
  --n-100: #edf3f8; /* muted surface */
  --n-125: #eaf1f7; /* table header band */
  --n-200: #e7eef5; /* page canvas */
  --n-250: #dde7f0; /* table totals row */
  --n-300: #c9d5e2; /* border */
  --n-500: #50657a; /* muted foreground */
  --n-900: #142033; /* foreground */
  /* The dark surface ramp. --d-* is a cross-file contract rather than private
     working notes: Django's own backend/static/css/auth.css reads --d-muted-fg
     directly, so renaming one here renames it there. */
  --d-bg: #091523;
  --d-card: #112338;
  --d-zebra: #14283b;
  --d-thead: #172b40;
  --d-elev: #192e43; /* muted surface */
  --d-totals: #1e3550; /* table totals row */
  --d-border: #29435d;
  --d-fg: #eaf2f8;
  --d-muted-fg: #9cb1c5;
  /* Dark chrome. --d-sidebar-field-border repeats --d-border's hex and is kept
     separate anyway: they are the same colour by coincidence, not by rule, and
     the field border has to be free to move when the field surface does. */
  --d-sidebar: #07111d;
  --d-sidebar-fg: #e2eaf2;
  --d-sidebar-border: #20364c;
  --d-sidebar-field: #0a1827;
  --d-sidebar-field-border: #29435d;
  /* The chrome is slate in BOTH themes, so everything drawn on it takes the
     dark theme's brand values even while the page is light — these are those,
     named once here instead of repeated across five --sidebar-* roles. */
  --brand-on-dark: #2dd4bf; /* the teal itself: active mark, ring */
  --brand-on-dark-hi: #6ee7d5; /* lifted, for the active nav label */
  --brand-on-dark-ink: #071e1a; /* ink laid on top of the teal */
  --brand-on-dark-soft: rgb(45 212 191 / 0.14); /* the active nav tint */
  --bg: var(--n-200);
  --card: var(--n-25);
  --fg: var(--n-900);
  --muted: var(--n-100);
  --muted-fg: var(--n-500);
  --border: var(--n-300);
  /* Table chrome, named apart from --muted because it bands a table rather
     than lifts a panel: a zebra row sharing the muted surface stops reading as
     a stripe the moment a muted panel sits beside the table. The totals band is
     a third step, not a shade of the header: it used to be --n-150, 1.009:1
     from --thead, which is not a band at all, and in dark it was literally
     --d-elev — the same token as --muted. Now --n-250 is 1.099:1 from --thead
     and 1.229:1 from --card; --d-totals is 1.154:1 from --d-thead, 1.110:1
     from --d-elev and 1.272:1 from --d-card. --muted-fg holds 4.81:1 on the
     light band and --d-muted-fg 5.66:1 on the dark one. */
  --thead: var(--n-125);
  --zebra: var(--n-50);
  --totals: var(--n-250);

  /* Layer 2: Theme B, Graphite + Teal. */
  --brand: #0f766e;
  --brand-hi: #0d6660;
  --on-brand: #ffffff;
  --brand-soft: #ecfaf7;
  /* The menu/row highlight, and deliberately not --brand-soft: over the
     popover — which is --card — --brand-soft measures 1.052:1 light and
     1.048:1 dark, a highlight nobody can see. A brand alpha at the same 0.14
     the sidebar already uses composites to 1.215:1 light and 1.347:1 dark,
     beside the sidebar's own 1.344:1. It stays an alpha rather than a hex so
     the step survives over the card, the canvas and a zebra row alike, and
     --accent-foreground (--fg) still reads 13.2:1 light, 10.4:1 dark on it. */
  --accent-surface: rgb(15 118 110 / 0.14);
  --accent: #d97706;
  --ring: #0f766e;
  --panel: #0c2a2a;
  --status-ok-mark: #22c55e;
  --status-ok-text: #15803d;
  --status-warn-mark: #f59e0b;
  --status-warn-text: #b45309;
  --status-risk-mark: #ef4444;
  --status-risk-text: #b91c1c;

  /* Layer 3: fixed data-series identity, independent of brand. */
  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;

  --font-sans: "Fira Sans", system-ui, sans-serif;
  --font-mono: "Fira Code", ui-monospace, monospace;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --radius: 6px;
  --table-row-h: 38px;
  --shadow-card:
    0 1px 3px rgb(15 39 64 / 0.08), 0 4px 12px rgb(15 39 64 / 0.07);
  /* The dark card elevation, a primitive under its own name because a dark arm
     cannot write --shadow-card: var(--shadow-card) — that is a self-reference,
     not an override. */
  --d-shadow-card:
    inset 0 1px 0 rgb(255 255 255 / 0.035), 0 3px 12px rgb(0 0 0 / 0.38);

  /* shadcn semantic bridge. */
  --background: var(--bg);
  --foreground: var(--fg);
  --popover: var(--card);
  --popover-foreground: var(--fg);
  --primary: var(--brand);
  --primary-foreground: var(--on-brand);
  --secondary: var(--muted);
  --secondary-foreground: var(--fg);
  --muted-foreground: var(--muted-fg);
  --accent-foreground: var(--fg);
  --destructive: var(--status-risk-text);
  --input: var(--border);
  /* Badges, the one component whose *shape* has to read at a glance. **The
     border carries the shape**, and one border does it for both variants:
     `secondary` is the filled pill and `outline` the hollow one. A surface one
     step off the card is not a shape — on a zebra row it is nearly the badge's
     own, so a column of statuses stops reading as a column of badges. The
     border needs a step the neutral ramp does not have: --n-300 is 1.46:1 on
     --card and 1.40:1 on --zebra, a line nobody sees, and the next step --n-500
     is 5.91:1, a rule heavier than the text it encloses. #7a8da3 sits between
     them at 3.34:1 on --card and 3.20:1 on --zebra; the dark arm's #5f7893 is
     3.48:1 and 3.29:1. Both are deliberately heavier than the card and table
     borders around them (2.29:1 and 2.24:1 measured against those) — a badge is
     a shape *on* a surface, not another rule across it. */
  --badge-border: #7a8da3;
  /* Chrome, and the one place the two themes deliberately stop being twins:
     the sidebar is slate in *both*, so it never tracks --card. Everything
     rendered on it therefore needs its own values rather than the page's —
     the page ring (#0f766e) is 2.4:1 on this ground, and the page border is a
     bright line across it. globals.css redirects --border/--input/--ring/
     --destructive inside [data-slot="sidebar"] so nothing inside inherits the
     wrong one. */
  --sidebar: #203248;
  --sidebar-foreground: #e7eef6;
  --sidebar-primary: var(--brand-on-dark);
  --sidebar-primary-foreground: var(--brand-on-dark-ink);
  --sidebar-accent: var(--brand-on-dark-soft);
  --sidebar-accent-foreground: var(--brand-on-dark-hi);
  --sidebar-border: #35495f;
  --sidebar-ring: var(--brand-on-dark);
  --sidebar-field: #19283a;
  --sidebar-field-border: #40556c;
  /* The risk ink the *dark* theme already picks, for the reason it picks it:
     dark chrome. The light theme's #b91c1c is 2.0:1 on the slate. */
  --sidebar-destructive: #f87171;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: var(--d-bg);
  --card: var(--d-card);
  --fg: var(--d-fg);
  --muted: var(--d-elev);
  --muted-fg: var(--d-muted-fg);
  --border: var(--d-border);
  --thead: var(--d-thead);
  --zebra: var(--d-zebra);
  --totals: var(--d-totals);
  /* The badge border takes the dark ramp step picked for it beside the light
     one in :root, where the measurements are. */
  --badge-border: #5f7893;
  --shadow-card: var(--d-shadow-card);
  --brand: var(--brand-on-dark);
  --brand-hi: #5ee0d0;
  --on-brand: #06201c;
  --brand-soft: #0f2a2a;
  --accent-surface: rgb(45 212 191 / 0.14);
  --accent: #fbbf24;
  --ring: var(--brand-on-dark);
  --panel: #08201f;
  /* Status *text* has to be re-picked for dark, not inherited: the light values
     are dark inks. #b91c1c is 2.5:1 on --d-card, under the 4.5:1 this design
     system requires, and --destructive is built from it — so every
     destructive control and error string in the app was failing in dark mode.
     Marks (chart fills, dots) keep their light values; they only need 3:1. */
  --status-ok-text: #4ade80;
  --status-warn-text: #fbbf24;
  --status-risk-text: #f87171;
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  /* Chrome stays slate in both themes; only its depth changes. The brand values
     on it (primary, primary-foreground, accent, accent-foreground, ring) read
     the --brand-on-dark primitives in :root, which do not change with the
     theme, so they are inherited here rather than repeated. */
  --sidebar: var(--d-sidebar);
  --sidebar-foreground: var(--d-sidebar-fg);
  --sidebar-border: var(--d-sidebar-border);
  --sidebar-field: var(--d-sidebar-field);
  --sidebar-field-border: var(--d-sidebar-field-border);
}

/* Follow the operating system when the viewer has expressed no preference.
   The :where(:not(...)) guard keeps this rule at low specificity and lets an
   explicit light choice beat OS-dark — so the toggle wins in both directions,
   not just one. */
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
  color-scheme: dark;
  --bg: var(--d-bg);
  --card: var(--d-card);
  --fg: var(--d-fg);
  --muted: var(--d-elev);
  --muted-fg: var(--d-muted-fg);
  --border: var(--d-border);
  --thead: var(--d-thead);
  --zebra: var(--d-zebra);
  --totals: var(--d-totals);
  /* The badge border takes the dark ramp step picked for it beside the light
     one in :root, where the measurements are. */
  --badge-border: #5f7893;
  --shadow-card: var(--d-shadow-card);
  --brand: var(--brand-on-dark);
  --brand-hi: #5ee0d0;
  --on-brand: #06201c;
  --brand-soft: #0f2a2a;
  --accent-surface: rgb(45 212 191 / 0.14);
  --accent: #fbbf24;
  --ring: var(--brand-on-dark);
  --panel: #08201f;
  /* Status *text* has to be re-picked for dark, not inherited: the light values
     are dark inks. #b91c1c is 2.5:1 on --d-card, under the 4.5:1 this design
     system requires, and --destructive is built from it — so every
     destructive control and error string in the app was failing in dark mode.
     Marks (chart fills, dots) keep their light values; they only need 3:1. */
  --status-ok-text: #4ade80;
  --status-warn-text: #fbbf24;
  --status-risk-text: #f87171;
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  /* Chrome stays slate in both themes; only its depth changes. The brand values
     on it (primary, primary-foreground, accent, accent-foreground, ring) read
     the --brand-on-dark primitives in :root, which do not change with the
     theme, so they are inherited here rather than repeated. */
  --sidebar: var(--d-sidebar);
  --sidebar-foreground: var(--d-sidebar-fg);
  --sidebar-border: var(--d-sidebar-border);
  --sidebar-field: var(--d-sidebar-field);
  --sidebar-field-border: var(--d-sidebar-field-border);
}
}
