/*
 * brand.css — THE single place to change Ratenova's brand colours.
 *
 * Loaded first on every page family (base.html, control_base.html, the
 * control auth pages, login, and marketing). Everything brand-coloured in
 * the other stylesheets and inline <style> blocks references these tokens —
 * directly (var(--brand-600)) or via derived tokens in theme.css
 * (--th-brand, hero glows via color-mix). To rebrand the site, edit the
 * values below and nothing else.
 *
 * Scale runs light → dark (Tailwind-style weights).
 *
 * Two blocks: the BRAND scale (below) and the CHART tokens (further down, with
 * their own header). The chart block is keyed on data-theme rather than
 * data-accent and spells its hues as literals — read its comment before
 * changing anything in it, because its values are load-bearing for
 * accessibility, not cosmetic.
 *
 * The [data-accent="violet"] selector is here rather than in prefs.css on
 * purpose: violet is the brand, so this stays the only file that says what
 * violet is. It matters because an element can carry a data-accent of its own —
 * the accent swatches on Account Settings do, to paint themselves in the colour
 * they apply — and without it the violet swatch would inherit whichever accent
 * the user currently has selected and stop showing violet at all.
 */
:root,
[data-accent="violet"] {
  --brand-300: #c4b5fd;
  --brand-400: #a78bfa;
  --brand-500: #8b5cf6;
  --brand-600: #7c3aed;
  --brand-700: #6d28d9;

  /* Gradient partner used in avatar / logo marks. */
  --brand-accent: #d946ef;

  /* Text colour used on top of solid brand backgrounds. */
  --brand-contrast: #ffffff;

  /* Brand-tinted dark chrome surfaces: the sidebar rail gradient, the
     sign-in / marketing canvases, the dark hero panels and the dark
     Intelligence Hub background. Hand-tuned tints of the brand hue —
     re-tune these when changing the scale above. */
  --brand-ink-0: #05060f;   /* deepest canvas (login, marketing, IH dark) */
  --brand-ink-1: #0a0b1c;   /* canvas gradient partner */
  --brand-rail-0: #140b26;  /* sidebar rail gradient bottom / dark hero base */
  --brand-rail-1: #1c1038;  /* sidebar rail gradient top / dark hero mid */
  --brand-rail-2: #2a1852;  /* dark hero highlight */
}

/* ═══ CHART TOKENS ═══════════════════════════════════════════════════════════
 *
 * The colour vocabulary for every chart in the platform. Lives here because a
 * rebrand must change chart hues too, and this file is the one place that
 * happens — but note two deliberate departures from the block above.
 *
 * 1. LITERAL HEX, NOT var(--brand-*). prefs.css loads directly after this file
 *    and rewrites --brand-* from [data-accent="…"], so a chart written against
 *    var(--brand-600) would repaint per user. Series identity must be stable —
 *    a chart cannot mean something different depending on who is logged in, and
 *    the colourblind-separation guarantees below were computed for THESE hexes
 *    and would not survive an accent swap. Slot 1 is the literal value of
 *    --brand-600 / --brand-500 rather than a reference to it; keep them in sync
 *    by hand when rebranding. This is the one file allowed to hold brand-hue
 *    literals, so the "no new hardcoded brand literals" rule still holds.
 *
 * 2. KEYED ON data-theme, NOT data-accent. Same reason.
 *
 * ── The slot ORDER is a safety mechanism, not decoration ─────────────────────
 * Charts assign slots 1,2,3… in order and NEVER cycle. The order was searched
 * so that every ADJACENT pair stays distinguishable under simulated protanopia
 * and deuteranopia — adjacent because stacked segments, grouped bars and
 * legend neighbours are what actually sit side by side. Re-ordering these, or
 * inserting a hue, invalidates that and must be re-run through the validator.
 *
 * Measured (OKLab ΔE ×100; targets: CVD ≥ 8, normal-vision ≥ 15, ≥ 3:1 vs surface):
 *
 *            worst adjacent CVD   worst adjacent normal   contrast
 *   light           12.7                  15.7            all ≥ 3:1
 *   dark            14.0                  16.1            all ≥ 3:1
 *
 * SERIES CAP: the adjacent guarantee covers stacks, bars and lines. Scatter,
 * bubble, choropleth and small-multiples put NON-adjacent slots side by side,
 * so they are capped at the FIRST FOUR SLOTS, which clear the all-pairs gate in
 * both modes (worst pair CVD 8.2 light / 9.0 dark). Past four in those forms,
 * fold to "Other" or facet — do not reach for slot 5.
 *
 * A 9th series is never a generated hue. Fold it into "Other".
 *
 * Re-validate after ANY change (surfaces are per-mode and must be passed):
 *   validate_palette.py "<slots 1-8>" --mode light --surface "#ffffff"
 *   validate_palette.py "<slots 1-8>" --mode dark  --surface "#0e0f23"
 *   …and with --pairs all on the first four.
 */
