/* The palette. Every colour in this application is defined here, once, for both
 * themes at the same time.
 *
 * There is no second block of light-mode overrides and no `prefers-color-scheme`
 * media query. Each token is a `light-dark()` pair, so the theme is chosen by one
 * property — `color-scheme` — and the whole page follows, including the parts CSS
 * does not own: native form controls, scrollbars, the caret, and the default
 * canvas behind the page.
 *
 *     :root                    color-scheme: light dark   → follows the OS
 *     html[data-theme=light]   color-scheme: light        → chosen
 *     html[data-theme=dark]    color-scheme: dark         → chosen
 *
 * `assets/theme.js` sets that attribute before first paint. Without it — a page
 * with scripts blocked, or the offline report opened from disk — `light dark`
 * still resolves against the reader's system, so the fallback is the right theme
 * rather than a broken one.
 *
 * One consequence worth knowing before reading a token out in script:
 * `getComputedStyle(root).getPropertyValue("--series-1")` returns the literal
 * text `light-dark(#1f6feb, #4c93f7)`, because custom properties compute as
 * specified. Anything that needs a real colour — Chart.js does — must resolve it
 * through an element, which is what `UC6Theme.colour()` exists to do.
 *
 * Colour policy: the neutrals carry the design and the hues carry meaning. Six
 * accents, each with a job (see below), used at full strength for a stroke or a
 * glyph and as a 12–16% tint for a fill. Chart fills are tints for that reason —
 * a chart should read as ink with colour in it, not as colour with ink on top.
 */

