/* THE PALETTE, IN ONE PLACE (2026-08-27).
 *
 * It was declared FOUR times -- `index.html`, `pour/index.html`,
 * `planner/index.html` and `admin/index.html` each carried their own `:root`
 * block -- and that is the drift at its SOURCE rather than a symptom of it.
 * Four copies cannot stay equal, and each was edited by whoever happened to be
 * working on that surface. What the copies had already produced, measured the
 * day they were collapsed:
 *
 *   LIGHT  all three of phone / panel / pour agreed, to the hex. Good.
 *   DARK   they agreed on NOTHING. Twelve tokens, twelve disagreements:
 *            --ink   #e7e9ec / #e8eaed      --line  #2b2f36 / #2c3036
 *            --ink2  #a7afb7 / #a9b0b8      --bg    #131519 / #15171a
 *            --ink3  #79818a / #7b828b      --card  #1c1f25 / #1d2024
 *            --accent    #5f8dff / #5a8cff  --hot   #f0736e / #ff6b6a
 *            --accent-bg #1a2740 / #1b2740  --hot-bg #381f1e / #3a1f1e
 *            --warm-bg   #352a16 / #332a17
 *            --ok / --ok-bg drifted THREE ways -- #33b481 / #3ac088 / #4bd0a0.
 *          Not one of those is a decision anybody made. They are what happens
 *          when a colour is typed twice.
 *
 * THIS COMMIT IS ZERO-PIXEL AND THE DRIFT IS PRESERVED, deliberately. Every
 * hex below is the one that surface already shipped; nothing is rounded,
 * averaged or "tidied". The disagreements are parked in one file where they
 * can be read side by side, and the visual flip that collapses them is its own
 * commit so it can be reverted on its own.
 *
 * VENDORED, mirroring `vendor/tabler`: a local file with a version query, no
 * CDN. Reps are on flaky cellular and a stylesheet that fails to load takes
 * every colour on the page with it.
 *
 * HOW A SURFACE PICKS ITS COLUMN: `data-surface` on <html>, static markup, no
 * JavaScript. The theme mechanisms are each surface's own and are NOT touched
 * here -- the phone, planner and panel stamp `data-theme` from a script before
 * first paint, and the pour page follows the OS because it is standalone and
 * has no toggle to remember (TASTING_SPEC section 12).
 *
 * THE PLANNER IS NOT DRIFT. Warm paper, a darker blue accent and its own
 * warn/danger/spill scale are deliberate -- it is a desk screen, not a phone in
 * a bar -- so it overrides rather than conforms, and says so below.
 *
 * ===========================================================================
 * THE DARK RULES (2026-08-27). Written down as RULES rather than as a second
 * palette, because a second palette is a second thing to keep equal and this
 * file exists because of what that costs.
 *
 *  1. HUE IS CONSTANT; ONLY LIGHTNESS FLIPS. This was already the rule for
 *     company chips -- `--co-l` goes .50 -> .80 and the hue never moves -- and
 *     it is generalised here. Every dark value below is derivable from its
 *     light one, which is why they can be checked rather than agreed.
 *  2. THE ACCENT LIGHTENS, ITS TINT DARKENS. #3a45b0 -> #8b93f0 and
 *     #e8e9fa -> #23244a. They swap ends, not places.
 *  3. ELEVATION IS SURFACE LIGHTNESS, NOT SHADOW. A card is lighter than the
 *     ground; it does not also cast a shadow. Shadows on dark read as grime.
 *  4. NEVER A PURE BLACK AND NEVER A COOL ONE. The ground is #171613, not
 *     #000 and not #0f1115. The warm cast carries across both themes; a cool
 *     dark beside a warm light reads as two products.
 *  5. TWO MUTES IN BOTH THEMES. One grey clears 4.5:1 on card AND ground for
 *     TEXT (`--ink3`); one lighter (or, in dark, darker) for rules and dots
 *     (`--mute-line`). One token cannot serve both -- see the split below.
 *  6. STATUS COLOURS KEEP THEIR MEANING. A theme changes lightness, never what
 *     a colour means. Red is late in both.
 *
 * ON THE HEXES BELOW, since they look arbitrary: every light pair clears 4.5:1
 * for text at 11px, INCLUDING on the ground rather than only on the card --
 * which is the check that is usually skipped, and the reason these are not
 * rounder numbers. The candidates that failed it are recorded so nobody
 * re-derives them: #77726a as the mute, #1d8f6b as the ok ink, #c0403f as the
 * hot ink. Do not tidy any of these without re-measuring both backgrounds.
 * ===========================================================================
 */

/* ---------------------------------------------------------------------------
 * LIGHT. One palette, every surface. The per-surface columns below hold only
 * what a surface genuinely has no equivalent of anywhere else.
 * ------------------------------------------------------------------------- */
