/* The design tokens, and nothing else.
 *
 * ⚠️ THIS FILE EXISTS SO THE PAGES CANNOT DISAGREE. It was inline in
 * index.html until dash.html needed the same palette, and a second copy of
 * ninety lines of colour is a drift waiting to happen - the map gets a new
 * accent, the dashboard keeps the old one, and nothing at runtime says so.
 * One definition, one <link> per page.
 */
/* 🔑 WARM PAPER, MONOSPACE, NO FRAMEWORK AND NO WEBFONT.
 *
 * 2026-10-22: the palette moved off Tailwind's cool slate onto a warm paper
 * ground, and the type moved to monospace throughout. The scales are still
 * borrowed where a borrowed number is better than an invented one - the
 * accents are Tailwind's indigo/orange/emerald steps - but the neutrals are
 * warm and chosen against the surfaces below.
 *
 * ⚠️ TAILWIND ITSELF IS NOT AN OPTION, and the reason is the CSP rather
 * than taste: nginx sends `script-src 'self'`, and the Tailwind CDN is a
 * SCRIPT - a runtime compiler. The built route needs Node, a CSS artifact
 * in the deploy and a staleness check: a toolchain and a new silent-failure
 * mode, for styling.
 *
 * ⚠️ AND NO WEBFONT. `default-src 'self'` would allow a self-hosted woff2,
 * but not Google Fonts - and a vendored font is ~100 KB of binary in the
 * repo for a face the machine already has. The stack below resolves to
 * SF Mono on the Mac, Menlo on older ones, Consolas on Windows, DejaVu on
 * Linux. Nothing to load, nothing to go stale, no FOUT.
 *
 * 🔑 EVERY COLOUR BELOW WAS CHECKED, NOT CHOSEN. Contrast against its own
 * surface, and the series pair's separation under protanopia, deuteranopia
 * and tritanopia. The numbers are in the comments where they matter.
 */
