/* =========================================================================
   Design tokens — the single place colour, type and spacing are decided.
   Taken from the interface mock so the login screen and the shell are
   recognisably the same product. The settled design will replace the values
   here; nothing outside this file should name a colour.

   ONE THEME — dark (Adam's decision 1, 2026-09-20; task 2 of
   `tasks/todo.md`). The light palette and the `[data-theme="dark"]` block
   that overrode it are gone: `:root` below carries what the dark block
   carried, value for value, so that task changed which palette is live and
   not what any colour is. TASK 3 then replaced the values with Appendix A
   of `docs/audits/craft/00-design-system.md` — see the palette block
   below, which carries the measured ratios.

   `theme.js` still sets `data-theme="dark"` on <html> before first paint.
   Nothing in any stylesheet selects on it any more; it is kept because it
   costs one line and leaves a second theme re-addable, and because the same
   script owns the `theme-color` meta iOS paints behind the status bar.

   WHAT THIS FILE HOLDS, AND WHAT IT DOES NOT. Tokens, the box-sizing and
   element resets, and the one global `:focus-visible` ring. It used to hold
   `.lab`, `.btn`, `.p` and `.mark` as well, for want of anywhere better;
   task 5 moved them to `components.css`, which loads immediately after this
   file on both pages. A component is not a token — the brief's hard
   constraint is that colour is DECIDED here, not that everything shared
   lives here. Do not add a class back to this file.
   ========================================================================= */

