/* ElectionLog design tokens.
 *
 * One vocabulary for every ElectionLog surface: the archive, this hub, and
 * the graphic maker inside it. It is loaded first by every page and defines
 * no rules — only values — so adding it to a page cannot change how anything
 * looks until that page points a property at it.
 *
 * WHY THIS EXISTS, measured across the three codebases before it was written:
 *
 *   - 16 colours are defined in more than one place. TWO of them agree on a
 *     name. --act / --accent, --paper / --bg, --rule / --line, --verify /
 *     --good, --seal / --danger are each one colour with two names.
 *   - #7D8A95 is --field in the archive (a form border) and --ink-faint in
 *     the hub (faint text). Same value, unrelated jobs. That is exactly why
 *     the primitives below are named for what a colour IS, and the semantic
 *     layer above them for what it is FOR: unify by value, not by name, or
 *     the next person "tidies" one of those two into the other.
 *   - The archive measures its bar's height into --navh at runtime. The hub
 *     measures the same bar into --navbar-h. Two implementations of one idea,
 *     in one organisation, neither aware of the other.
 *   - Between them the four stylesheets use 28, 20, 18 and 20 distinct
 *     literal spacing values, and 19, 12, 0 and 15 distinct literal font
 *     sizes, including 9.5px, 10.5px, 13.5px and 16.5px. That is not a scale,
 *     it is a continuum.
 *
 * HOW TO USE IT. Three layers, and you almost always want the middle one:
 *
 *   1. PRIMITIVES (--el-*). What a value IS. Never used directly in a rule.
 *   2. SEMANTIC. What it is FOR: --surface, --ink, --accent. This is what
 *      component CSS should name. Themes rebind this layer and nothing else.
 *   3. COMPONENT. --btn-h, --field-h, --navbar-h. One place a control's size
 *      is decided, so a link dressed as a button cannot quietly disagree with
 *      the button beside it.
 *
 * The scales are here to be adopted, not to be enforced retroactively.
 * Nothing was rounded to fit them when this file landed — a token file that
 * moves pixels on arrival is a redesign wearing a refactor's clothes. New
 * work picks the nearest step; old values get converted when their component
 * is next touched anyway.
 */

/* ========================================================================
   1. PRIMITIVES — what a value is
   ======================================================================== */

