/* Govably design tokens — the single source of truth for the clerk app's visual values.
 *
 * Why this file exists: app.js carried 124 distinct literal hex colors across 407
 * occurrences, #084734 alone appearing 57 times even though it IS clerky-900 in the
 * Tailwind config. styles.css carried 121 more, font sizes at half-pixel granularity,
 * 18 border radii, and z-index values up to 2147483647. There was nothing to reach for,
 * so every screen invented its own.
 *
 * Almost nothing here is new. The brand ramp is the clerky/brand palette from app.html's
 * tailwind.config; the ink ramp and --gv-paper are lifted verbatim from
 * notices/shared/styles.css so a later app/notices convergence is a rename rather than a
 * redesign. Only the scales that did not exist anywhere — space, radius, shadow, type,
 * z-index, motion — are authored here.
 *
 * Rules:
 *   - Add a token when a value is used in more than one place, or when it names a
 *     decision (what "danger" means) rather than a measurement.
 *   - Every text role below is asserted at WCAG AA 4.5:1 by
 *     tools/checks/check-design-tokens.js. The ramps are NOT — a ramp stop is a color,
 *     not a promise that it is readable.
 *   - Changing a --gv-brand-* value means changing the tailwind.config block in
 *     app.html to match, in the same commit. The check fails when they drift.
 *
 * Documented at /design/foundations.html.
 */