:root {
  /* Follows the system until theme.js or a reader says otherwise. */
  color-scheme: light dark;

  /* ── neutrals ───────────────────────────────────────────────────────────
   * Light is parchment rather than #fff, and cards lift *up* to white; dark is
   * near-black, and cards lift up to graphite. The direction of elevation
   * reverses between themes, which is why both are written as pairs rather than
   * one being derived from the other by inversion.
   */
  --canvas:        light-dark(#fbfbfa, #090909);
  --surface-1:     light-dark(#ffffff, #131316);
  --surface-2:     light-dark(#f4f4f1, #1b1b1f);
  --surface-3:     light-dark(#eeeeea, #202024);
  --hairline:      light-dark(#e3e3df, #27272c);
  --hairline-soft: light-dark(#ececE8, #1b1b1e);

  --ink:           light-dark(#0e0e10, #ffffff);
  --ink-body:      light-dark(#26262a, #e4e4e8);
  --ink-muted:     light-dark(#6c6c72, #9a9aa2);
  --ink-faint:     light-dark(#91919a, #6e6e76);

  /* The primary action inverts: a white pill is invisible on parchment, so on
     light it becomes near-black with white type. Same shape, same contrast. */
  --primary:       light-dark(#101012, #ffffff);
  --on-primary:    light-dark(#ffffff, #000000);

  /* ── accents ────────────────────────────────────────────────────────────
   * Muted jewel tones, not the saturated defaults of a component library. Each
   * light value is darkened until it holds 4.5:1 on the light canvas; each dark
   * value is lifted until it holds 4.5:1 on the dark one. Tested, not eyeballed
   * — see scripts/check_contrast.py.
   *
   * The values are the output of scripts/check_contrast.py, not of taste alone:
   * each one holds 4.5:1 on both the page and a card in its own theme, and all
   * five series stay at least 0.10 apart in OKLab — 0.055 under simulated
   * deuteranopia and protanopia. That last constraint is what set ochre lighter
   * and rose deeper than they would otherwise be: gold and pink are the pair that
   * collapses into one colour for a red-green deficiency, and lightness is the
   * only separation that survives it.
   *
   *   azure   the signal colour: links, focus, the primary series
   *   iris    identity: the AI surfaces, spotlight panels, the fifth series
   *   jade    good news: success, headroom, positive movement
   *   ochre   caution: warnings, the middle of an ordinal ramp
   *   rose    loss: revenue at risk, failures, negative movement
   *   copper  exposure: the formulary sections and the top of the ordinal ramp
   */
  --azure:         light-dark(#1b6ceb, #5fa5ff);
  --iris:          light-dark(#7038cf, #bd8dff);
  --jade:          light-dark(#0f7a64, #3fc9a2);
  --ochre:         light-dark(#8a5d0f, #f5c96b);
  --rose:          light-dark(#bd2b5f, #f2708f);
  --copper:        light-dark(#a85426, #ef8b4d);

  /* The one chromatic signal that is never decorative. */
  --accent:        var(--azure);
  --accent-blue:   var(--azure);   /* the name the pages already use */

  /* A hue used as a *fill* cannot be the same value as a hue used as a mark: the
     azure that reads well as text on black is too light to carry white type. So
     filled controls — the send button, the user's own chat bubble — get a deeper
     value, and white type holds 4.5:1 on both. */
  --accent-fill:   light-dark(#1b62d4, #2b6fd6);
  --on-accent:     #ffffff;

  /* Tints: the same hue as a surface rather than as a mark. */
  --azure-soft:    color-mix(in oklab, var(--azure)  light-dark(9%, 15%), transparent);
  --iris-soft:     color-mix(in oklab, var(--iris)   light-dark(9%, 15%), transparent);
  --jade-soft:     color-mix(in oklab, var(--jade)   light-dark(10%, 16%), transparent);
  --ochre-soft:    color-mix(in oklab, var(--ochre)  light-dark(12%, 16%), transparent);
  --rose-soft:     color-mix(in oklab, var(--rose)   light-dark(10%, 16%), transparent);
  --copper-soft:   color-mix(in oklab, var(--copper) light-dark(11%, 16%), transparent);


  /* Light/dark counterpart surfaces, for the pair of mock thumbnails on the
     landing page that exist to show one of each. They invert with the theme, so
     the pair stays a pair instead of one of them disappearing. */
  --inverse-canvas: light-dark(#101012, #ffffff);
  --inverse-ink:    light-dark(#ffffff, #101012);

  /* ── the choropleth ramp ────────────────────────────────────────────────
   * Seven steps of one hue for the state cartogram. Sequential data, so the ramp
   * is monotone in lightness and the most saturated end is always the high end —
   * running dark→light on the dark canvas and light→dark on the light one.
   *
   * Teal-cyan rather than the navy this used to be. Navy's quiet end sat at
   * #15171b against a #090909 canvas and a #131316 card, so on the dark theme
   * the bottom third of a fifty-tile map was indistinguishable from the surface
   * it was drawn on — the map read as a handful of bright states floating in
   * nothing. Cyan carries far more chroma at the same lightness, so a low step
   * is visibly a tile rather than a hole, and the high end lands somewhere a
   * navy ramp cannot reach without turning pale.
   *
   * The floor is as high as the label rule allows, not as high as it could be:
   * steps 1-4 carry a 55%-white label on the dark theme, which caps how light
   * they may get. That constraint is what fixes the spacing, and it is checked
   * in scripts/check_contrast.py rather than eyeballed.
   */
  --ramp-1: light-dark(#eff5f7, #0e2b33);
  --ramp-2: light-dark(#d7e9f0, #113f4d);
  --ramp-3: light-dark(#b1d7e3, #125668);
  --ramp-4: light-dark(#7dbdd0, #0c6377);
  --ramp-5: light-dark(#3d97b1, #1fa2c0);
  --ramp-6: light-dark(#1e7491, #48c8e0);
  --ramp-7: light-dark(#0a4e68, #8ae7f5);
  /* Type on a ramp tile: the high end of the ramp is the high-contrast end, so
     the label flips once, not per tile. */
  --ramp-ink-high: light-dark(#ffffff, #04161c);
  --ramp-ink-low:  light-dark(rgba(14, 14, 16, 0.55), rgba(255, 255, 255, 0.55));

  /* ── semantic ───────────────────────────────────────────────────────────*/
  --success:       var(--jade);
  --warn:          var(--ochre);
  --critical:      var(--rose);
  --success-soft:  var(--jade-soft);
  --warn-soft:     var(--ochre-soft);
  --critical-soft: var(--rose-soft);

  /* ── charts ─────────────────────────────────────────────────────────────
   * Five categorical series and one ordinal ramp. The ramp is a single hue,
   * monotone in lightness, because the thing it encodes (how replaceable a drug
   * is) is ordered data — a categorical palette would imply identity. It runs
   * dark→light on the dark canvas and light→dark on the light one, so "harder"
   * is always the higher-contrast end.
   */
  --series-1: var(--azure);
  --series-2: var(--jade);
  --series-3: var(--ochre);
  --series-4: var(--rose);
  --series-5: var(--iris);
  --series-1-soft: var(--azure-soft);
  --series-2-soft: var(--jade-soft);
  --series-3-soft: var(--ochre-soft);
  --series-4-soft: var(--rose-soft);
  --series-5-soft: var(--iris-soft);

  --band-easy: light-dark(#c18644, #b3691c);
  --band-some: light-dark(#a85f1f, #d07f22);
  --band-hard: light-dark(#6b3410, #f6c89a);

  /* ── categorical ────────────────────────────────────────────────────────
   * Ten steps for the places that genuinely have ten things to tell apart — the
   * mart explorer's marts and the slices of a share chart. The six accents come
   * first, then four of them deepened toward the canvas, so neighbouring entries
   * differ in lightness as well as in hue and the sequence survives being read
   * in greyscale. No eleventh: past ten, a legend is doing the work colour
   * cannot, and the label is already there.
   */
  --cat-1:  var(--azure);
  --cat-2:  var(--jade);
  --cat-3:  var(--ochre);
  --cat-4:  var(--iris);
  --cat-5:  var(--rose);
  --cat-6:  var(--copper);
  --cat-7:  color-mix(in oklab, var(--azure) 62%, light-dark(#0e0e10, #f2f2f5));
  --cat-8:  color-mix(in oklab, var(--jade) 62%, light-dark(#0e0e10, #f2f2f5));
  --cat-9:  color-mix(in oklab, var(--iris) 62%, light-dark(#0e0e10, #f2f2f5));
  --cat-10: color-mix(in oklab, var(--copper) 62%, light-dark(#0e0e10, #f2f2f5));

  /* A five-step diverging scale for tier movement, where both ends are a
     judgement — jade for a move in our favour, rose for a move against, and a
     desaturated middle that says "no material change" rather than "amber". */
  --div-1: var(--jade);
  --div-2: color-mix(in oklab, var(--jade) 55%, var(--ochre));
  --div-3: light-dark(#a9a29a, #93a0ac);
  --div-4: color-mix(in oklab, var(--rose) 55%, var(--ochre));
  --div-5: var(--rose);

  /* The dimming behind a modal or a drawer. */
  --scrim: light-dark(rgba(14, 14, 16, 0.34), rgba(0, 0, 0, 0.62));

  --grid:      light-dark(rgba(14, 14, 16, 0.07), rgba(255, 255, 255, 0.07));
  --grid-firm: light-dark(rgba(14, 14, 16, 0.13), rgba(255, 255, 255, 0.13));

  /* ── overlays ───────────────────────────────────────────────────────────
   * What `rgba(255,255,255,.08)` used to be written as inline. Spelled as tokens
   * because that literal is invisible on a light canvas, and there were 47 of
   * them on the landing page alone.
   */
  --overlay-1: light-dark(rgba(14, 14, 16, 0.035), rgba(255, 255, 255, 0.04));
  --overlay-2: light-dark(rgba(14, 14, 16, 0.06),  rgba(255, 255, 255, 0.07));
  --overlay-3: light-dark(rgba(14, 14, 16, 0.10),  rgba(255, 255, 255, 0.12));
  --overlay-4: light-dark(rgba(14, 14, 16, 0.16),  rgba(255, 255, 255, 0.20));

  --ink-a72: light-dark(rgba(14, 14, 16, 0.72), rgba(255, 255, 255, 0.72));
  --ink-a45: light-dark(rgba(14, 14, 16, 0.45), rgba(255, 255, 255, 0.45));
  --ink-a24: light-dark(rgba(14, 14, 16, 0.24), rgba(255, 255, 255, 0.24));

  /* ── depth ──────────────────────────────────────────────────────────────
   * On dark, elevation is a surface step and the shadow is almost nothing. On
   * light it has to be an actual shadow, so both live in the same token and the
   * pages do not branch.
   */
  --shadow-1: 0 1px 2px light-dark(rgba(16, 16, 18, 0.05), rgba(0, 0, 0, 0.30)),
              0 6px 16px light-dark(rgba(16, 16, 18, 0.05), rgba(0, 0, 0, 0.22));
  --shadow-2: 0 2px 4px light-dark(rgba(16, 16, 18, 0.06), rgba(0, 0, 0, 0.34)),
              0 18px 44px light-dark(rgba(16, 16, 18, 0.09), rgba(0, 0, 0, 0.40));
  --focus-ring: light-dark(rgba(31, 111, 235, 0.20), rgba(76, 147, 247, 0.20));

  /* ── the gradient spotlight family ──────────────────────────────────────
   * These panels stay saturated in both themes — they are posters, and their
   * type is white on top of the colour rather than on the page. The light values
   * are deepened so that white type still clears 4.5:1 on them.
   */
  --g-iris:    light-dark(#5b3fe0, #6a4cf5);
  --g-magenta: light-dark(#a93bc6, #bf44df);
  --g-copper:  light-dark(#c9662b, #df7534);
  --g-rose:    light-dark(#ce3f5a, #e2566f);
  /* the names the landing page already uses */
  --g-violet:  var(--g-iris);
  --g-orange:  var(--g-copper);
  --g-coral:   var(--g-rose);

  /* ── aliases ────────────────────────────────────────────────────────────
   * The names written before this file existed. Kept so the dashboard shell,
   * auth.css and user-card.css did not all have to be rewritten in the same
   * change as the palette — they resolve to the tokens above and therefore
   * theme correctly without knowing that they do.
   */
  --canvas-soft:     var(--surface-2);
  --canvas-card:     var(--surface-1);
  --canvas-mid:      var(--surface-3);
  --hairline-strong: light-dark(#d5d5d0, #313138);
  --body:            var(--ink-body);
  --mute:            var(--ink-muted);
  --good:            var(--success);
  --field:           var(--surface-2);
  --line:            var(--hairline);
}

html[data-theme="light"] { color-scheme: light; }
html[data-theme="dark"]  { color-scheme: dark; }

/* The page background is painted by the root as well as by body, so a short page
   and an over-scroll on a phone show the theme rather than the browser's idea of
   white. */
html { background: var(--canvas); }

::selection { background: color-mix(in oklab, var(--azure) 28%, transparent); color: var(--ink); }

/* ──────────────────────────────────────────────────────────────────────────
   THE SWITCH
   Markup is built by theme.js into any `[data-theme-switch]` element, so a page
   opts in by placing one empty div and never repeats the three buttons.
   ────────────────────────────────────────────────────────────────────────── */

.themeswitch {
  display: inline-flex; align-items: center; gap: 2px; padding: 3px;
  background: var(--surface-2); border: 1px solid var(--hairline);
  border-radius: 100px; line-height: 1;
}
.themeswitch__btn {
  display: grid; place-items: center; width: 28px; height: 28px; padding: 0;
  border: 0; border-radius: 100px; background: none; color: var(--ink-muted);
  cursor: pointer; transition: background 0.18s ease, color 0.18s ease;
  min-height: 0;
}
/* The two state rules are written as `.themeswitch .themeswitch__btn` rather
   than `.themeswitch__btn`, which is otherwise the same element. The extra class
   buys specificity: auth.css styles the primary pill as a bare `button` and
   paints its hover with `button:hover:not(:disabled)`, which is 0-2-1 and beats
   a plain `.themeswitch__btn:hover` at 0-2-0 — so hovering the switch filled it
   with the primary colour while the icon kept the muted ink, i.e. near-black on
   near-black in light and the inverse in dark. The switch has to outrank any
   page's idea of what a button looks like, because it is mounted onto pages that
   were styled before it existed. */
.themeswitch .themeswitch__btn:hover { color: var(--ink); background: var(--overlay-2); }
.themeswitch__btn svg { width: 15px; height: 15px; display: block; }
.themeswitch .themeswitch__btn[aria-checked="true"] {
  background: var(--surface-1); color: var(--ink);
  box-shadow: var(--shadow-1);
}
.themeswitch__btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--azure), 0 0 0 4px var(--focus-ring);
}

@media (prefers-reduced-motion: reduce) {
  .themeswitch__btn { transition: none; }
}