:root {
  /* ---- ink, from black to hairline -----------------------------------
     One ramp. The archive's --ink/--ink-2/--muted/--field/--rule/--rule-soft
     and the hub's --ink/--ink-soft/--ink-faint/--line/--line-soft are the
     same six values in two vocabularies; these are those six.

     The three lightest are structure, and they are darker than a designer's
     instinct: the archive's note records that at #D2DBE0 a card edge measured
     1.40:1 on white and a section rule 1.05:1, which is another way of saying
     it was not there. */
  --el-ink-900: #0E151C;   /* body text, borders, the focus ring */
  --el-ink-700: #46586A;   /* secondary prose            7.3:1 on white */
  --el-ink-600: #566470;   /* mono metadata              6.1:1 on white */
  --el-ink-400: #7D8A95;   /* form control borders       3.5:1 on white */
  --el-ink-300: #A4B4BE;   /* card edges, section rules  2.1:1 on white */
  --el-ink-200: #B7C4CC;   /* dividers inside a card     1.8:1 on white */

  /* ---- grounds -------------------------------------------------------- */
  --el-white:   #FFFFFF;   /* cards and panels */
  --el-paper:   #E7ECEF;   /* the page */
  --el-paper-2: #F0F2F4;   /* a panel on the page */
  --el-navy-900: #121A24;  /* the bar and other dark blocks */
  --el-navy-950: #0A0F14;  /* the bar, on dark */

  /* ---- the action colour. Buttons only, and never white text on it. ---- */
  --el-amber-500: #E9A81C;
  --el-amber-600: #C48F17; /* its hover */
  --el-amber-800: #7D5B10; /* when gold has to be text on a light ground */

  /* ---- the two meaning colours. There is no third. --------------------
     A fourth hue for a new state is the wrong move; separate it by fill,
     weight or shape. */
  --el-red-600: #A81D33;   /* serious, and errors */
  --el-red-050: #FCF2F4;
  --el-green-700: #296B60; /* confirmed by a moderator */
  --el-green-050: #EAF1EF;

  --el-grey-500: #999999;  /* the wordmark's own grey */

  /* ---- dark. Derived, not brand: the archive is light only, so these are
     the hub's own, kept here so the two copies of the dark theme below
     reference one set of values instead of repeating twenty hexes each. */
  --el-dk-bg: #0E151C;
  --el-dk-surface: #18212B;
  --el-dk-surface-2: #1F2A35;
  --el-dk-line: #35454F;
  --el-dk-line-soft: #2A3843;
  --el-dk-ink: #E7ECEF;
  --el-dk-ink-soft: #AFBDC7;
  --el-dk-red: #E2808F;
  --el-dk-red-bg: #2A1920;
  --el-dk-green: #5FAE9F;
  --el-dk-amber-text: #D6AB63;

  /* ---- type -----------------------------------------------------------
     Two families do different jobs and one is a real disagreement between
     properties, kept rather than papered over: the archive sets body text in
     Public Sans and display in Archivo; the team tools use Archivo for both,
     at Casey's direction. The semantic --font-body below is where each
     property says which it means, so the divergence is one line, not a fork. */
  --el-font-sans: 'Public Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --el-font-struct: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --el-font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;
  /* The canvas faces. FIXED — every finished campaign graphic was rendered
     with these exact files, and a substitution silently stops new graphics
     matching the ones already made. Not for chrome, ever. */
  --el-font-canvas-display: 'ElectionLog Display', Impact, 'Arial Black', sans-serif;
  --el-font-canvas-mono: 'ElectionLog Mono', ui-monospace, monospace;

  /* ---- type scale ------------------------------------------------------
     A ladder, so a size is a choice from a list rather than a number someone
     typed. The half-pixel sizes in the existing files are what its absence
     looks like. */
  --el-text-2xs: 10px;
  --el-text-xs:  11px;
  --el-text-sm:  12px;
  --el-text-md:  14px;
  --el-text-base:16px;
  --el-text-lg:  18px;
  --el-text-xl:  20px;
  --el-text-2xl: 26px;

  /* ---- space ----------------------------------------------------------
     Even numbers, doubling at the top. Every gutter, gap and pad picks a
     step. */
  --el-space-1:  2px;
  --el-space-2:  4px;
  --el-space-3:  6px;
  --el-space-4:  8px;
  --el-space-5:  10px;
  --el-space-6:  12px;
  --el-space-7:  14px;
  --el-space-8:  16px;
  --el-space-9:  20px;
  --el-space-10: 24px;
  --el-space-11: 32px;
  --el-space-12: 40px;

  /* ---- shape ----------------------------------------------------------- */
  --el-radius-sm: 5px;
  --el-radius: 10px;
  --el-radius-pill: 999px;
  --el-border-w: 2px;      /* the drawn edge: cards, buttons, inputs */
  --el-hairline: 1px;      /* a divider, which is not an edge */
}

/* ========================================================================
   2. SEMANTIC — what a value is for.  Component CSS names these.
   ======================================================================== */

:root {
  --bg: var(--el-paper);
  --surface: var(--el-white);
  --surface-2: var(--el-paper-2);
  --line: var(--el-ink-300);
  --line-soft: var(--el-ink-200);
  --ink: var(--el-ink-900);
  --ink-soft: var(--el-ink-700);
  --ink-faint: var(--el-ink-400);
  --accent: var(--el-amber-500);
  --accent-dk: var(--el-amber-600);
  --accent-ink: var(--el-ink-900);   /* dark ink on amber, never white */
  --danger: var(--el-red-600);
  --danger-bg: var(--el-red-050);
  --good: var(--el-green-700);
  --warn: var(--el-amber-800);
  --nav: var(--el-navy-900);
  --mark-grey: var(--el-grey-500);

  /* This property's body face. The one line that differs between the archive
     and the team tools; see the note on --el-font-sans. */
  --font-body: var(--el-font-struct);
  --font-struct: var(--el-font-struct);
  --font-mono: var(--el-font-mono);

  --radius: var(--el-radius);
  --radius-sm: var(--el-radius-sm);
  --bw: var(--el-border-w);
  --gutter: var(--el-space-8);
  --shadow: 4px 4px 0 var(--ink);
  --shadow-sm: 3px 3px 0 var(--ink);
}