:root {
    /* ── Brand ramp ───────────────────────────────────────────────────────────
       Mirrors the `clerky` and `brand` scales in app.html's tailwind.config (which
       are byte-identical duplicates of each other, both in use). The 950 stop exists
       only here and in notices; the Tailwind config stops at 900. */
    --gv-brand-50:  #f5fbe6;
    --gv-brand-100: #dff2c5;
    --gv-brand-200: #cdedb3;
    --gv-brand-300: #cef17b;
    --gv-brand-400: #a4d655;
    --gv-brand-500: #7eba36;
    --gv-brand-600: #5a9326;
    --gv-brand-700: #3d6b1c;
    /* 800/900/950 were #1d4730, #084734 and #052a20 — hues 147°, 162° and 164°, against
       700's 95°. The ramp was a yellow-green for eight stops and a blue-green for three,
       spliced in the middle, so a board tile read as a different green from the step icons
       rather than a darker one (#386). These continue the ramp's own 83 → 87 → 91 → 95
       drift instead of starting a second family. */
    --gv-brand-800: #2b4e18;
    --gv-brand-900: #19350d;
    --gv-brand-950: #0e2108;

    /* ── Ink ramp ─────────────────────────────────────────────────────────────
       Warm neutrals, adopted verbatim from notices/shared/styles.css. Warmer than
       Tailwind's slate/gray, which is why app screens built from raw Tailwind grays
       read slightly cold beside the notices product. */
    --gv-ink-900: #0c1612;
    --gv-ink-800: #1c2825;
    --gv-ink-700: #344441;
    --gv-ink-600: #4f615d;
    --gv-ink-500: #6b7c78;
    --gv-ink-400: #98a6a2;
    --gv-ink-300: #c4cdc9;
    --gv-ink-200: #dde2df;
    --gv-ink-100: #ecefed;
    --gv-ink-50:  #f7f8f7;

    /* ── Surfaces ─────────────────────────────────────────────────────────── */
    --gv-surface:       #ffffff;    /* cards, modals, inputs — the reading surface */
    --gv-surface-sunk:  var(--gv-ink-50);
    --gv-paper:         #fafaf7;    /* the app background */
    --gv-paper-2:       #f5f4ed;
    /* One hairline. Named so a segmented control can pull a button onto its
       neighbour's edge — calc(-1 * this) — without hardcoding the width in two
       places that must agree. */
    --gv-border-width:  1px;
    --gv-border:        var(--gv-ink-200);
    --gv-border-strong: var(--gv-ink-300);
    --gv-scrim:         rgba(12, 22, 18, 0.5);  /* one modal scrim, replacing five */

    /* ── Text roles ───────────────────────────────────────────────────────────
       The only color tokens allowed to carry text, and every one is contrast-checked
       in CI. Note the ramp stops that are deliberately absent: --gv-ink-500 lands at
       4.39:1 on white and fails AA, and --gv-ink-400 at 2.53:1 is nowhere near. Those
       two are border, icon and disabled values only. */
    --gv-text:          var(--gv-ink-900);  /* 18.44:1 on --gv-surface */
    --gv-text-muted:    var(--gv-ink-600);  /*  6.56:1 */
    --gv-text-subtle:   #5f716d;            /*  5.16:1 — one stop darker than
                                                --gv-ink-500 precisely because that
                                                stop fails AA. */
    --gv-text-invert:   #ffffff;
    --gv-text-disabled: var(--gv-ink-400);  /* non-content only; never body copy */

    /* ── Semantic colors ──────────────────────────────────────────────────────
       The -fg stop is the text/icon color and is AA on both --gv-surface and its own
       -bg. These match the accents already chosen in notices/shared/styles.css. */
    --gv-success-fg:     #15803d;
    --gv-success-bg:     #f0fdf4;
    --gv-success-border: #bbf7d0;

    /* --gv-warning is the SOLID mid stop, the way --gv-gold sits beside --gv-gold-fg:
       a mark, not a label. It is the orange this app has always flagged with — the
       import flags and .agr-item.flagged both hardcode #f59e0b — so a rule that wants
       "the attention colour" as a stroke or an edge has a token to name instead of a
       hex to copy. 2.1:1 on white, so it is decoration only; when the warning has to
       carry words, --gv-warning-fg is the readable stop. */
    --gv-warning:        #f59e0b;
    --gv-warning-fg:     #b45309;
    --gv-warning-bg:     #fffbeb;
    --gv-warning-border: #fde68a;

    --gv-danger-fg:      #b91c1c;
    --gv-danger-bg:      #fef2f2;
    --gv-danger-border:  #fecaca;

    --gv-info-fg:        #075985;
    --gv-info-bg:        #f0f9ff;
    --gv-info-border:    #bae6fd;

    /* HOW FAR ALONG a meeting is — the three states the dashboard's step chain, the
       in-meeting tab strip and the audit timeline's lanes all report. One vocabulary,
       because it was written out four times in Tailwind literals and drifted: the
       in-progress glyph was amber-600 over an amber-500 bar, and not-started was
       gray-400 on two screens and gray-300 on the third.

       Done is --gv-brand-600, NOT the --gv-brand-400 a finished ROW carries down its
       left edge. They are the same statement and deliberately not the same value: 400
       is 1.70:1 on white, which a 4px edge can hold and a glyph cannot — WCAG 2.1
       1.4.11 asks 3:1 of a graphical object, and 600 (3.73:1) is the lightest stop on
       this ramp that clears it. Same hue family, a little darker, still legible to
       someone who cannot pick the green out of the grey.

       Each state carries its hover because the dashboard chain darkens every icon under
       the pointer and that shade is a decision like any other. The other two screens
       render the same classes and simply have nothing that hovers.

       --gv-step-none is 2.54:1 and is NOT held to 3:1, deliberately: "not started" is
       the absence of a state, it sits on a grey rail that carries the shape anyway, and
       darkening it would make a step nobody has reached yet more present on screen than
       one in progress. See check-design-tokens.js, which asserts the other two. */
    --gv-step-done:           var(--gv-brand-600);
    --gv-step-done-hover:     var(--gv-brand-700);
    --gv-step-progress:       #d97706;
    --gv-step-progress-hover: #b45309;
    --gv-step-none:           #9ca3af;
    --gv-step-none-hover:     #4b5563;

    /* Brand-tinted "neutral positive" pill — the shape most app statuses want. */
    --gv-brand-fg:       var(--gv-brand-900);
    --gv-brand-bg:       var(--gv-brand-50);
    --gv-brand-border:   var(--gv-brand-200);

    /* Undifferentiated / inactive pill. */
    --gv-neutral-fg:     var(--gv-ink-700);
    --gv-neutral-bg:     var(--gv-ink-100);
    --gv-neutral-border: var(--gv-ink-200);

    /* ── Gold ─────────────────────────────────────────────────────────────────
       The AI-nib accent (the #gov-ai-icon-style block in app.html). --gv-gold is
       decoration — an icon stroke on a light ground — and is not AA as text.
       --gv-gold-fg is the readable stop, already in use as `--am` in the mbtv and
       mbmv style blocks. */
    --gv-gold:          #d4a017;
    --gv-gold-fg:       #8a6d1a;
    --gv-gold-fg-hover: #755c16;
    --gv-gold-bg:       #fdf9ec;
    --gv-gold-border:   #ecdcae;

    /* ── AI ───────────────────────────────────────────────────────────────────
       An AI action is its own register: it costs a call and can take a minute, so
       "this spends AI" should be legible before the label is read.

       INDIGO, and this is the register's fourth hue — worth reading before changing
       it a fifth time, because it has now been round in a circle. It was filled indigo-600, moved to the nib's own gold so
       the icon and its button agreed, then to violet-700, and is now indigo-800.
       Gold went because it reads as brown at text weight and barely cleared AA at
       4.90:1. Violet cleared it easily but was the most SATURATED thing on a screen
       made of muted greens and greys — fine on one primary button, loud repeated
       down twelve rows. Indigo is the same separation from the registers either side
       of it (brand green for done, red for destructive) at a fraction of the
       vibration, and 9.93:1.

       Nothing fills any more (see .gv-btn), so these name a rule and a wash rather
       than a slab: -fg is the border and the label, -bg the hover wash beneath it.

       The nib keeps its brand-900 body — that mark is the product's, not the
       register's — and takes indigo ink, so the icon and the button it sits on say
       the same thing. -ink is measured against 3:1, the threshold for a graphical
       object, and clears it at 8.88:1 on the wash. */
    --gv-ai-fg:       #3730a3;
    --gv-ai-fg-hover: #312e81;
    --gv-ai-bg:       #eef2ff;
    --gv-ai-nib:      var(--gv-brand-900);
    --gv-ai-ink:      #3730a3;

    /* ── Space ────────────────────────────────────────────────────────────────
       A 4px grid. styles.css currently uses every odd value between 2 and 28. */
    --gv-space-1:  4px;
    --gv-space-2:  8px;
    --gv-space-3:  12px;
    --gv-space-4:  16px;
    --gv-space-5:  20px;
    --gv-space-6:  24px;
    --gv-space-7:  32px;
    --gv-space-8:  40px;
    --gv-space-9:  48px;
    --gv-space-10: 64px;

    /* ── Control sizes ────────────────────────────────────────────────────────
       Square icon-only controls — transport buttons, icon buttons. The 40px main
       size is the one a clerk hits repeatedly while scrubbing a three-hour
       recording; it is deliberately close to the 44px touch-target guidance rather
       than the 32px the two existing transports settled on independently. */
    --gv-control-3xs: 14px;     /* the checkbox tick. Below every target-size guideline
                                   there is, and deliberately so: a checkbox is sized to
                                   sit beside its text, and .gv-check-row is what turns the
                                   label into the target. A bare box without that wrapper is
                                   a 14px target and nothing hides that — the attendance
                                   roster is the one place in the app that pays it. */
    --gv-control-2xs: calc(var(--gv-control-xs) * 0.8);  /* 19.2px — see DESIGN-SYSTEM.md
                                   on target size before reaching for this one */
    --gv-control-xs:  1.5rem;   /* 24px — dense grids */
    --gv-control-sm: 28px;
    --gv-control-md: 34px;
    --gv-control-lg: 40px;

    /* ── Radius ───────────────────────────────────────────────────────────── */
    --gv-radius-sm:   6px;
    --gv-radius-md:   8px;   /* the existing --rf-radius; the app's default */
    --gv-radius-lg:   12px;
    --gv-radius-xl:   16px;
    --gv-radius-full: 9999px;

    /* ── Elevation ────────────────────────────────────────────────────────────
       Four steps, tinted with the ink hue rather than pure black so a shadow sits on
       the warm background without going grey. Replaces 20+ ad-hoc shadow strings. */
    --gv-shadow-sm: 0 1px 2px rgba(12, 22, 18, 0.06);
    --gv-shadow-md: 0 2px 8px rgba(12, 22, 18, 0.10);
    --gv-shadow-lg: 0 8px 24px rgba(12, 22, 18, 0.12);
    --gv-shadow-xl: 0 20px 48px rgba(12, 22, 18, 0.18);

    /* ── Type ─────────────────────────────────────────────────────────────────
       The clerk app has no UI font of its own — it inherits Tailwind's stack. That is
       recorded here rather than fixed, because changing it is a design decision, not a
       refactor. --gv-font-doc is the existing --rf-font-doc. */
    --gv-font-ui:   system-ui, -apple-system, "Segoe UI", sans-serif;
    --gv-font-doc:  "Source Serif 4", Georgia, serif;
    --gv-font-mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

    /* The floor, and it is meant to be hard to reach for. One use: the timestamp on a
       play control, where a column of thirty of them runs down a list beside the words
       they point at, and anything larger out-ranks the text. Pair it with
       --gv-weight-medium — DM Mono at 400 goes thin here.
       Not for prose, not for anything that has to be read rather than glanced at, and
       never for the only copy of a piece of information. These are fixed px, so a reader
       who enlarges their browser text gets nothing from it. */
    --gv-text-3xs:  10px;
    --gv-text-2xs:  11px;   /* dense metadata: table meta, pill text */
    --gv-text-xs:   12px;
    --gv-text-sm:   13px;   /* the app's most common size */
    --gv-text-base: 14px;   /* body copy */
    --gv-text-md:   16px;
    --gv-text-lg:   18px;
    --gv-text-xl:   22px;
    --gv-text-2xl:  28px;

    --gv-leading-none:  1;      /* controls whose height is set by padding, not text */
    --gv-leading-tight: 1.25;
    --gv-leading-snug:  1.4;
    --gv-leading-base:  1.55;
    --gv-leading-relaxed: 1.7;  /* quoted speech and settled language — read, not scanned */

    /* Uppercase runs need the extra room; nothing else in the system tracks out. */
    --gv-tracking-wide: 0.04em;

    --gv-weight-normal:   400;
    --gv-weight-medium:   500;
    --gv-weight-semibold: 600;
    --gv-weight-bold:     700;

    /* ── Layering ─────────────────────────────────────────────────────────────
       The app's 43 hand-rolled overlays currently pick from 50, 60, 80, 999, 9998,
       9999 and 10000, so which modal wins is an accident of who was written last.
       These are the only z-index values new code should use. */
    --gv-z-base:     1;
    --gv-z-dropdown: 1000;
    --gv-z-sticky:   1100;
    --gv-z-overlay:  1200;
    --gv-z-modal:    1300;
    --gv-z-toast:    1400;
    --gv-z-tooltip:  1500;

    /* ── Motion ───────────────────────────────────────────────────────────────
       Anything using these must also honour prefers-reduced-motion (AGENTS.md §7). */
    --gv-dur-fast: 120ms;
    --gv-dur-base: 160ms;
    --gv-dur-slow: 240ms;
    --gv-dur-spin: 700ms;   /* one turn of .gv-spinner */
    --gv-ease:     cubic-bezier(0.4, 0, 0.2, 1);

    /* ── Focus ────────────────────────────────────────────────────────────────
       One ring. The frontend has six :focus-visible rules in total today, all on the
       public transcript, using four different recipes between them. Drawn as an
       outline so it works on any background without a matching box-shadow. */
    /* The ring on a chosen row. Discussions drew this at rgba(8,71,52,.10) and Votes
       at .14 — the same idea, two alphas, because they were written a year apart.
       Distinct from --gv-focus-* on purpose: focus is where the keyboard is right
       now, selection is what the clerk decided. Both can be true at once.

       Softened from 3px/.12. That read well in a four-row specimen, but "a choice has
       been made" is the state MOST rows end up in on a real meeting — a placed agenda
       item, an assigned speaker, a recorded vote — and a halo on nearly every row is
       noise rather than emphasis. The state is still unmistakable: is-selected also
       carries a --gv-brand-700 border against the default --gv-ink-200. */
    --gv-ring-selected: 0 0 0 2px rgba(8, 71, 52, 0.07);

    /* The wash that runs across a choice at the moment it is committed. Brief, and
       left-to-right, so it reads as the answer landing rather than as a loading bar. */
    --gv-sweep-commit: linear-gradient(90deg, rgba(8, 71, 52, 0.16), rgba(8, 71, 52, 0.04) 55%, rgba(8, 71, 52, 0));

    --gv-focus-color:  var(--gv-brand-700);
    --gv-focus-width:  2px;
    --gv-focus-offset: 2px;
}
