/* Shared design tokens — loaded by every frontend page via
   <link rel="stylesheet" href="/tokens.css">, before that page's own <style> block
   so page-local rules still override it.

   Union of the pages' :root blocks (admin, new-hire, directory, invites, login,
   signup, welcome were identical or a strict subset of these values). Where pages
   disagreed, admin's value won — it is the largest, most-edited surface — except
   --brand-accent (kept from new-hire; it names the canonical green) and the
   [hidden] rule (kept from admin). Page-specific tokens (--sidebar-w, builder's
   --panel-w and friends, etc.) stay defined on their own page, after this link, so
   they override cleanly. See
   .superpowers/sdd/PLAN-arch-frontend-modules/task-2-report.md for every value
   that changed as a result of this consolidation. */
/* Surface lightness and hue, both themes. Retuned 2026-09-15, in answer to
   "dark is way too green and light is way too creme". Both halves of that were
   measurable, and both were worse than the previous version of this comment
   claimed.

   LIGHT was not merely warm, it was DARK. --bg sat at L* 89.4, which is ten
   points below the page ground every major system uses: Material 3, Primer,
   Tailwind and Apple all put a light canvas at 95-100 and a raised surface at
   95-98, and none of them goes below ~90 even for a third tier. A page ground at
   89 with a 97 card is the grey-on-beige that reads as cream. It now runs
   93.7 / 96.9 / 100 -- bg is a faint green-grey, and the CARD is white -- which is
   the canvas-then-white pattern those systems share.

   The hue landed on the third try, and the two misses are worth recording because
   they bracket it. At a +2 green bias the palette measured perfectly and looked
   like every other admin console -- that is what taking "neutral greys" literally
   costs a product whose whole identity is one colour. At +6 dark was back to
   reading as a green room, which was the original complaint. Dark now sits at
   **+4**, light at +7 to +8 -- light can carry more because a tint reads weaker
   against a near-white ground than against a dark one, which is the same asymmetry
   that makes the contrast floors harder to hit in dark mode. In both, the blue
   channel is held two steps above red so the neutrals sit in the same family as
   forest #1B6B41 instead of drifting toward teal.

   Restoring the hue cost nothing measurable: every ratio below is from the values
   as shipped.

   DARK was green. The previous comment asserted "green bias on every structural
   dark token is now within +/-2 of neutral"; measured, the tokens ran +7.5 to
   +12.5, and --surface was +12. So the doc described a neutral palette while the
   file shipped a green one, which is exactly the complaint. Every structural dark
   token is now +2, one step cool, and the accent is the only thing carrying real
   green -- which is what the rule always said.

   What did NOT change, deliberately:

   - **Dark's lightness band.** L* 20.5 / 23.7 / 26.8, unchanged. Research for this
     retune pointed at Material 3's tone-10 baseline (~L* 7) as the industry norm,
     and that was overruled: the 2026-09-10 retune lifted dark OFF L* 12.6 on
     purpose, because it had 13.5:1 of text contrast against a 4.5:1 floor and was
     darker than it needed to be. The complaint here was hue, not lightness.
   - **Three perceptible elevation steps.** Light +3.3 then +3.1, dark +3.2 then
     +3.1, both above the ~3 L* threshold where an edge is reliably visible with no
     border.
   - **Body text off AAA.** 8.67:1 light and 8.65:1 dark, against a 4.5 floor. High
     enough to be comfortable, short of the glare a near-black-on-white sets up.

   Every ratio here was measured, not estimated. The worst pair is 5.38:1 in light
   (--accent-tx on --bg-tint) and 4.86:1 in dark (--text-3 on --surface).
   --border-mid is 1.8-1.9:1 against its ground in both themes; that is unchanged
   from the previous palette (2.05 / 2.22) and is acceptable because it is a
   decorative edge, not a boundary carrying information -- the 3:1 floor is for the
   latter.

   --text-3 and --red-tx move WITH the surfaces. Dimming a background without
   darkening the muted text on it spends contrast you cannot see going, which is
   how these palettes drift under AA one small edit at a time. */