:root{
  /* ---- the ground ---------------------------------------------------
     Warm paper rather than cool grey, which is the whole mood shift. The
     cards stay pure white so the chart palette validated against white is
     still validated. */
  --bg:#faf8f4;        /* paper   */
  --card:#ffffff;
  --line:#e9e3d9;      /* hairline, 1.28:1 on the card - visible, quiet   */
  --line2:#d8cfc0;     /* a hover edge                                    */
  --fg:#1c1a17;        /* warm near-black, 17.4:1                         */
  --mut:#7a7267;       /* 4.74:1 ⚠️ #8a8277 read better and failed at 3.79 */

  /* ---- the two accents, which do different jobs ----------------------
     🔑 --acc IS DATA AND INTERACTION; --brand IS IDENTITY. Splitting them
     is what lets the chrome be terracotta without a warning pill and an
     active tab sharing a colour. --acc stays in the blue-indigo family so
     the chart series and the sequential ramp still belong to it. */
  --acc:#4338ca;       /* indigo-700, 7.90:1 */
  --acc-soft:#eef0fd;
  --brand:#c2410c;     /* terracotta, 5.18:1 - the wordmark and the current tab */
  --brand-soft:#fdf2ec;
  --ring:#4338ca66;

  /* ---- status, reserved ----------------------------------------------
     ⚠️ NEVER a series colour and never a tab's identity: these four mean a
     STATE, and a palette that spends red on "the third line" has nothing
     left to say "this battery is flat". */
  --ok:#15803d;        /* 5.02:1 */
  --warn:#b45309;      /* 5.02:1 */
  --bad:#b91c1c;       /* 6.47:1 */

  /* ---- type -----------------------------------------------------------
     🔑 ONE FAMILY, EVERYWHERE. A table of readings in a proportional face
     is ragged, and the eye reads ragged as noise. Mono fixes that for the
     numbers and sets the tone for everything else. */
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,
         "DejaVu Sans Mono",monospace;

  /* spacing: the 0.25rem step */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:20px; --s6:24px;
  /* radius. ⚠️ Smaller than before - paper and mono want crisp corners. */
  --r-sm:3px; --r:5px; --r-md:7px; --r-lg:10px; --r-xl:14px;
  /* elevation. Warm shadows: a grey shadow on cream reads as dirt. */
  --sh-sm:0 1px 2px 0 #2a1f1208;
  --sh:0 1px 3px 0 #2a1f1214,0 1px 2px -1px #2a1f1214;
  --sh-lg:0 10px 15px -3px #2a1f121a,0 4px 6px -4px #2a1f121a;
  /* motion */
  --t:150ms cubic-bezier(.4,0,.2,1);
  /* 🔑 ONE HEIGHT FOR EVERY INLINE CONTROL. See the select rule in
     dash.css for why matching padding is not enough. */
  --ctl-h:32px;

  /* ---- chart series -------------------------------------------------
     🔑 VALIDATED, NOT CHOSEN - contrast against this theme's own card and
     separation under all three dichromacies:

       light  #2563eb + #ea580c   on white 5.17 / 3.56
              dE normal 39.6  protan 31.8  deutan 37.5  tritan 46.1
       dark   #3b82f6 + #ea580c   on #1e1a15 4.70 / 4.86
              dE normal 36.1  protan 30.6  deutan 33.4  tritan 40.7

     ⚠️ Two slots, in a fixed order, and a third series is NOT a third hue
     invented here - it is a second chart. Almost every chart on the
     dashboard is a single measure over time and needs no categorical
     colour at all; this pair exists for the two that compare L1 against
     L5. */
  --c1:#2563eb; --c2:#ea580c;
  /* Sequential, one hue light->dark: how well a cell's position is known. */
  --q1:#dbeafe; --q2:#93c5fd; --q3:#60a5fa; --q4:#3b82f6; --q5:#1d4ed8;
  --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%237a7267' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 7.5 5 5 5-5'/%3E%3C/svg%3E");
  /* 🔑 THE BASEMAP IS WARMED TO MATCH THE PAGE. Standard OSM is a cool
     blue-green sheet and it sat in the cream chrome like a window into a
     different product. ⚠️ Kept gentle: this is a map people navigate by,
     so the filter must not cost legibility. */
  --tile-filter:sepia(.22) saturate(.9) brightness(1.02) contrast(.96);
  --attrib-bg:#faf8f4c0;
}
/* 🔑 THREE STATES, TWO SELECTORS.
   An absent `data-theme` means FOLLOW THE SYSTEM - the default, and what
   the media query is for. ⚠️ :not([data-theme="light"]) is what lets
   somebody on a dark Mac force light: without it the media query still
   wins and the toggle looks broken in exactly one direction, which is the
   hardest kind of broken to notice while testing on a light machine.
   The second selector is the mirror - dark forced on a light system.

   ⚠️ THE REFERENCE THIS PALETTE COMES FROM HAS NO DARK MODE. The warm dark
   below is this project's, built in the same family: warm ink rather than
   the old blue-black slate, and every step re-checked against it. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --bg:#15120e;      /* warm ink   */
    --card:#1e1a15;
    --line:#332c23;    /* 1.26:1 on the card */
    --line2:#423a2f;
    --fg:#efe9df;      /* 14.3:1 */
    --mut:#a0968a;     /* 5.95:1 */
    --acc:#818cf8;     /* indigo-400, 5.80:1 */
    --acc-soft:#232034;
    --brand:#e8835a;   /* terracotta lifted off the ink, 6.45:1 */
    --brand-soft:#2b211a;
    --ring:#818cf880;
    --ok:#34d399; --warn:#fbbf24; --bad:#f87171;
    --sh-sm:0 1px 2px 0 #00000059;
    --sh:0 1px 3px 0 #00000073,0 1px 2px -1px #00000073;
    --sh-lg:0 10px 15px -3px #00000080,0 4px 6px -4px #00000080;
    --c1:#3b82f6; --c2:#ea580c;
    /* ⚠️ The ramp RUNS THE OTHER WAY on a dark surface - a near-white step
       is the loud end here, where on white it was the quiet one. */
    --q1:#1e3a8a; --q2:#1d4ed8; --q3:#2563eb; --q4:#3b82f6; --q5:#93c5fd;
    --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23a0968a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 7.5 5 5 5-5'/%3E%3C/svg%3E");
    --tile-filter:invert(1) hue-rotate(180deg) brightness(.92)
      contrast(.88) saturate(.75);
    --attrib-bg:#1e1a15c0;
  }
}
:root[data-theme="dark"]{
    --bg:#15120e;      /* warm ink   */
    --card:#1e1a15;
    --line:#332c23;    /* 1.26:1 on the card */
    --line2:#423a2f;
    --fg:#efe9df;      /* 14.3:1 */
    --mut:#a0968a;     /* 5.95:1 */
    --acc:#818cf8;     /* indigo-400, 5.80:1 */
    --acc-soft:#232034;
    --brand:#e8835a;   /* terracotta lifted off the ink, 6.45:1 */
    --brand-soft:#2b211a;
    --ring:#818cf880;
    --ok:#34d399; --warn:#fbbf24; --bad:#f87171;
    --sh-sm:0 1px 2px 0 #00000059;
    --sh:0 1px 3px 0 #00000073,0 1px 2px -1px #00000073;
    --sh-lg:0 10px 15px -3px #00000080,0 4px 6px -4px #00000080;
    --c1:#3b82f6; --c2:#ea580c;
    /* ⚠️ The ramp RUNS THE OTHER WAY on a dark surface - a near-white step
       is the loud end here, where on white it was the quiet one. */
    --q1:#1e3a8a; --q2:#1d4ed8; --q3:#2563eb; --q4:#3b82f6; --q5:#93c5fd;
    --chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23a0968a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 7.5 5 5 5-5'/%3E%3C/svg%3E");
    --tile-filter:invert(1) hue-rotate(180deg) brightness(.92)
      contrast(.88) saturate(.75);
    --attrib-bg:#1e1a15c0;
}