/* Dark, twice, because one of the two conditions is a media query and a media
   query cannot be part of a selector. Only the BINDINGS repeat; the values
   live once, above.
 *
 * Both are gated on the page not declaring itself a fixed-dark surface. That
 * is not tidiness — it is load-bearing. `:root:not(...)` is two selectors, so
 * it outranks a plain `:root`, and a themed block here therefore beat the
 * graphic maker's own `:root` values even though its stylesheet loads later:
 * the maker's `--line` silently became the hub's dark rule colour whenever
 * the reader's OS was in dark mode. A page whose surface is fixed does not
 * take a theme, and now says so on its <html> element. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-surface="fixed-dark"]) {
    --bg: var(--el-dk-bg);
    --surface: var(--el-dk-surface);
    --surface-2: var(--el-dk-surface-2);
    --line: var(--el-dk-line);
    --line-soft: var(--el-dk-line-soft);
    --ink: var(--el-dk-ink);
    --ink-soft: var(--el-dk-ink-soft);
    --danger: var(--el-dk-red);
    --danger-bg: var(--el-dk-red-bg);
    --good: var(--el-dk-green);
    --warn: var(--el-dk-amber-text);
    --nav: var(--el-navy-950);
    --shadow: 4px 4px 0 #000000;
    --shadow-sm: 3px 3px 0 #000000;
  }
}
:root[data-theme="dark"]:not([data-surface="fixed-dark"]) {
  --bg: var(--el-dk-bg);
  --surface: var(--el-dk-surface);
  --surface-2: var(--el-dk-surface-2);
  --line: var(--el-dk-line);
  --line-soft: var(--el-dk-line-soft);
  --ink: var(--el-dk-ink);
  --ink-soft: var(--el-dk-ink-soft);
  --danger: var(--el-dk-red);
  --danger-bg: var(--el-dk-red-bg);
  --good: var(--el-dk-green);
  --warn: var(--el-dk-amber-text);
  --nav: var(--el-navy-950);
  --shadow: 4px 4px 0 #000000;
  --shadow-sm: 3px 3px 0 #000000;
}

/* A WORKSPACE IS DARK IN BOTH THEMES.
 *
 * The graphic maker is the case: every campaign graphic is composed on
 * near-black or on the gold, and previewing one against paper misrepresents
 * the work. Such a page puts data-surface="fixed-dark" on its <html>, which
 * turns off the two theme blocks above and leaves it to bind the semantic
 * layer to whatever its workspace needs.
 *
 * So the maker is not an exception to this system. It is a page that has
 * declared its surface, and its own stylesheet binds the semantic names from
 * there. Light and dark are for surfaces that follow the reader; a workspace
 * follows the work. */

/* ========================================================================
   3. COMPONENT — one place a control's size is decided
   ======================================================================== */

/* These are DESCRIPTIVE, not yet prescriptive: they record what the controls
 * measure today so that adopting them changes nothing, and the rules take
 * them over in a change that is about that. Written the other way round — a
 * tidy number the controls do not actually obey — a token file is worse than
 * none, because it reads like a decision and is a guess.
 *
 * What measuring found, and what adoption has to reconcile. Every one of
 * these is a line-height accident rather than a decision, because every
 * declared size is a `min-height` that the content already exceeds:
 *
 *     button            min-height 42px   renders 45.3px
 *     button.small      min-height 34px   renders 35.3px
 *     .pill.small       min-height 34px   renders 34.0px  (1px border, not 2)
 *     .help-dot         height     35px   renders 35.0px
 *     input             min-height 42px   renders 48.8px
 *     select            min-height 42px   renders 43.0px
 *
 * A text field and the select under it on the Settings page are 5.8px apart
 * and nothing in the stylesheet says so. That is the drift this layer exists
 * to end, and ending it moves pixels, which is why it is its own change. */
:root {
  --btn-h: 45px;
  --btn-h-sm: 35px;
  --btn-pad-x: var(--el-space-7);
  --btn-pad-x-sm: var(--el-space-5);
  --btn-radius: var(--radius);
  --btn-text: 0.94rem;
  --btn-text-sm: 0.86rem;

  --field-h: 45px;
  --field-pad-x: var(--el-space-6);
  --field-radius: var(--radius);

  /* Published at runtime by nav.js from the bar's measured height — it moves
     with the safe-area inset on a notched phone, so it cannot be a constant.
     This is the value for the frame before the script runs. --navh is the
     archive's name for the same measurement; both are here so the two
     properties converge on one without either having to rename first. */
  --navbar-h: 54px;
  --navh: var(--navbar-h);
}

/* ========================================================================
   ARCHIVE COMPATIBILITY
   The archive's 8,392-line index.html names these, and renaming them there
   would be a sweep with nothing to show for it. Aliases instead, so adopting
   this file over there is one <link> and no edits.
   ======================================================================== */

:root {
  --paper: var(--bg);
  --card: var(--surface);
  --ink-2: var(--ink-soft);
  --muted: var(--el-ink-600);
  --field: var(--el-ink-400);
  --rule: var(--line);
  --rule-soft: var(--line-soft);
  --act: var(--accent);
  --act-dk: var(--accent-dk);
  --act-fg: var(--accent-ink);
  --gold-deep: var(--el-amber-800);
  --seal: var(--danger);
  --seal-bg: var(--danger-bg);
  --verify: var(--good);
  --verify-bg: var(--el-green-050);
  --focus: var(--ink);
  --sans: var(--font-body);
  --cond: var(--font-struct);
  --mono: var(--font-mono);
}