:root {
  --bg:          #F2EEE4;
  --surface-2:   #F9F7F1;
  --surface:     #FFFFFF;
  --bg-tint:     #E1EFE8;
  --bg-tint-2:    #F7F4EE;
  --border:      #D2E1D8;
  --border-mid:  #98B4A6;
    /* ── The chrome ───────────────────────────────────────────────────────
     The top bar and the nav rail, and nothing else. They are a different KIND of
     surface from a card -- they are the same on every page and hold no customer
     data -- so they get their own names even when the value matches `--surface`.

     **They are deliberately NOT tinted, and that is the finding.** Four attempts
     put the brand into a surface and all four failed:

       1. warm cream page greys (L* 89 canvas)   -> "way too cream"
       2. near-neutral greys (+2 green)          -> "too generic"
       3. sage greys (+6 to +8 green)            -> "overcorrected to green"
       4. a forest chrome band on this token     -> "really bad for dark mode"

     The fourth is the informative one. On a pale ground a low-chroma hue recedes
     and reads as a change of material; on a dark ground it does not, so the rail
     stopped being chrome and became a feature competing with the table beside it.

     The names are kept anyway. A future attempt to distinguish the chrome -- with
     a border weight, a shadow, a hairline -- has one seam to work at instead of
     twelve call sites, and reverting it again is a value change. */
  --chrome:        #FFFFFF;
  --chrome-border: #E2DDD0;

  --text:        #2A4534;
  --text-2:      #3B5243;
  --text-3:      #49604F;
  --text-inv:    #FFFFFF;

  /* An inverted confirmation surface -- the dark panel the Assign board shows on a
     light page, for "Sales Onboarding assigned to 2 people". It is deliberately not
     a toast: it names who was skipped and why, and that has to stay readable rather
     than fade. Tokenised because the first implementation hardcoded these four hex
     values, which the theme-safe test does NOT catch: it looks for a literal `color:`
     over a THEMED background, and a literal colour over a literal background is
     self-consistent enough to pass while still ignoring the theme. */
  --panel-inv:     #1E3A2A;
  --panel-inv-tx:  #E4EFE8;
  --panel-inv-tx2: #A9D5B8;

  /* The ink that goes ON --accent. This has to be a token: --accent is dark in
     light mode and light in dark mode, so one hardcoded value cannot be correct
     in both. 39 pages hardcoded #0B1A18 here, which the theme-safe test cannot
     catch -- a literal colour over a literal colour is self-consistent. */
  --on-accent:  #FDFFFC;

  /* The ink that goes ON a filled danger control, and the same story as
     --on-accent: it reverses between themes, so no literal can be right in both.
     Light --red was #D9584A, on which NO ink cleared AA -- white 3.86:1,
     near-black 3.36:1 -- so a danger button could not be built from it at all.
     It is now 14% darker in lightness at the same hue, which clears 4.87:1 with
     white while still reading as the same red. Dark's #FF8585 needs no retune:
     it carries this ink at 6.92:1 and is unchanged. */
  --on-red:     #FFFFFF;

  --brand-accent: #1B6B41;
  --accent:     var(--brand-accent, #1B6B41);
  --accent-dark:  #14512F;
  --accent-darker: #0F3D23;

  /* ── Brand identity ───────────────────────────────────────────────────
     The logo, approved 2026-09-15 (design-shotgun round 2, variant B1): a
     checkmark whose stroke closes its own rounded-square enclosure, set in a
     deep forest rather than the UI green.

     --logo is deliberately NOT --accent. They are different jobs: --accent is a
     FILL tuned so that #0B1A18 clears AA on it and white does not, which is what
     keeps it bright (see the C3 note and test_dark_text_on_the_green_not_white).
     The logo has no such constraint -- it is a single-colour mark on a page
     background, so it can be dark enough to read as forest. Collapsing the two
     would force the accent darker, white would start passing on it, and every
     button in the product would have to be re-measured. If the brand green is
     ever genuinely retired, that is a deliberate palette change with its own
     contrast pass, not a side effect of picking a logo.

     --brand-forest / --brand-cream are the identity pair for brand surfaces
     (favicon ground, apple-touch icon, OG images). They are not UI surfaces and
     nothing in the app chrome should reach for them. */
  --brand-forest: #123D2B;
  --brand-cream:  #F6F1E7;
  --logo:         #1B6B41;

  /* ── Type ──────────────────────────────────────────────────────────────
     One UI face, one mono face, per UI-DESIGN-STANDARDS section 2. These exist
     because nothing enforced that rule: 16 pages each hardcoded their own
     font-family string and their own Google Fonts URL across four different
     weight sets, so the doc said "Inter and DM Mono" while the code said four
     slightly different things. The stack is metric-close to Inter so a failed
     webfont reflows as little as possible. */
  --font-ui:     'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  /* No mono WEBFONT. DM Mono was carrying two label roles -- the .hdr section
     header and the scope pills -- for 29.8 kB, and its x-height of 0.496 is the
     lowest of any face measured, so the smallest text in the product was set in
     the narrowest-eyed font available. Those labels are Inter at 600 now;
     uppercase, tracking and colour already distinguish them three ways over.
     The token stays for genuine code or id display, on the system stack. */
  --font-mono:   ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --red:         #CF3B2B;
  --red-bg:      #FBEDE8;
  --amber:       #E39A3A;
  --amber-bg:    #FBF0DC;
  --accent-tint:    #D5ECE0;

  /* ── Brand lines ──────────────────────────────────────────────────────
     Where the brand actually lives, after four failed attempts to put it in a
     surface. The rule that came out of them:

       full chroma is allowed only where the element is under ~1% of the
       viewport; anything larger must sit at chroma-over-lightness <= 0.15 in BOTH themes.

     Dark's budget is roughly four times tighter than light's for the same
     perceived quietness, because saturation is chroma relative to lightness: a
     tint at fixed chroma reads ten times more coloured at L* 24 than at L* 95. The
     Helmholtz-Kohlrausch effect then makes the saturated version look brighter
     than its luminance, so it advances instead of receding -- which is exactly
     how a forest nav rail stopped being chrome and became a feature.

     --nav-on-bg is the fill behind the current nav item. It used to be
     --accent-tint, which in dark measured chroma-over-lightness = 0.688 -- the most saturated
     surface in the whole dark UI -- while sitting at 1.02:1 against the page. The
     loudest token in the palette and perceptually invisible, at the same time. The
     3px accent rail now carries the state at 5.10:1 and the fill is near-neutral.

     --border-control is the fix for a real WCAG 1.4.11 failure. An EMPTY input has
     no content, so its border is the only thing identifying it as a control, which
     puts that border in scope at 3:1. --border measured 1.17-1.53:1 depending on
     the ground, and --border-mid did not rescue it at 1.80-2.23:1. Decorative card
     edges keep --border; only controls take this. */
  --nav-on-bg:      #D5ECE0;
  --border-control: #74887E;

  /* ── Categorical accents ──────────────────────────────────────────────
     Five hues for CATEGORIES — a department, a team, an org value. Added
     2026-09-15, and they are a deliberate amendment to rule 1's "a category badge
     that repeats per row is neutral at rest".

     The distinction that makes both true: that rule was written about a badge
     carrying the SAME value on every row, where the colour adds nothing the word
     does not already say. These are assigned per DISTINCT VALUE and are stable —
     Engineering is always teal, Sales is always clay — so the colour is a second
     channel you can scan down a column without reading. It is information, not
     decoration, which is the test.

     What has NOT changed: --accent is still the only green that means ACTION. A
     category never takes --accent, and --cat-forest is a different, lighter green
     precisely so a category pill cannot be mistaken for a button.

     Every pair below clears 4.5:1 as text on its own tint AND on every page
     surface the pill can land on. The inks are the most saturated value that still
     does, not the safest near-black — a categorical palette that resolves to five
     shades of charcoal has not earned its place. */
  --cat-forest-bg: #E0F0E8;  --cat-forest-tx: #1C784A;
  --cat-teal-bg:   #E0EEF0;  --cat-teal-tx:   #1E7380;
  --cat-indigo-bg: #E0E2F0;  --cat-indigo-tx: #4558D3;
  --cat-plum-bg:   #EEE0F0;  --cat-plum-tx:   #A32BB6;
  --cat-clay-bg:   #F0E6E0;  --cat-clay-tx:   #A15326;


  /* Near-neutral, and slightly stronger: a shadow tuned for a beige ground
     all but disappears against a near-white one. */
  --shadow-sm:   0 1px 3px rgba(24,36,30,.09);
  --shadow-md:   0 4px 16px rgba(24,36,30,.12);
  --shadow-lg:   0 8px 32px rgba(24,36,30,.16);

  --header-h:    64px;
  /* ── Motion ────────────────────────────────────────────────────────────
     Easing was the generic `ease` keyword everywhere, which is symmetric and
     reads as unrefined: an entrance that accelerates INTO its resting point
     fights what the eye expects. NN/g's animation-duration guidance is to use
     ease-OUT for entrances, because it "makes the animation feel responsive"
     while leaving "the eye time to focus", and ease-IN for exits. Curves are
     Material's decelerate / accelerate / standard, which are the widely
     implemented values for exactly that split.
     Durations: NN/g puts the usable band at 100-500ms, calls 100-400ms right
     for most transitions, and says "at 500ms, animations start to feel like a
     real drag". --dur-travel is the deliberate exception: it is narrative
     motion crossing the whole stage, and NN/g scales duration with how far the
     element travels. It is content, not feedback. */
  --ease-out:    cubic-bezier(0, 0, .2, 1);
  --ease-std:    cubic-bezier(.2, 0, 0, 1);
  --dur-quick:   140ms;
  --dur-base:    240ms;
  --dur-slow:    380ms;
  --dur-travel:  900ms;

  --radius:      10px;
  --radius-sm:   6px;

  /* Shared tokens that used to live only in templates/builder.html's own <style>.
     Four other pages -- templates/index, templates/task, people and org -- USED
     them via var() without defining them, so radii silently fell back to square
     corners and the "customized" colours resolved to nothing. A var() with no
     definition fails quietly: no console error, no test failure, just the wrong
     shape. They belong here, where every page loading tokens.css gets them. */
  --radius-card: 12px;
  --radius-pill: 100px;
  --custom:      #8A5510;
  --custom-dim:  #D9BE8A;
  --custom-tint: #F7EDD8;
  --accent-dim:  #A9D5B8;

  /* Tells the browser which schemes the page actually supports, so UA-painted
     chrome -- form controls, scrollbars, the canvas behind the page -- follows the
     theme instead of staying light on a dark page. Every colour below was themed
     and this was not, so a date input and a scrollbar stayed light in dark mode.
     It mirrors the token blocks exactly: the toggle wins over the OS in both
     directions. (MDN: color-scheme; W3C css-color-adjust-1.) */
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg:          #2F3231;
    --surface-2:   #363938;
    --surface:     #3D403F;
    --bg-tint:     #293D33;
    --bg-tint-2:    #333635;
    --border:      #4A4E4C;
    --border-mid:  #626664;
    /* See the light block: the chrome is forest, the canvas is not. */
    --chrome:        #3D403F;
    --chrome-border: #4A4E4C;

    --text:        #E4E8E5;
    --text-2:      #AFB6B1;
    --text-3:      #A9B1AC;
    --text-inv:    #2F3231;

    /* Inverting against an already-dark page means lifting, not darkening: #1A3325
       against the #323638 surface would read as a hole rather than a panel. */
    --panel-inv:     #22402E;
    --panel-inv-tx:  #E9F3EB;
    --panel-inv-tx2: #A9DCC2;

    --on-accent:  #12241A;
    --on-red:     #12241A;
    --accent:     #6FD79B;
    --accent-dark:  #8FE5B3;
    --accent-darker: #6FD79B;
    /* The mark lifts on a dark ground rather than darkening; forest on #2E3133
       would read as a hole. Same reasoning as --panel-inv above. */
    --logo:         #6FD79B;

    --red:         #FF8585;
    --red-bg:      #3A2724;
    --amber:       #FFC26A;
    --amber-bg:    #392F1C;
    --accent-tint:    #1E382B;
    /* See the light block. Dark's fill is near-neutral by necessity, not by
    taste: chroma-over-lightness here is 0.082, against 0.688 for the token it replaces. */
    --nav-on-bg:      #454A48;
    --border-control: #828E88;

  /* See the light block for why these exist and what rule they amend. */
  --cat-forest-bg: #2B4A3B;  --cat-forest-tx: #32C87D;
  --cat-teal-bg:   #2B464A;  --cat-teal-tx:   #43BDD0;
  --cat-indigo-bg: #2B2F4A;  --cat-indigo-tx: #9DA7E7;
  --cat-plum-bg:   #462B4A;  --cat-plum-tx:   #D891E3;
  --cat-clay-bg:   #4A372B;  --cat-clay-tx:   #DD9D78;


    /* See the light block for why these exist and what rule they amend. */
    --cat-forest-bg: #2B4A3B;  --cat-forest-tx: #32C87D;
    --cat-teal-bg:   #2B464A;  --cat-teal-tx:   #43BDD0;
    --cat-indigo-bg: #2B2F4A;  --cat-indigo-tx: #9DA7E7;
    --cat-plum-bg:   #462B4A;  --cat-plum-tx:   #D891E3;
    --cat-clay-bg:   #4A372B;  --cat-clay-tx:   #DD9D78;


    --shadow-sm:   0 1px 3px rgba(0,0,0,.32);
    --shadow-md:   0 4px 16px rgba(0,0,0,.38);
    --shadow-lg:   0 8px 32px rgba(0,0,0,.50);
    /* See the light block: promoted out of builder.html so every page has them. */
    --radius-card: 12px;
    --radius-pill: 100px;
    --custom:      #E8A93F;
    --custom-dim:  #4A3A1C;
    --custom-tint: #352B1A;
    --accent-dim:  #2C4A3C;

  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:          #2F3231;
  --surface-2:   #363938;
  --surface:     #3D403F;
  --bg-tint:     #293D33;
  --bg-tint-2:    #333635;
  --border:      #4A4E4C;
  --border-mid:  #626664;
  /* See the light block: the chrome is forest, the canvas is not. */
  --chrome:        #3D403F;
  --chrome-border: #4A4E4C;

  --text:        #E4E8E5;
  --text-2:      #AFB6B1;
  --text-3:      #A9B1AC;
  --text-inv:    #2F3231;

  --on-accent:  #12241A;
  --on-red:     #12241A;
  --accent:     #6FD79B;
  --accent-dark:  #8FE5B3;
  --accent-darker: #6FD79B;
  --logo:         #6FD79B;

  --red:         #FF8585;
  --red-bg:      #3A2724;
  --amber:       #FFC26A;
  --amber-bg:    #392F1C;
  --accent-tint:    #1E382B;
  /* See the light block. Dark's fill is near-neutral by necessity, not by taste:
     chroma-over-lightness here is 0.082, against 0.688 for the token it replaces. */
  --nav-on-bg:      #454A48;
  --border-control: #828E88;

  --shadow-sm:   0 1px 3px rgba(0,0,0,.32);
  --shadow-md:   0 4px 16px rgba(0,0,0,.38);
  --shadow-lg:   0 8px 32px rgba(0,0,0,.50);
  /* See the light block: promoted out of builder.html so every page has them. */
  --radius-card: 12px;
  --radius-pill: 100px;
  --custom:      #E8A93F;
  --custom-dim:  #4A3A1C;
  --custom-tint: #352B1A;
  --accent-dim:  #2C4A3C;

}

[hidden] { display: none !important; }

/* C3 — semantic colours legible as TEXT. The base --red/--amber/--accent
   stay exactly as they are for fills, borders and dots; these are the text-only
   variants. Light values clear WCAG AA (4.5:1) on every surface they appear on:
   the matching tint, --bg and --surface. The dark palette already passed, so the
   dark values are the base colours unchanged. Measured 2026-09-09. */
:root { --red-tx: #A32E1E; --amber-tx: #75500C; --accent-tx: #1B6B41; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=light]) { --red-tx: #FF9A8A; --amber-tx: #F0BE62; --accent-tx: #6FD79B; }
}
:root[data-theme=dark] { --red-tx: #FF9A8A; --amber-tx: #F0BE62; --accent-tx: #6FD79B; }
