/* Design tokens.

   These are the source for the APP's colour, space and radius. Three places deliberately do
   NOT read them and carry literals instead, because they must render where this file does not
   exist: invoice.css / invoice_print.css (Pdf::Renderer inlines only those two, so a var()
   there resolves on screen and falls back on paper), layouts/mailer.html.erb (an email has no
   stylesheet), and the five public/*.html error pages (they render with the app down). Each
   says so at its own top. Changing a value here means changing it in those three by hand.

   --header-h is read by the header's min-height. Custom properties rather than Sass variables
   because the values are read at runtime, not compiled away. */
:root {
  color-scheme: light;

  /* Surfaces -- the prototype's warm paper. Direction D, 2026-08-26. */
  --c-paper: #f4f1ea;
  --c-surface: #fbfaf6;
  --c-surface-2: #ece7db;   /* read-only values, recessed rows */

  /* Ink */
  --c-ink: #1b2a2b;
  --c-ink-2: #5f6f6a;
  --c-ink-3: #66766f;       /* 4.6:1 on the surface -- the floor, not a soft grey */

  /* Rules. Three, and they are not interchangeable:
       --c-line        hairline between rows and inside cards. DECORATIVE: at 1.3:1 it is
                       deliberately below the 3:1 of WCAG 1.4.11 and must never be the only
                       thing marking a control's edge.
       --c-line-control every input, select, textarea and chip border. 3.2-3.8:1, which is what
                       1.4.11 requires of a control boundary.
       --c-line-strong  the heavy rule under a total. Ink, not a grey. */
  --c-line: #ddd6c8;
  --c-line-soft: #e8e2d5;
  --c-line-control: #8b7f6a;
  --c-line-strong: #1b2a2b;

  /* The prototype's teal. Its amber and plum come back with it (2026-08-26) -- they had been
     retired so ochre could mean exactly one thing, tax relief. Ochre already also served
     --c-caution, so the signal was never sole; what returns is amber in the brand mark and
     plum on the "sent" badge. The invoice's own N/A colour is a literal in invoice.css and is
     unaffected by anything here. */
  --c-accent: #0e6f6d;
  --c-accent-dk: #0a4f4e;
  --c-accent-tint: #e3efee;
  --c-on-accent: #ffffff;   /* 6.0:1 on the accent, 9.4:1 on accent-dk */

  /* Semantic. Never used without an accompanying text label (WCAG 1.4.1). Both are a shade
     darker than the prototype's, which sat just under 4.5:1 against their own tints. */
  --c-caution: #9e5019;
  --c-caution-tint: #f6ece2;
  --c-ok: #2b7449;
  --c-ok-tint: #e7efe6;

  /* Dossier status: hue plus label, never hue alone. The backgrounds are the prototype's; the
     foregrounds are NOT -- the prototype's are 3.5:1 and 4.3:1 against them. These are the
     app's own, which clear 4.5:1. */
  --c-st-draft: #6f6042;    --c-st-draft-bg: #efe9dc;
  --c-st-verified: #3f6a2b; --c-st-verified-bg: #e7efe0;
  --c-st-invoiced: #0a4f4e; --c-st-invoiced-bg: #e2eeee;
  --c-st-sent: #6b4a72;     --c-st-sent-bg: #e5e2ef;

  /* Type. System stacks only: no webfont, no external host, works offline.
     GEORGIA HAS ONLY OLDSTYLE FIGURES and ignores font-variant-numeric: lining-nums, so a
     number set in it descends below the baseline -- "2026-014" and "G0G 0G0" are the cases
     that show it. The serif carries headings; any FIGURE belongs in the sans, which is why
     .section-total .v is not serif. The invoice document does not use this stack at all: it
     names Liberation Serif, which is metric-compatible with the container's fonts and has
     lining figures. See invoice.css. */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-serif: Georgia, "Liberation Serif", "Times New Roman", Times, serif;
  --fs-50: .75rem;
  --fs-75: .8125rem;
  --fs-100: .9375rem;
  --fs-200: 1.0625rem;   /* >=16px on inputs prevents iOS focus zoom */
  --fs-300: 1.25rem;
  --fs-400: 1.5rem;      /* page <h1> */
  --fs-500: 2rem;
  --lh-tight: 1.25;
  --lh-body: 1.5;

  /* Space -- 4px base */
  --s-1: .25rem; --s-2: .5rem; --s-3: .75rem; --s-4: 1rem;
  --s-5: 1.5rem; --s-6: 2rem; --s-7: 3rem;

  /* Radii. Buttons are NOT pills: the pill marks state, and a page where every control is a
     pill cannot use shape to say so. Chips are pills as well as the badge -- they are tap
     targets and the prototype has them that way -- so the rule is "buttons are rectangles",
     not "the badge is the only pill". */
  --r-1: 3px; --r-2: 6px; --r-3: 10px; --r-pill: 999px;
  --r-card: 14px;    /* the prototype's card */
  --r-input: 10px;

  /* The prototype's two-layer shadow: a hairline lift plus a wide soft one. */
  --elev-1: 0 1px 2px rgb(20 40 40 / .06), 0 8px 30px rgb(20 40 40 / .08);

  --tap-min: 2.75rem;     /* 44px */
  --tap-min-lg: 3rem;     /* 48px -- journal chips, used on a phone in the field */
  --header-h: 4.5rem;
  --grid-form-preview: 1fr 0.92fr;

  /* The APP chrome above <main> -- not browser chrome, which this file's --z notes and
     components.css both use the word for. Read by ONE thing: the billing preview pane's
     max-height, and only above --bp-two-pane.

     MEASURED in Chromium 2026-08-27, because the box model is not guessable from the two rules:

       .app-header   72.0   min-height: var(--header-h) GOVERNS, and box-sizing: border-box means
                            it already CONTAINS the 12px padding and the 1px border-bottom.
                            Tallest child is .header-end at 44px against a 47px content box.
       .app-nav      49.5   .app-nav a is 22.5 (--fs-100 x --lh-body, inherited) + 24 (--s-3 x 2
                            padding) + 2 (transparent border-bottom) = 48.5, so its
                            `min-height: var(--tap-min)` is INERT and 44px never applies. Plus the
                            nav's own 1px border-bottom.
                            ---
                     121.5

     So --header-h is the only token that genuinely drives this, and the nav's 49.5 is a literal:
     an earlier `calc(var(--header-h) + var(--tap-min) + 2px)` read like a derivation and was a
     coincidence -- it came to 118, short in both terms, with the errors partly cancelling.
     If .app-nav a's font size, padding or border changes, THIS NUMBER IS STALE.
     spec/guards/component_layout_spec.rb pins those three inputs and pins that nothing new renders
     above <main> -- a third piece of chrome would make every cap wrong with the token untouched.

     Not counted, deliberately: .flash. It is 0px tall when empty (see components.css) and
     transient and dismissible when not, so sizing permanent layout for it is the wrong trade. */
  --app-chrome-h: calc(var(--header-h) + 49.5px);   /* MEASURED 2026-08-27: 121.5px */

  /* Breakpoints, recorded here and written literally at each @media. A media query cannot read
     a custom property -- these exist so the value has one place to be looked up, not so the
     query can interpolate it. Keep the two in step by hand. */
  --bp-two-pane: 1024px;   /* layout.css -- the FIRST two-column width; the repo's only min-width query.
                              1081 until 2026-08-28. The 10.2" iPad in landscape is 1080 CSS px and
                              missed the two-pane layout by ONE pixel, which is the widest iPad the
                              office is likely to hold. At 1024 the preview pane is ~490px, the width
                              it already rendered at on a 1080 screen. Portrait (768-820) deliberately
                              stays one column: 1fr 0.92fr there gives 427/393px, too narrow for an
                              invoice, so the answer at that width is the sticky total bar and an
                              anchor to the preview rather than a second pane. */
  --bp-one-col: 640px;     /* components.css -- .fields collapses to one column */
  /* PANE-RELATIVE, not viewport-relative, and it is the only breakpoint here that is: the billing
     rows restack on the width of .pane--form's content box, via @container in components.css, not
     on the window's. They had to -- above --bp-two-pane the form pane is roughly half the window,
     so at 1080 a four-column table was being asked to fit in ~500px and every label wrapped twice.
     A viewport query cannot see that; it is the same width in one column and in two.
     Replaces an untokenised 700px literal, the only breakpoint in the repo that had no entry here.
     Crosses at roughly 684/685 of VIEWPORT in one column and 1313/1315 in two -- those are the
     widths to verify at, and docs/design-system.md records them. */
  --bp-row-card: 620px;

  /* Two stacking decisions, and their order is the decision: a payer combobox's listbox has to
     cover the fields under it, and the skip link has to cover everything. */
  --z-popover: 10;         /* the payer combobox's listbox, and the header's account panel */
  --z-skip: 20;            /* the skip link, which outranks both */

  --dur-1: 120ms;
  --ease-1: cubic-bezier(.2, .6, .3, 1);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-1: 0ms; }
}