:root,
[data-theme="light"] {
  /* Categorical — fixed order, never cycled. Slot 1 == --brand-600. */
  --chart-1: #7c3aed;  /* violet — brand */
  --chart-2: #c84e85;  /* magenta */
  --chart-3: #c16300;  /* orange */
  --chart-4: #008eae;  /* cyan     ← all-pairs safe up to here */
  --chart-5: #019a46;  /* green */
  --chart-6: #3a7ee0;  /* blue */
  --chart-7: #00948e;  /* teal */
  --chart-8: #928100;  /* yellow */

  /* Sequential — ONE hue, light→dark, for continuous magnitude (heatmaps,
     choropleths). The pale end is allowed to recede toward the surface. */
  --chart-seq-100: #e5e0ff;
  --chart-seq-150: #d2cbf4;
  --chart-seq-200: #bfb6e7;
  --chart-seq-250: #a99ed8;
  --chart-seq-300: #9487c8;
  --chart-seq-400: #8373bb;
  --chart-seq-500: #6f5cac;
  --chart-seq-600: #5d459c;
  --chart-seq-700: #4b2c8c;

  /* Ordinal — discrete ORDERED marks (funnel stages, tiers, confidence bands).
     A separate selection from the ramp above: neighbours need a visible
     lightness gap, which the continuous mid-steps do not give. */
  --chart-ord-1: #aca2da;
  --chart-ord-2: #9688ca;
  --chart-ord-3: #8070b9;
  --chart-ord-4: #6b57a8;
  --chart-ord-5: #583e98;

  /* Diverging — cyan ↔ orange around a neutral midpoint, for signed values
     (above/below plan, sentiment, share change). Deliberately NOT anchored on
     brand violet: a brand-coloured pole would imply "brand = good", which is
     wrong on a chart about a competitor. */
  --chart-div-cool-3: #0088a6;
  --chart-div-cool-2: #3bb1d3;
  --chart-div-cool-1: #a1d4e6;
  --chart-div-mid:    #eef0f4;
  --chart-div-warm-1: #e9c1a7;
  --chart-div-warm-2: #d88e59;
  --chart-div-warm-3: #b95e00;

  /* Chart chrome. Grid and axis are deliberately recessive — they orient, they
     do not compete with the data. */
  --chart-surface:    #ffffff;
  --chart-ink:        #0f172a;
  --chart-ink-soft:   #64748b;
  --chart-ink-muted:  #94a3b8;
  --chart-grid:       #e3e6f1;
  --chart-axis:       #cdd2e6;
}

[data-theme="dark"] {
  --chart-1: #8b5cf6;  /* violet — brand (== --brand-500) */
  --chart-2: #dd6197;
  --chart-3: #dc7100;
  --chart-4: #00a2c6;  /*          ← all-pairs safe up to here */
  --chart-5: #2cad58;
  --chart-6: #4c91f5;
  --chart-7: #00a8a2;
  --chart-8: #a69300;

  /* Sequential, DARK — re-stepped, not the light ramp flipped in place. The
     semantics of the token names are what stay fixed: -100 is always "near
     zero" and -700 always "maximum". On a light surface near-zero recedes by
     going pale; on a dark one it recedes by going deep, so magnitude climbs
     toward the LIGHT end here. Reusing the light ramp would put -700 at 1.8:1
     against this surface — the strongest value in the data, invisible. */
  --chart-seq-100: #3b0c7c;
  --chart-seq-150: #4b2c8c;
  --chart-seq-200: #5d459c;
  --chart-seq-250: #6f5cac;
  --chart-seq-300: #8373bb;
  --chart-seq-400: #978acb;
  --chart-seq-500: #aca2da;
  --chart-seq-600: #c2b9e9;
  --chart-seq-700: #d8d2f8;

  --chart-ord-1: #bfb6e7;
  --chart-ord-2: #a599d4;
  --chart-ord-3: #8c7dc2;
  --chart-ord-4: #7461af;
  --chart-ord-5: #5d459d;

  --chart-div-cool-3: #0088a6;
  --chart-div-cool-2: #0faacf;
  --chart-div-cool-1: #7fc7df;
  --chart-div-mid:    #2a2d42;
  --chart-div-warm-1: #e3ae8a;
  --chart-div-warm-2: #d48449;
  --chart-div-warm-3: #b95e00;

  /* --chart-surface is the OPAQUE composite of the translucent --ih-card
     (rgba(15,17,38,.72)) over the --brand-ink-0/1 canvas. Cards keep their
     translucency; this token exists for chart internals that must PAINT the
     surface colour — the 2px spacer between stacked segments, the ring on
     overlapping marks — and it is the surface every contrast figure above was
     measured against. Re-derive it if --ih-card or the ink canvas changes. */
  --chart-surface:    #0e0f23;
  --chart-ink:        #ffffff;
  --chart-ink-soft:   #9aa0c3;
  --chart-ink-muted:  #6a7093;
  --chart-grid:       rgba(148, 155, 220, 0.14);
  --chart-axis:       rgba(148, 155, 220, 0.26);
}

/* Status colours are RESERVED and never themed — a status hue must never be
 * reused as "series 5", or a chart will say "critical" when it means "EMEA".
 * They alias the canonical --th-* set (theme.css); the literal fallbacks cover
 * control-plane pages, which do not load theme.css — same pattern, and the
 * same reason, as the --ih-* status aliases in intelligence.css.
 *
 * These sit close to same-hue series slots by measurement, not by oversight:
 * on light, status-good is ΔE 5.0 from slot 5 (green) and status-warning ΔE
 * 6.8 from slot 3 (orange). That is why a status colour ALWAYS ships with an
 * icon and a label and never carries meaning by hue alone. */
:root,
[data-theme="light"] {
  --chart-status-good:     var(--th-success, #059669);
  --chart-status-warning:  var(--th-warning, #d97706);
  --chart-status-critical: var(--th-danger,  #dc2626);
}

[data-theme="dark"] {
  --chart-status-good:     var(--th-success, #34d399);
  --chart-status-warning:  var(--th-warning, #fbbf24);
  --chart-status-critical: var(--th-danger,  #f87171);
}