:root {
  /* Dark, so the browser's own scrollbars, form controls and autofill are
     dark too. Without it the app runs down the side of a white scrollbar. */
  color-scheme: dark;

  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Mono", "Roboto Mono", Menlo, Consolas, monospace;

  /* =====================================================================
     THE PALETTE — Appendix A of `docs/audits/craft/00-design-system.md`,
     task 3 of `tasks/todo.md`. Every ratio quoted below was computed with
     the WCAG relative-luminance formula against the values in this block,
     not carried over from the report.

     This task changed VALUES and nothing else: no rule was added or
     removed, and the only new declarations are the three the appendix
     names as part of the contract (`--edge-acc`, `--pos`, `--mute`).
     Structure is task 10's; type and spacing are 11 and 12's.
     ===================================================================== */

  /* --- A.1 Surfaces: five levels, each a visible step -------------------
     Adjacent contrast 1.088 / 1.100 / 1.148 / 1.172, ground to top
     1.611:1. Today's four levels spanned 1.16:1 IN TOTAL, which on any
     real monitor is one colour — which is why the panels did not sit on
     the page, and why a graph-paper texture and cut corner brackets were
     added to fake the depth they were missing. TASK 10 took both off — the
     `<body>` texture and its `--grid` / `--grid-size` tokens, and the 9px
     corner brackets on `.p` — in the same commit that gave `.p` the ladder,
     a real padding and a 10px radius, because removing the decoration first
     would have left every panel with nothing at all dividing it from the
     page. Decision 2 (2026-09-20) bans both outright; do not paint a
     texture on a surface again. */
  --bg: #0a0c0f;
  --surface-1: #13171c;
  --surface-2: #1b2028;
  --surface-3: #252b34;
  --surface-4: #2f3642;
  /* `--panel`, `--panel-2` and `--panel-3` stood here as aliases of levels
     1, 2 and 3, so that task 3 could change what the colours WERE without
     twelve stylesheets changing in the same commit. Task 10 is the commit
     where structure changes, so it spent that bridge: all 66 reads across
     the ten tab stylesheets now name the ladder step they mean, and the
     three aliases are gone. One ladder, one set of names for it. Several
     comments still SAY `--panel` where they are recounting what a rule used
     to do; that is history, and it is accurate. */

  /* --- A.2 Text: three levels, all passing AA where they are used ------
     On `--surface-1` / `-2` / `-3`: `--text` 15.44 / 14.04 / 12.23,
     `--text-2` 8.96 / 8.14 / 7.09, `--text-3` 5.92 / 5.38 / 4.69.

     `--text-3` is the colour of the smallest type in the app and measured
     3.08:1 — it failed AA — so this is a legibility fix rather than a
     taste one. And the greens come out of the whole ramp deliberately:
     every level of ink was tinted green (`#e2f3ea`, `#7e9c91`,
     `#4e6560`), which is exactly what stopped the one accent reading as
     an accent. Ink goes neutral-cool; green is reserved. */
  --text: #eaeef3;
  --text-2: #aeb8c4;
  --text-3: #8a95a3;

  /* --- A.3 Borders: white-alpha, so one value works over every surface --
     Today's `--edge` was green, which is why every panel edge in the app
     glowed faintly — the second reason the accent did not read as one.

     Measured over `--surface-1` / `-2`: `--edge-soft` 1.20 / 1.23,
     `--edge` 1.46 / 1.50, `--edge-2` 1.88 / 1.91.

     `--edge-2` carries the row rules on the Labour grid and the
     separators in all four Settings tables, and it has a history: it was
     referenced and declared nowhere until commit 8236855, and the first
     attempt at defining it landed at 1.18:1 and still drew nothing a
     reader notices. 0.20 white clears 1.6:1 on both surfaces those tables
     actually sit on with room to spare, so it did not have to be raised —
     but it is the one hairline whose value is answerable to a number
     rather than to taste. `test/layout/craft-repairs.test.ts` measures
     it. */
  --edge-soft: rgba(255, 255, 255, 0.07);
  --edge: rgba(255, 255, 255, 0.13);
  --edge-2: rgba(255, 255, 255, 0.2);
  /* The boundary of a control you have to FIND before you can use it — a tick
     box, not a table rule. WCAG 1.4.11 asks 3:1 of any control's own edge, and
     the divider above is 1.91:1 against a control's fill and 2.10:1 against the
     panel behind it, which is a legible rule and an illegible box. 0.34 alpha
     measures 3.09:1 and 3.40:1, clearing it on both grounds. It is its own
     token because the two are different jobs: making every divider this strong
     would turn a quiet panel into a wireframe. */
  --edge-ctl: rgba(255, 255, 255, 0.34);
  /* The accent hairline: the one border allowed to carry the accent, so
     that a green edge means something again. 2.74:1 over `--surface-1`.
     Consumed by nothing until the component layer. */
  --edge-acc: rgba(46, 229, 152, 0.4);

  /* --- A.4 The one neon accent, its glow and its ring ------------------
     `--acc` measures 10.95 / 9.96 / 8.67 on surfaces 1 / 2 / 3. The glow
     and the ambient soft glow both come DOWN in strength (0.45 -> 0.30,
     0.14 -> 0.10 and 22px -> 20px): with a surface ladder that separates
     on its own, the bloom that was compensating for a flat one only
     smears the mark it is behind. */
  --acc: #2ee599;
  --acc-2: #1fb97b;
  --acc-dim: rgba(46, 229, 152, 0.1);
  --acc-dim2: rgba(46, 229, 152, 0.2);
  --glow: 0 0 12px rgba(46, 229, 152, 0.3);
  --glow-soft: 0 0 20px rgba(46, 229, 152, 0.1);
  /* Ink on the accent fill. The `#fff` literal `.btn.pri` used to carry
     measures 1.67:1 on the accent, which is why the dark theme had to
     override the primary button into a tinted outline rather than a
     filled button at all. This is 11.51:1 on the new accent, so there is
     one definition and it is a real fill. */
  --on-acc: #04140d;
  /* The focus ring as a box-shadow, so it follows `border-radius` instead
     of orbiting the element. The accent at 55%. Consumed in task 6.

     `--ring-inset` is the same ring drawn inwards, and it exists because two
     of the five controls sit INSIDE something that would clip an outward one:
     a `.seg` option lives in a 2px-padded track, and a `<summary>` is the full
     width of the panel it opens. Appendix D says "inset" for exactly those two.
     It is a second declaration rather than a second colour — change one and
     change the other. */
  --ring: 0 0 0 2px rgba(46, 229, 152, 0.55);
  --ring-inset: inset 0 0 0 2px rgba(46, 229, 152, 0.55);
  /* The same ring held off the control by 2px of the page's own ground, for a
     control whose FILL is already the accent — `.btn.pri`, and the switch's
     `on` track when task 9 builds it. Measured on the login screen: the plain
     ring on a green button is green on green and reads as a soft bloom rather
     than as focus; the gap is what makes it a ring again. Same colour, same
     2px, one gap. */
  --ring-gap: 0 0 0 2px var(--bg), 0 0 0 4px rgba(46, 229, 152, 0.55);

  /* --- A.4 The semantic set: five meanings, and this is the contract ---
     Contrast on `--surface-1` / `-2` / `-3` / `-4`:
       --acc  10.95 / 9.96 / 8.67 / 7.40
       --am    9.98 / 9.07 / 7.90 / 6.74
       --fall  9.31 / 8.46 / 7.37 / 6.29
       --mg    5.60 / 5.09 / 4.43 / 3.78

     One caution that is a design rule, not a note: `--mg` is 4.43 on
     `--surface-3` and 3.78 on `--surface-4`. Red TEXT belongs on surface
     1 or 2, or on `--mg-dim`; on a raised surface it has to be a border
     or a dot rather than a word. */
  --pos: var(--acc);
  /* A fall, or a figure below zero — Adam's decision 3, and the one
     behavioural colour change in this task. A night that lost money was
     drawn magenta in five rules; a losing Monday is ordinary in this
     business (`dashboard.css` says so in its own comment), so it is a
     FACT, not a decision waiting, and it gets its own cool colour. That
     is what leaves amber and red meaning only "you must act", which is
     the standing rule `test/layout/alarm-colours.test.ts` enforces.
     `--cy` is now the alias rather than the other way round: the Calendar
     delivery kind and the low-confidence chip are the same hue, and one
     value keeps them from drifting apart. */
  --fall: #5ac8e8;
  --cy: var(--fall);
  --cy-dim: rgba(90, 200, 232, 0.12);
  /* A decision is waiting, soft. Never a trend, never a status. */
  --am: #ffb224;
  --am-dim: rgba(255, 178, 36, 0.12);
  /* A decision is waiting, hard — a refusal, a blocker. */
  --mg: #ff4d6d;
  --mg-dim: rgba(255, 77, 109, 0.12);
  /* Nothing recorded. Never a zero. */
  --mute: var(--text-3);

  /* The backdrop behind an overlay, a phone sheet or a pushed page. */
  --scrim: rgba(0, 0, 0, 0.66);


  /* Corner radius, named by one rule (`.setfield`, settings.css) and declared
     nowhere, so that declaration was invalid. Zero is what the app draws
     today: every other field and button is square, so `.setfield` matches
     `.ein` and `.cin` beside it. It is now an alias of `--r-0` below, which
     is the same zero — the owner's ruling puts data tables and this field's
     neighbours at square, and moving one field to 6px here would be the
     redesign arriving in a defect fix, one input early. */
  --rad: var(--r-0);

  /* =====================================================================
     THE CRAFT RE-SKIN'S SCALES — task 1 of `tasks/todo.md`, spec in
     `docs/audits/craft/00-design-system.md` appendices A and B.

     Every token below this line is NEW and, at this point, consumed by
     NOTHING. Task 1 is deliberately additive: it lands the vocabulary so
     that tasks 3 and 10-13 are each a small diff against names that already
     exist, rather than twelve stylesheets all changing in one commit.

     Everything here is colour-independent — a spacing step, a radius, a
     duration, a weight. The *colour* roles task 1 added (`--surface-4`,
     `--on-acc`, `--ring`, `--fall`) sit with their families in the palette
     block above, and task 3 gave them Appendix A's values.

     NAMING — one deliberate deviation from the report, so the next reader
     does not think it was ignored. Appendix B.2 names the type tokens
     `--t-micro`, `--t-md`, `--t-hero`; Appendix B.4 names the durations
     `--t-tap`, `--t-hover`, `--t-layer`. Two unrelated families sharing one
     `--t-*` namespace is a trap. So:
       - durations keep `--t-*`, matching the phone's existing `--ph-t-*`
       - type splits into `--fs-*` (size), `--fw-*` (weight), `--ls-*`
         (tracking)
     Only the prefix moved; every value is the report's.
     ===================================================================== */

  /* --- Spacing: 8 steps on a 4px base (Appendix B.1) ------------------
     TASK 12 is where these stopped being decoration. Before it there were
     135 distinct padding values and 32 distinct gap values across the
     thirteen stylesheets, 95 of the paddings used exactly once — including
     `10px 10px 14px 26px`, `6px 18px 6px 37px` and `2px 16px 14px 29px`.
     Like things did not line up, and the eye reads that as carelessness
     even when it cannot name it.

     Justification, each: 4 is the smallest gap the eye reads as intentional
     at this type size; 8 is the workhorse; 12 separates related lines; 16 is
     the panel's own padding and the page gutter; 24 separates sections
     within a panel; 32 separates panels; 48 and 64 are page-level
     breathing. 2 is a segmented control's inner gutter and a hairline
     inset, and nothing else.

     Nothing outside this scale. An odd number in a stylesheet is now either
     a bug or a measurement that is answerable to something else (an icon's
     own width, a sticky column's offset, a safe-area inset) and says so in
     a comment. */
  --s-0: 2px;
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;
  --s-7: 48px;
  --s-8: 64px;

  /* `--gap` and `--pad` are the two spacing names that predate the scale.
     `--pad` was declared and used ZERO times anywhere in the codebase;
     `--gap` was 18px — off-grid — and used in 13 of the ~130 places it
     could be. Both are now the scale's own 16, and both are used. Either
     the tokens are the rule or they are decoration.

     They stay as names rather than being spent for `--s-4` everywhere,
     because they carry a meaning the step does not: `--gap` is the air
     between two panels on a page and `--pad` is a panel's own inner
     padding. If the page ever wants 24 between panels, that is one edit
     here rather than a sweep. */
  --gap: var(--s-4);
  --pad: var(--s-4);

  /* --- The page grid (Finding N3) --------------------------------------
     There was no grid: `.page` was a single flex column at `max-width:
     1180px` and every tab then invented its own `grid-template-columns` —
     `upload.css`'s `.grid3` at `repeat(3, minmax(0, 1fr))` with a 22px gap,
     `dashboard.css` and `calendar.css` each with their own. 1180 / 12 is
     not an integer; 1200 is, so a two-across panel on one tab and a
     three-across on another land on the same gutters. `.page` declares the
     12 columns once (`app.css`) and a tab spans them.

     `--gutter` is the scale's 16 and is the same number as `--gap`, on
     purpose: the horizontal air between two panels side by side and the
     vertical air between two panels stacked are one measurement, or the
     page is not on a grid at all. */
  --page-max: 1200px;
  --gutter: var(--s-4);

  /* --- Type primitives (Appendix B.2) ---------------------------------
     These are raw sizes, weights and tracking ONLY. The nine COMPOSITE
     roles the report names — a section heading, a column head, a sub-line,
     body, a panel title, the three figure sizes and the hero — each also
     carry a face, a transform and (for the figures) `tabular-nums`, so each
     is a utility CLASS, not a token. TASK 11 BUILT ALL NINE, in
     `components.css` under "THE TYPE ROLES" — `.ty-sec`, `.lab`, `.ty-xs`,
     `.ty-sm`, `.ty-md`, `.ty-lg`, `.ty-fig`, `.ty-fig-lg` and `.ty-hero` — and
     that block carries the reasoning, including which five of the nine are
     allowed the monospace face and why `tabular-nums` is declared exactly once.
     Do not re-derive a role here or in a tab stylesheet: a role is a class, a
     primitive is a token, and a tab that cannot take the class names these
     tokens rather than a pixel. */
  --fs-micro: 10px;
  --fs-xs: 11px;
  --fs-sm: 12px;
  --fs-md: 13px;
  --fs-lg: 15px;
  --fs-fig: 13px;
  --fs-fig-lg: 20px;
  --fs-hero: 32px;

  --fw-body: 400;
  --fw-mid: 500;
  --fw-bold: 620;

  --ls-micro: 0.14em;
  --ls-tight: -0.01em;
  --ls-hero: -0.02em;

  /* --- Radius: Adam's decision 4, which SUPERSEDES Appendix B.3 --------
     The report proposed 4px controls / 6px panels / 10px overlays; it was
     written before the ruling of 2026-09-20. The ruling is what is below:
     data tables square, controls 6px, panels and overlays and phone sheets
     10px, dots and the switch fully round. */
  --r-0: 0;
  --r-ctl: 6px;
  --r-panel: 10px;
  --r-full: 999px;

  /* --- Motion: one curve, three durations (Appendix B.4) ---------------
     A fast-out, settle-in curve — the same family the phone already used.
     `phone.css` now aliases `--ph-ease` and the three `--ph-t-*` to these, so
     the product has ONE curve and three durations rather than a desktop with
     no named curve at all beside a phone with its own system.

     Every transition in the app names a property list, one of these three
     durations and `--ease`. A bare `transition: 0.14s` animates every
     animatable property there is — `width`, `border-color`, `visibility` —
     which is how a hover ends up feeling mushy and, in this codebase, how a
     `.btn` fading `visibility` once refused focus in the phone's account
     sheet. There are none left; keep it that way.

     Which duration is which: `--t-tap` is a control answering a press where
     it stands, `--t-hover` a hover or a state fading in, `--t-layer` a whole
     layer arriving over the app. The reduced-motion block below zeroes all
     three at once, which is what makes naming them the rule rather than a
     preference. */
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --t-tap: 90ms;
  --t-hover: 140ms;
  --t-layer: 220ms;

  /* --- Elevation: 4 steps (Appendix B.5) -------------------------------
     Tuned for the dark ground, and declared on `:root` rather than per
     theme because there is now only the one theme. The rule
     they encode: on a dark UI elevation is carried by SURFACE LEVEL first
     and shadow second — a panel rises by moving up the ladder, not by
     gaining a shadow — so only `--e-2` and `--e-3`, things that genuinely
     float over content, use a shadow at all. */
  --e-0: none;
  --e-1: 0 1px 2px rgba(0, 0, 0, 0.45);
  --e-2: 0 4px 14px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05);
  --e-3: 0 16px 48px rgba(0, 0, 0, 0.62), 0 0 0 1px rgba(255, 255, 255, 0.07);
}