:root{
  /* ---- type ---------------------------------------------------------------
   * IBM Plex Sans for text, IBM Plex Mono for every number that CHANGES: times,
   * day counts, days-late, licence numbers, money, pill counts, and the 11px
   * uppercase section labels. The admin panel is a screen made almost entirely
   * of numbers, and in a proportional face a column of them does not read as a
   * column -- 1 is narrow, 0 is wide, and the eye re-finds the decimal on every
   * row. See `.num` at the foot of this file.
   *
   * The system stack stays behind them: Plex ships as a Latin1 subset, so a
   * glyph outside that range falls through per-character rather than dragging
   * four more subsets down a cellular connection. */
  --font-sans:'IBM Plex Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  --font-mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  /* ---- THE TYPE SCALE (2026-08-28) --------------------------------------
   * SIX STEPS, and the reason there are six is the same reason there is one
   * palette file: a size typed per screen is a size that drifts. What shipped
   * before this was SEVENTEEN steps inside the 10-19px band --
   *   10 . 10.5 . 11 . 11.5 . 12 . 12.5 . 13 . 13.5 . 14 . 14.5 . 15 . 15.5
   *   . 16 . 16.5 . 17 . 18 . 19
   * -- where adjacent steps differ by ~4%, which is below the threshold at
   * which a reader perceives a difference at all.
   *
   * The cost was not ugliness. It was that SIZE COULD NOT EXPRESS IMPORTANCE,
   * so importance fell to COLOUR -- which is how six colour systems ended up
   * competing in one 390px column, and why the sentence the account screen
   * exists to deliver was set at the same 14px as a settings row six blocks
   * below it.
   *
   * Every step below is >= 18% from its neighbour, which is comfortably
   * perceptible. 12px is THE FLOOR; nothing readable goes under it.
   *
   *   --t-xs   12  section labels, pills, mono captions, tab-bar labels
   *   --t-s    14  body, row meta, list sub-lines, sheet rows
   *   --t-m    17  row titles, primary button labels, sheet titles
   *   --t-l    20  the one sentence a screen is about
   *   --t-xl   26  screen subject (an account's name)
   *   --t-xxl  34  a single dominant figure
   *
   * WEIGHTS STAY AT THREE: 400, 500, 600. Plex is vendored at exactly those
   * (plus mono 500/600); a fourth means another file down a cellular
   * connection. `700` in the old CSS now maps to `600` -- Plex 600 is already
   * heavy enough that the difference read as a rendering artefact, and there
   * was no 700 face to load in the first place.
   *
   * ICON SIZES ARE NOT TYPE. `font-size` on a `.ti` glyph is an icon size and
   * stays free (14/15/16/17/18/19/20/21/22/23/26 are all in use and all
   * correct). That carve-out is written into `lint-globals.mjs` as an explicit
   * exception rather than left as folklore -- without it the rule is unusable
   * and gets abandoned in a week. */
  --t-xs:12px;  --lh-xs:1.35;
  --t-s:14px;   --lh-s:1.45;
  --t-m:17px;   --lh-m:1.3;
  --t-l:20px;   --lh-l:1.3;
  --t-xl:26px;  --lh-xl:1.15;
  --t-xxl:34px; --lh-xxl:1.05;

  /* ---- ground and paper ---------------------------------------------------
   * Warm, not cool, and never a pure white below the card. Rule 4 in the
   * header: the warm cast is what carries across both themes. */
  --bg:#f5f4f1;
  --card:#ffffff;
  --line:#e6e3dd;
  /* The quieter rule -- an inner divider inside a card, where `--line` reads as
     the card's own edge repeated. */
  --line-soft:#efece7;

  /* ---- ink ----------------------------------------------------------------
   * Three weights of text and NOT A FOURTH. Every one clears 4.5:1 at 11px on
   * the CARD and on the GROUND -- see the header for the candidates that only
   * cleared it on the card, which is the check that usually gets skipped. */
  --ink:#1b1a19;
  /* Darkened 2026-08-28 (Buyers-tab handoff, "daylight legibility"): the two
     mutes and the hot ink each gained a few points of contrast for phones read
     in direct sun. Light column only -- the dark values already clear it. */
  --ink2:#57534b;
  /* SMALL TEXT: meta lines, section headings, timestamps, counts. Darkened
     from the old #8a9099 (3.0:1 on the ground -- it never passed) and it can
     be, because the decorative job moved to `--mute-line` below. */
  --ink3:#6b665e;
  /* NON-TEXT ONLY: dots, rules, dividers, separators. Nothing here is read, so
     nothing here owes a contrast ratio -- which is the whole reason the two
     were split. Darkening this to match `--ink3` would turn every divider into
     a border. */
  --mute-line:#c5c0b6;

  /* ---- accent -------------------------------------------------------------
   * Indigo rather than the old commodity blue. Rule 2: in dark the accent
   * LIGHTENS and its tint DARKENS -- they swap ends, not places. */
  --accent:#3a45b0;
  --accent-bg:#e8e9fa;
  --accent-line:#c3c7ee;

  /* ---- status. Rule 6: a theme changes lightness, never meaning. ----------
   * `--hot` is late / wrong / closed. `--warm` is attention, not alarm.
   * `--ok` is done. `--cool` is NEW -- see below, it is not a shade of ok.
   * Each is an INK with a tint behind it, and the ink clears 4.5:1 on its own
   * tint as well as on the card and the ground. */
  --hot:#a83431;
  --hot-bg:#fbe9e8;
  --hot-line:#eec2c0;
  --warm:#8a5d0c;
  --warm-bg:#f7eddb;
  --warm-line:#e8cf9a;
  --ok:#136b50;
  --ok-bg:#e2f2ec;
  --ok-line:#a9d8c7;

  /* COOL GETS ITS OWN TEAL (2026-08-27). `--cool-bg` and `--ok-bg` were the
     same hex -- two names for one colour, which is the glossary's rule broken
     in CSS. They are not the same idea: cool means NEW (never visited, first
     order, a fresh door) and ok means DONE. A door nobody has been to is not a
     finished one, and rendering them identically said it was. Merging was the
     other option and it was rejected for that reason. */
  --cool:#0d6470;
  --cool-bg:#ddeff1;
  --cool-line:#b6dde2;

  /* COLD IS NOT COOL, AND IT NEEDED REAL TOKENS (2026-08-28).
     `#4a90d9` was a bare hex in `app.js`'s warmth colour map with no `-bg` /
     `-line` behind it, unlike hot/warm/ok/cool -- so the accounts list could
     draw a cold DOT and nothing else. (That map has since gone: both the row
     edge and the filter chips take their colour from CSS.) A warmth filter that lights its chip in
     the warmth's own colour needs the full trio, and a 3.34:1 dot colour
     cannot become text: measured on card it is 3.34, on ground 3.04, and this
     file's rule is 4.5 on BOTH.
     Derived by rule 1 -- hue held at the dot's own 210.6, only lightness moved
     -- so the cold dot means the same thing it always did, just legibly.
     Measured: ink 6.46 on card, 5.88 on ground, 5.32 on its own tint.
     NOT MERGED INTO `--cool`. Cool means NEW in this product and cold means
     COLD; the file refused that merge once already for `--ok` and the same
     argument holds here. A door nobody has warmed is not a fresh one. */
  --cold:#2260a0;
  --cold-bg:#e2eaf3;
  --cold-line:#b7cce1;

  /* Spilled work -- a stop that did not fit the day (the planner's word). Its
     own hue because it is neither late nor fine. */
  --spill:#61439b;
  --spill-bg:#eee9f8;
  --spill-line:#cdc0ea;

  /* ---- fills and washes ---------------------------------------------------
   * Text sitting ON a filled block. White in light -- and in dark those fills
   * become LIGHT, so white on them is the unreadable pair. A literal cannot
   * flip with the theme; a token can. */
  --on-fill:#ffffff;
  /* Barely-there tints for a whole row rather than a chip. */
  --hot-wash:#fdfaf9;
  --warm-wash:#fdfbf6;
  --fill-wash:#faf9f6;
  /* Table striping, chips and the tab strip. */
  --zebra:#faf9f6;
  --chip-bg:#eae7e0;
  --tabs-bg:#eae7e1;
  --sub:#edeae4;
  /* The stronger rule, for a divider that has to separate rather than hint. */
  --line2:#d6d2c8;

  /* COMPANY CHIPS on merged timelines. The HUE is derived per company in JS
     (`companyHue`, identical in the phone and the panel, pinned by
     `company_colors.test.mjs`) and arrives inline as `--co-h`; the lightness
     and chroma live here so a company is the same colour on both surfaces.
     THIS IS THE PRECEDENT RULE 1 GENERALISES -- hue constant, lightness flips
     -- so it needs no change. oklch holds perceived lightness constant across
     the wheel, which is what lets 360 hues stay legible where hand-picked
     hexes wash out at yellow and go muddy at blue. */
  --co-l:.50; --co-c:.15;
  --co-l-bg:.95; --co-c-bg:.045;

  /* ---- DENSITY -----------------------------------------------------------
   * Comfortable is the default. The panel's Comfortable/Compact toggle stamps
   * `data-density` on <html> and moves these; anything that reads them gets
   * tighter, and anything that does not is unaffected. */
  --card-pad:14px;
  --row-pad:11px 0;
  --gap:10px;
}

/* The panel is roomier than the phone and always has been. */
:root[data-surface="admin"]{
  --card-pad:16px;
  --row-pad:12px 0;
}
:root[data-surface="admin"][data-density="compact"]{
  --card-pad:10px 12px;
  --row-pad:7px 0;
  --gap:8px;
}
/* One column of thumb-sized targets on a phone held at arm's length. */
:root[data-surface="pour"]{
  --card-pad:16px;
  --row-pad:12px 0;
}
:root[data-surface="planner"]{
  --card-pad:14px 16px;
}

/* ---------------------------------------------------------------------------
 * DARK. Derived from the light values by the six rules in the header -- hue
 * constant, lightness flipped -- rather than picked independently, which is
 * what makes it checkable instead of merely agreed.
 *
 * ONE BLOCK FOR EVERY SURFACE. Until this commit there were three, and they
 * disagreed on twelve tokens by two or three points of lightness apiece. Not
 * one of those differences was a decision; they were what happens when a
 * colour is typed in four files. The pour page's OS-driven block below is the
 * same values reached by a different mechanism, not a fourth opinion.
 * ------------------------------------------------------------------------- */
:root[data-theme='dark']{
  --bg:#171613;
  --card:#201f1b;
  --line:#302e29;
  --line-soft:#292722;

  --ink:#ece9e3;
  --ink2:#b0aaa0;
  --ink3:#8e887e;
  --mute-line:#4a463f;

  --accent:#8b93f0;
  --accent-bg:#23244a;
  --accent-line:#3b3d70;

  --hot:#f0837d;
  --hot-bg:#3a201d;
  --hot-line:#6f3634;
  --warm:#e2a544;
  --warm-bg:#33280f;
  --warm-line:#6e5620;
  --ok:#4bd0a0;
  --ok-bg:#12312a;
  --ok-line:#23604e;
  --cool:#57c8d2;
  --cool-bg:#102e33;
  --cool-line:#1f4d54;
  /* Hue held at 210.6, lightness flipped. 6.92 on card, 7.59 on ground,
     5.82 on its own tint. */
  --cold:#78ace3;
  --cold-bg:#1d2e3e;
  --cold-line:#385676;
  --spill:#b6a3e6;
  --spill-bg:#251f38;
  --spill-line:#4b3f74;

  /* Rule 3: elevation is surface lightness, so a filled block's foreground is
     the GROUND rather than white. */
  --on-fill:#171613;
  --hot-wash:#221a19;
  --warm-wash:#221e13;
  --fill-wash:#1b1a17;
  --zebra:#1c1b18;
  --chip-bg:#2b2924;
  --tabs-bg:#26241f;
  --sub:#232219;
  --line2:#423e37;

  /* Hue unchanged -- a company is the same colour in both themes and on every
     surface. Only the lightness flips: ink up, chip down toward the card. */
  --co-l:.80; --co-c:.13;
  --co-l-bg:.29; --co-c-bg:.055;
}

/* THE POUR PAGE FOLLOWS THE OS and has no toggle, because it is opened once by
   somebody with no account on a phone that may never come back -- there is
   nowhere to remember a preference and nobody to set one. Same values as the
   block above, reached by the only mechanism this page has. */
@media (prefers-color-scheme:dark){
  :root[data-surface="pour"]{
    --bg:#171613;
    --card:#201f1b;
    --line:#302e29;
    --line-soft:#292722;
    --ink:#ece9e3;
    --ink2:#b0aaa0;
    --ink3:#8e887e;
    --mute-line:#4a463f;
    --accent:#8b93f0;
    --accent-bg:#23244a;
    --hot:#f0837d;
    --hot-bg:#3a201d;
    --warm:#e2a544;
    --warm-bg:#33280f;
    --ok:#4bd0a0;
    --ok-bg:#12312a;
    --on-fill:#171613;
  }
}

/* ---------------------------------------------------------------------------
 * EVERY NUMBER THAT CHANGES.
 *
 * `tabular-nums` as well as the mono face: Plex Mono is already fixed-width,
 * but the token also covers a fallback face that is not, and a column that
 * only lines up once the webfont lands is a column that jumps on every load.
 *
 * ALSO THE 11px UPPERCASE SECTION LABELS, which are not numbers -- they are
 * the things numbers sit under, and setting the label in the same face is what
 * makes a stat tile read as one object rather than a caption beside a figure.
 * ------------------------------------------------------------------------- */
.num,
.sechead,
.hub-badge,
.pill,
[data-num]{
  font-family:var(--font-mono);
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
}