/*
 * Reduced motion, for the whole product, in one block — and the reason it can
 * be one block is the rule above it: every transition in the app names one of
 * the three duration tokens, so zeroing the tokens reaches all of them at
 * once. No stylesheet has to list its own selectors, and a transition added
 * later inherits this by naming a token, which is the only way it is allowed
 * to be written anyway. `phone.css` aliases `--ph-t-*` to these, so the phone
 * is reached through the same three values.
 *
 * 1ms rather than 0s: the transition still ends, so a `transitionend`
 * listener still fires and nothing waits for ever.
 *
 * WHAT THIS DOES NOT DO, and must not. It does not turn feedback off. A
 * colour or a background that changes under the pointer still changes — it
 * simply arrives at once instead of fading in, which is what the phone's tick
 * box has always done deliberately. Anything whose MOVEMENT was carrying the
 * message on its own has to say that message another way, and those live
 * where the movement does: `components.css`'s busy spinner steps instead of
 * spinning, and `phone.css`'s last block holds a ticked row in place rather
 * than blanking it. Zeroing a duration is not by itself a complete answer.
 *
 * It is declared here, immediately under the tokens, because that is where a
 * reader looks for what a token can be; no later stylesheet re-declares these
 * three, so source order never comes into it. That is the opposite of
 * `phone.css`'s own block, which beats rules by naming their selectors and
 * therefore has to stay last in that file.
 */
@media (prefers-reduced-motion: reduce) {
  :root {
    --t-tap: 1ms;
    --t-hover: 1ms;
    --t-layer: 1ms;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  /* Body. 13.5px was an odd half-pixel that renders differently by zoom level
     (Finding T1); 13px is the scale's `--fs-md` and the `.ty-md` role. */
  font-size: var(--fs-md);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

button,
input {
  font: inherit;
  color: inherit;
}

h1,
h2,
h3,
p {
  margin: 0;
}

:focus-visible {
  outline: 2px solid var(--acc);
  outline-offset: 2px;
}
