/* ============================================================================
   Portmasters Visual System v2 — Semantic Alias Layer (tokens-semantic.css)
   ----------------------------------------------------------------------------
   PURPOSE: a thin ROLE vocabulary layered on top of tokens.css. Every value
   here is a pure var() alias of an EXISTING primitive — ZERO new values, ZERO
   new colors/radii, ZERO renames. All original primitive names in tokens.css
   keep working exactly as before; this file only ADDS role aliases.

   LOAD ORDER: tokens.css MUST be loaded/imported before this file so every
   var() below resolves. (tokens.css is intentionally left unmodified — no
   @import was added to it.)

   TWO-VOICE RULE (G0-4, DECIDED 2026-07-03): product buttons/controls are
   rectangles at the control tier (--radius-button-product); pills
   (--radius-pill 100px) are MARKETING-only. Two voices: rectangles work, pills sell.
   (The control tier itself moved 8px -> 12px on 2026-07-29 — see RADIUS ROLES
   below. The rule is unchanged; only the number under it moved.)

   GATE 0 CLOSED 2026-07-03 — the previously-excluded values are now DECIDED and
   aliased below: G0-1 magenta #D342F0 (--accent), G0-2 radius tiers
   (--radius-card / --radius-control), G0-3 text-safe green (--text-positive).

   2026-07-29 — FIGMA MIRROR. Four founder-approved changes land in tokens.css
   and are given role names here: the radius ladder (8/14 -> 12/12 + a new 18px
   tray tier), the 44px control height (REVERSED 2026-08-04 — the founder set every
   single-row control to 36px, one height, no exceptions; tokens.css:540-574 is the
   live value and this line is kept only as the 2026-07-29 record), the five-plane
   dark ladder, and the file-wide removal of inner shadows. One new role is NOT a pure var() alias:
   --radius-tab is a composed shorthand (`8px 8px 0 0`) because tab-button's
   corner cannot be expressed as a single value. Noted rather than hidden.
   ============================================================================ */

:root {

  /* ==========================================================================
     SURFACE / BACKGROUND ROLES — THE FIVE PLANES, NAMED, IN BOTH THEMES
     --------------------------------------------------------------------------
     2026-08-02. Until now the plane law was only expressible in DARK: the deep
     ladder had five rungs and the light ladder had two, so --bg landed on Figma's
     TRAY value and --surface-1 on Figma's CARD value and the whole light stack sat
     one step light with tray and card collapsed onto the same hex. tokens.css now
     carries the three missing light rungs (--paper-sunk / --paper-inlay /
     --paper-press); this block gives all five planes ONE role name each that means
     the same thing in both themes, which is the thing the system never had.

       role                dark              light               Figma role
       --surface-page      --deep    #0f0715  --paper-sunk  #f4f2f6  surface/page
       --surface-tray      --deep-2  #1e1029  --paper       #faf8fc  surface/tray
       --surface-plate     --deep-4  #241830  --paper-inlay #efeaf3  surface/plate
       --surface-stalled   --deep-5  #2b1d36  --paper-press #f1ecf6  surface/stalled
       --surface-card      --deep-6  #322639  --paper-2     #ffffff  surface/card

     These are ADDITIVE. No existing role changes value except --bg (below), so no
     component moves unless its own lane moves it. Prefer a plane role over
     --surface-1/-2 in new code: the plane roles cannot lie about which theme they
     are in, and the two ordinals currently can (see the note under them).

     INK × THE FIVE LIGHT PLANES — recomputed 2026-08-02 AFTER the ink repoints in
     the STATUS TEXT block below, WCAG 2.x, from the hexes, because moving a
     background silently invalidates contrast on foregrounds nobody touched.
     Column order is worst-first. The light floor is the PLATE #efeaf3, NOT white
     and NOT the page (gate BW-K5).

     EVERY TEXT ROLE NOW CLEARS AA 4.5 ON ALL FIVE LIGHT PLANES. The seven-row
     "below AA on at least one plane" section this table used to carry is gone
     because the values moved, not because the bar did — see (a).

       ink role              value      plate  stalled   page    tray    card   AA4.5
       --text-primary        #16131c    15.50   15.79   16.50   17.39   18.36   PASS
       --text-secondary      #353c4d     9.31    9.49    9.91   10.45   11.02   PASS
       --text-info           #232CD2     7.51    7.65    7.99    8.42    8.89   PASS
       --text-muted          #4e5666     6.23    6.35    6.63    6.99    7.38   PASS
       --text-info-subtle    #2B3DE5     6.11    6.23    6.51    6.86    7.24   PASS  was #425FF0 4.30
       --text-error          #C4123F     5.06    5.15    5.39    5.68    5.99   PASS  was #E22056 3.88
       --text-error-strong   #C4123F     5.06    5.15    5.39    5.68    5.99   PASS  alias of --text-error
       --text-error-subtle   #C4123F     5.06    5.15    5.39    5.68    5.99   PASS  was #F2407B 3.06
       --text-warning        #9d5011     4.94    5.03    5.26    5.54    5.85   PASS  was #AA5813 4.31
       --text-success        #007a5c     4.50    4.59    4.79    5.05    5.33   PASS  was #008364 4.00
       --text-success-subtle #007a5c     4.50    4.59    4.79    5.05    5.33   PASS  was #00C993 1.81
       --text-positive       #007a5c     4.50    4.59    4.79    5.05    5.33   PASS  alias of --text-success

     NON-TEXT, AA 3:1, on all five light planes — worst (plate) first. --mode-* is
     in THIS table and not the one above: foundation-colour.md BW-M5 rules a mode is
     a stroked glyph at the 3:1 bar and is never a text colour, which is why
     --mode-land #008364 at 4.00 on the plate is a PASS and not the AA failure the
     old table logged it as. Mode hues do not move (founder ruling: sea blue / land
     green / air pink stay).

       non-text role           value      plate  stalled   page    tray    card   AA3
       --border-strong         #353c4d     9.31    9.49    9.91   10.45   11.02   PASS
       --mode-sea              #232CD2     7.51    7.65    7.99    8.42    8.89   PASS
       --mode-air              #C4123F     5.06    5.15    5.39    5.68    5.99   PASS
       --mode-land             #008364     4.00    4.08    4.26    4.49    4.74   PASS
       --border-success        #008364     4.00    4.08    4.26    4.49    4.74   PASS  was #00A478 2.69 FAIL
       --border-success-strong #008364     4.00    4.08    4.26    4.49    4.74   PASS  alias
       --accent-hover          #bb25d4     4.10    4.17    4.36    4.60    4.85   PASS
       --border-error-strong   #E22056     3.88    3.95    4.13    4.35    4.59   PASS
       --green                 #00936f     3.28    3.34    3.49    3.68    3.89   PASS
       --border-error          #F2407B     3.06    3.12    3.26    3.43    3.62   PASS  see (c)
       --accent                #d342f0     3.05    3.11    3.25    3.43    3.62   PASS  see (d)
       --focus-ring            #d342f0     3.05    3.11    3.25    3.43    3.62   PASS  see (d)

     Hairlines and inert fills are deliberately below 3:1 and are not graphical
     objects: --border #e8e3f0 1.06 · --field-border #B4BFC7 1.58 · --skeleton
     #D9E1E5 1.12 · --surface-disabled #ECF0F3 1.01.

       (a) THE 2026-08-02 INK REPOINT. Seven text roles were under 4.5 on the plate:
           --text-error 3.88 · --text-error-subtle 3.06 · --text-success 4.00 ·
           --text-success-subtle 1.81 · --text-warning 4.31 · --text-info-subtle 4.30
           (and --mode-land 4.00, which was never a text role — see the note above).
           Four of the seven were annotated rather than fixed: two as "pre-existing,
           the repoint did not break them", two as "by design, low-emphasis". Both
           excuses are now withdrawn — a role the file itself labels "small text ⇒ AA
           4.5:1" either meets the bar or it does not. Values, provenance and the
           rejected alternatives are at the STATUS TEXT block below; the table above
           is measured from the hexes those declarations now resolve to.
       (b) WHAT THE --bg REPOINT ITSELF BROKE, kept for history: measured old-page
           #faf8fc vs new-page #f4f2f6 across all 23 ink/border/accent roles, ZERO
           text roles crossed AA on the PAGE — every role that passed on #faf8fc
           still passes on #f4f2f6. Exactly one role of any kind crossed a bar, and
           it was non-text: --border-success #00A478 read 3.023 on the old page and
           2.868 on the new one, one and a half hundredths of headroom being all it
           ever had. Repointed to --success-700 #008364, the first existing ramp stop
           that clears the WORST light plane (4.0026 plate, not merely 4.26 page).
           Stated cost: the resting and hover valid edges collapse onto one colour in
           light, as they already had in dark. Full provenance at --border-success.
       (c) --border-error #F2407B clears 3:1 by 0.06 on the plate. It is NOT below
           the bar, so it is not this lane's defect to fix, but foundation-colour.md
           §7 row 9 (E3) does rule it should go to --error-700 #C4123F; landing that
           also requires re-tinting --shadow-error (tokens.css). Left open, named.
       (d) --accent #d342f0 3.0536 is now the tightest non-text margin in the light
           theme, +0.0536. As a FILL and a RING it passes; as small TEXT it is
           3.62:1 even on white and fails everywhere — see the ban at the ACCENT
           ROLES block below. foundation-colour.md §7 row 26 rules the light accent
           should become --primary-700 #9e1bb0 (5.4775 plate), which is a
           founder-visible brand change and is not this lane's to make.

     THE TIGHTEST PASSING TEXT CELL IN THE LIGHT THEME is --text-success /
     --text-positive #007a5c on the plate at 4.5028:1 — it clears AA by under three
     thousandths, and after the repoint above THREE role names now land on that one
     cell instead of one. Treat it as a tripwire: any future darkening of
     --paper-inlay, however small, fails all three at once. Re-measured after the
     2026-08-02 repoints, not assumed: neither --border-success (success-* ramp) nor
     --text-warning (--warning-text) shares an ancestor with --green-text and no
     plane value changed, so the cell is still exactly 4.5028.
     Second-tightest text cell: --text-warning #9d5011 at 4.9408.

     ONE CONSEQUENCE THIS LANE DID NOT ACT ON, flagged because this change is its
     stated precondition: foundation-colour.md conflict C3 rules that the LIGHT
     accent becomes --primary-700 #9e1bb0, "once plane 0 became #f4f2f6", because
     --primary-600 #bb25d4 then measures 4.36 on the page and 4.10 on the inlay —
     both under 4.5 as text. Recomputed here independently: 4.3616 and 4.0971, which
     reproduces C3's published 4.36 / 4.10 exactly, and #9e1bb0 gives 5.8311 / 5.4775
     against C3's 5.83 / 5.48. Plane 0 IS now #f4f2f6, so C3's precondition is met as
     of this commit. The accent repoint is a founder-visible brand change and is not
     in this lane's scope.
     ========================================================================== */
  --surface-page:    var(--paper-sunk);   /* → #f4f2f6 — plane 0: page / board well */
  --surface-tray:    var(--paper);        /* → #faf8fc — plane 1: top nav, sub-bar, sidebar, column body, panel, section, table header, footer */
  --surface-plate:   var(--paper-inlay);  /* → #efeaf3 — plane 1.5: the column nameplate / inlay. Also the ratified disabled-control and selected-row fill (foundation-colour.md §2.8) — a MATERIAL, at most three classes may paint it */
  --surface-stalled: var(--paper-press);  /* → #f1ecf6 — the debossed / no-activity card, drag placeholder */
  --surface-card:    var(--paper-2);      /* → #ffffff — plane 2: card, popover, menu, tooltip, dialog, sheet, toast, combobox list */

  --bg:          var(--surface-page); /* REPOINTED 2026-08-02: WAS --paper #faf8fc, which is Figma's TRAY value — the page was painting itself one rung too light because no page rung existed. Now --paper-sunk #f4f2f6. Mandated by foundation-colour.md:645 ("--bg (light) | --paper #faf8fc | REPOINT | --paper-sunk #f4f2f6 | system-wide | SPEC D2"). Dark value unchanged (#0f0715).
     CONSUMER LIST CORRECTED 2026-08-02. It read "Seven consumers, all page-level" and then listed four, one of which had already been reverted. Re-derived by grepping every component stylesheet for `var(--bg)`: there are THREE declarations, all page-level — app-shell.css:267 (.pm-shell root), auth-split-layout.css:138, master-detail-layout.css:125. stat-tile.css is NOT a consumer: line 81 is the comment recording that the one-round `background-color: var(--bg)` regression on the tile was reverted, and a tile is a content object that must inherit its host's plane. (269 further `var(--bg)` reads exist across matrix/_preview HTML — those are demo page backdrops, not library consumers.) */
  /* --surface-1 / --surface-2 ARE NOT PLANE-CLEAN, AND THAT IS DELIBERATE TODAY.
     In DARK they resolve correctly: --surface-1 → tray, --surface-2 → card. In LIGHT
     --surface-1 resolves to the CARD plane (#ffffff) and --surface-2 to an off-palette
     cool grey (--neutral-50 #F4F7F9, which foundation-colour.md §2.8 records as
     "dropped as a surface"). So --surface-1 means TRAY in dark and CARD in light —
     which is exactly why card.css needed a bespoke [data-theme="dark"] override
     (card.css:116) and why the light tray and the light card came out the same hex.
     THE VALUES ARE LEFT ALONE ON PURPOSE. ~40 component files read --surface-1 as
     "the white card/panel/focus-ring-offset" and ~35 read --surface-2 as "the quiet
     hover/inset wash"; repointing either one without moving those consumers in the
     same change would not fix the collapse, it would relocate it (cards would go
     #faf8fc = the tray value; every hover wash would go pure white and vanish).
     The target state is foundation-colour.md §2.1 — light --surface-1 → --surface-tray,
     light --surface-2 → --surface-card, washes/disabled/selected → --surface-plate —
     and it is a coordinated components/ migration, not a token repoint. Reported as a
     blocker by the token lane rather than done blind. */
  --surface-1:   var(--paper-2);    /* → --paper-2 #ffffff — raised card / panel surface (pure white). Dark: --deep-2 tray. See the note above. */
  --surface-2:   var(--neutral-50); /* → --neutral-50 #F4F7F9 — secondary/inset wash (subtle chrome). Dark: --deep-6 card. See the note above. */
  --surface-disabled: var(--neutral-100); /* → --neutral-100 #ECF0F3 — inert/disabled control fill (G1-1 veto value, VERBATIM in light); dark override below (M1 Amir decision: disabled gets a dark fill in dark mode) */
  --skeleton: var(--neutral-200); /* → #D9E1E5 — loading placeholder fill; VISIBLE vs white (M1 wrongly borrowed --surface-2 #F4F7F9 = 1.076:1, invisible — founder "skeleton not works"). Dark override below. */

  /* ==========================================================================
     BORDER ROLES
     ========================================================================== */
  --border:        var(--line);      /* → --line #e8e3f0 — default hairline border */
  --border-strong: var(--ink-700);   /* → --ink-700 #353c4d — high-contrast/emphasis border */

  /* ==========================================================================
     TEXT ROLES
     ========================================================================== */
  --text-primary:   var(--ink);       /* → --ink #16131c — primary body / headings ink */
  /* R1 (ratified 2026-07-28, F4) — the three-tier ink slide. Was ink-500/ink-400;
     that collapsed the tiers because --text-muted #737d8d and --text-secondary
     #4e5666 sat too close. Now three distinct tiers, all AA on paper. Matches the
     Figma PM Theme roles text/secondary and text/muted exactly. */
  --text-secondary: var(--ink-700);   /* → --ink-700 #353c4d — lead & body paragraphs */
  --text-muted:     var(--ink-500);   /* → --ink-500 #4e5666 — muted meta / sub-labels */
  --text-on-dark:   var(--white);     /* → --white #ffffff — text over dark sections */
  --text-positive:  var(--text-success);/* → #007a5c via --text-success (G0-3 --green-text). 4.5028:1 on the plate = the tightest passing cell in light, see the SURFACE ROLES matrix; #00936f stays for large/fill. NAME RETIRED 2026-08-02 (foundation-colour.md §7 row 4 — "two roles, one meaning"): it now reads --text-success instead of --green-text directly, so the two cannot drift apart again. Value is BYTE-IDENTICAL to what it painted before; kept as an alias because 6 files still read it. Do not use in new code — use --text-success */

  /* ==========================================================================
     TRANSPORT-MODE ROLES — the route-line colour encodes shipment mode
     (live product convention): sea=blue · road=green · air=red. Distinct from
     STATUS roles (error/success/info) — a mode is not a state. Dark variants
     below lift each to a lighter stop legible on the deep surfaces.
     ========================================================================== */
  /* D5 (ratified 2026-07-26, applied 2026-07-28 under F4).
     The four hexes that used to live here (#2f6bed #16a34a #e0245e, and the dark
     trio below) were invented — none belonged to any shipped ramp, which is a
     provenance violation sitting in the semantic layer. Each is now repointed onto
     an EXISTING ramp stop, and every value below matches the Figma PM Theme roles
     mode/sea, mode/land and mode/air byte-for-byte.
     `--mode-road` is RENAMED to `--mode-land` — the data enum is LAND_FCL/LAND_LCL
     and "road" is not a word in it. The old name is kept as a deprecated alias so
     no consumer breaks; components/route-line/route-line.css:67 still reads it. */
  --mode-sea:  var(--info-700);     /* #232CD2 — ocean freight (SEA_*) */
  --mode-land: var(--success-700);  /* #008364 — land freight (LAND_FCL / LAND_LCL) */
  --mode-air:  var(--error-700);    /* #C4123F — air freight (AIR_*) */
  --mode-road: var(--mode-land);    /* DEPRECATED alias for --mode-land. Do not use in new code. */

  /* ==========================================================================
     STATUS SEMANTIC ROLES  (Phase-2b TRACK A — airtight-dark status vocabulary)
     ----------------------------------------------------------------------------
     WHY: components pulled RAW status primitives (--error-600/700, --success-700,
     --warning-700, --info-700, --error-500 …) for status TEXT and status BORDERS.
     Those primitives have NO [data-theme="dark"] override, so dark was NOT airtight
     (dark-purple text on dark-purple surfaces / near-black borders). These roles
     give one theme-flippable alias per status intent (Carbon $text-error/$support-*
     principle). LIGHT value of every role == the EXACT primitive it replaces, so
     light is byte-identical (grep/compute verified). DARK repoints below in the
     [data-theme="dark"] block to an EXISTING lighter ramp stop that passes WCAG on
     the deep-* surfaces — NO invented hex.

     STOP-FAITHFUL naming: two error-text stops and two of each subtle/strong stop
     are genuinely in use (label uses -700, helper uses -600; description uses -500,
     label uses -700). A single role can't carry two light values byte-identically,
     so each in-use stop gets its own role (the button file already carries per-context
     stops the same way). Base roles below == the card-named ones; *-strong / *-subtle
     are the second in-use stop.
     ========================================================================== */

  /* status TEXT (small text ⇒ AA 4.5:1, measured on the PLATE #efeaf3 — the light floor)
     ----------------------------------------------------------------------------
     ALL EIGHT REPOINTED / COLLAPSED 2026-08-02 (AA regression lane). Every one of
     these roles is declared "small text ⇒ AA 4.5:1" by the line above, and seven of
     the eight were below 4.5 on the light plate. The header matrix in this file used
     to record that as five "see (a)…(d)" footnotes — an annotated failure is still a
     failure, so the values move. Mandated by docs/m2-foundations/foundation-colour.md
     §7 rows 4-8 (the ratified repoint/retire table); the one role that table does not
     name (--text-info-subtle) follows the same rule this file already applied to
     --border-success: take the NEXT EXISTING RAMP STOP that clears the worst light
     plane. No hex is invented; the one non-ramp value (--warning-text) is a Figma
     variable minted as a sibling text stop in tokens.css, exactly like --green-text.

       role                    was                  now                plate  bar
       --text-error            error-600 #E22056    error-700 #C4123F  5.0588 4.5 (was 3.8764 FAIL)
       --text-error-strong     error-700 #C4123F    = --text-error     5.0588 4.5 (unchanged value)
       --text-error-subtle     error-500 #F2407B    = --text-error     5.0588 4.5 (was 3.0602 FAIL)
       --text-success          success-700 #008364  green-text #007a5c 4.5028 4.5 (was 4.0026 FAIL)
       --text-success-subtle   success-500 #00C993  = --text-success   4.5028 4.5 (was 1.8140 FAIL)
       --text-positive         green-text #007a5c   = --text-success   4.5028 4.5 (unchanged value)
       --text-warning          warning-700 #AA5813  warning-text #9d5011 4.9408 4.5 (was 4.3100 FAIL)
       --text-info-subtle      info-500 #425FF0     info-600 #2B3DE5   6.1115 4.5 (was 4.2972 FAIL)
       --text-info             info-700 #232CD2     unchanged          7.5067 4.5 PASS throughout

     THREE STOPS COLLAPSE, and that is the ratified intent, not a side effect:
     foundation-colour.md §7 row 8 retires --text-error-strong/-subtle onto
     --text-error ("three error-text stops for one meaning"), row 6 retires
     --text-success-subtle, row 4 retires the --text-positive NAME onto
     --text-success. All four names are KEPT as aliases so no consumer breaks
     (16 files read --text-warning, 21 --text-error, 17 --text-success, 6
     --text-positive). Dark already collapsed each family onto one stop in
     2026-07-29, so the aliases below simply make light behave the way dark
     already did.
     REJECTED for --text-success: --success-800 #006851 (5.7224) has more headroom
     than the ratified #007a5c (4.5028), but §7 row 5 names --green-text explicitly
     and it is the value --text-positive already paints; picking a different stop
     would put two greens back where the ruling just removed one. The 4.5028 cell
     stays this theme's tripwire — see the SURFACE ROLES matrix above. */
  --text-error:          var(--error-700);   /* → #C4123F 5.0588 plate / 5.9907 card — ALL error text (field/checkbox invalid label + helper, rte error copy, description-error). REPOINTED from --error-600 #E22056 (3.8764 plate, 4.1266 page — below AA on all five planes but the card). foundation-colour.md §7 row 7 */
  --text-error-strong:   var(--text-error);  /* DEPRECATED alias, collapsed 2026-08-02 → identical to --text-error #C4123F (its own former value). foundation-colour.md §7 row 8. Do not use in new code */
  --text-error-subtle:   var(--text-error);  /* DEPRECATED alias, collapsed 2026-08-02 → #C4123F. WAS --error-500 #F2407B = 3.0602 plate: it was never an AA small-text value, and "low-emphasis" was the excuse, not a licence. foundation-colour.md §7 row 8. Do not use in new code */
  --text-success:        var(--green-text);  /* → #007a5c 4.5028 plate / 5.3322 card — ALL success text (valid label/helper, typography label, chip labels). REPOINTED from --success-700 #008364 (4.0026 plate, 4.2609 page). foundation-colour.md §7 row 5. NB this is now the SAME value as --text-positive, which is the point of row 4: one green, one meaning */
  --text-success-subtle: var(--text-success);/* DEPRECATED alias, collapsed 2026-08-02 → #007a5c. WAS --success-500 #00C993 = 1.8140 plate / 2.1481 card — the worst text cell in the theme. foundation-colour.md §7 row 6. Do not use in new code */
  --text-warning:        var(--warning-text);/* → #9d5011 4.9408 plate / 5.8509 card — warning/attention text (typography label-warning). REPOINTED from --warning-700 #AA5813 (4.3100 plate, 4.3916 stalled). This is the ratified status-palette v2 value for Waiting (docs/2026-08-01-status-palette-proposal-v2.md §3, §5a: 5.26 page / 4.94 plate — reproduced exactly here); the primitive is minted in tokens.css beside the ramp, same pattern as --green-text */
  --text-info:           var(--info-700);    /* → #232CD2 7.5067 plate / 8.8894 card (typography label-info) — UNCHANGED, passes on every plane */
  --text-info-subtle:    var(--info-600);    /* → #2B3DE5 6.1115 plate / 7.2373 card (typography description-info). REPOINTED from --info-500 #425FF0 (4.2972 plate, 4.3785 stalled). Next existing ramp stop that clears the worst light plane — the same rule this file applied to --border-success. Kept as its own stop rather than collapsed onto --text-info, because unlike the error/success families the two info stops carry a real label-vs-description tier and both now pass */

  /* status BORDERS on controls (non-text UI ⇒ AA 3:1; light == current primitives) */
  --border-error:        var(--error-500);   /* → #F2407B 3.0602 plate / 3.6239 card — resting invalid control edge (field/select/checkbox). Clears 3:1 on every light plane, but by only 0.06 on the plate; foundation-colour.md §7 row 9 (E3) rules it should go to --error-700. NOT this lane's card — it is not below the bar. */
  --border-error-strong: var(--error-600);   /* → #E22056 3.8764 plate / 4.5904 card — invalid hover / checked fill edge */
  /* REPOINTED 2026-08-02 (AA regression lane). WAS --success-600 #00A478, which
     measured 2.6945 on the plate #efeaf3, 2.7455 on the stalled plane and 2.8684
     on the page — three of the five light planes below the WCAG 1.4.11 non-text
     3:1 bar, on the resting edge of a valid control. (It read 3.023 on the OLD
     page #faf8fc, so the plane repoint did not break it, it finished it: the stop
     only ever cleared the bar on the tray and the card.) --success-700 #008364 is
     the next existing ramp stop and the first that clears the WORST light plane:
     4.0026 plate · 4.0783 stalled · 4.2609 page · 4.4910 tray · 4.7398 card.
     No invented hex. Mandated by foundation-colour.md §6.3 E2 and §7 row 11
     ("--border-success | --success-600 #00A478 | REPOINT | --success-700 #008364").
     Rejected alternative: --green #00936f clears the plate at 3.2821 and would have
     preserved a resting/hover split, but it is the LANDING green, not a stop on the
     product success ramp, and 0.28 of headroom on the tightest plane is not a bar
     worth defending. CONSEQUENCE, stated not hidden: the resting and hover valid
     edges now collapse onto one colour in LIGHT — which is already true in DARK,
     where both have resolved to --success-400 #25E2A9 since 2026-07-29. A valid
     field therefore shows no hover change on its edge in either theme. That is
     foundation-colour.md §7 row 12 ("--border-success-strong | RETIRE | collapses
     after 11"); the NAME is kept as an alias below because three components read it
     (text-field.css:175, select.css:450, date-picker.css:423) and those files belong
     to other lanes. */
  --border-success:      var(--success-700); /* → #008364 4.0026 plate / 4.7398 card — resting valid control edge (field) */
  --border-success-strong: var(--border-success);/* DEPRECATED, collapsed 2026-08-02 → identical to --border-success #008364. Kept so existing consumers resolve; do not use in new code. */

  /* SUPPORT tints — subtle status fills/chip backgrounds (Carbon $support-*; the
     -50 tint is the canonical subtle-bg stop). Minted for vocabulary parity so a
     status chip pulls a role, not a raw primitive; light == the -50 tints. */
  --support-error:   var(--error-50);    /* → #FDF2F6 */
  --support-success: var(--success-50);  /* → #EAFFF6 */
  --support-warning: var(--warning-50);  /* → #FEFAEC */
  --support-info:    var(--info-50);     /* → #F0F3FE */

  /* CONTROL FIELD BORDER — resting/disabled edge of inputs & controls.
     Was raw --neutral-300 in 6 components; that opaque neutral fails <3:1 on --deep
     so dark controls lost their edge. Light == --neutral-300 (byte-identical); dark
     repoints to the white-alpha overlay below (same family as --border-strong). */
  --field-border:    var(--neutral-300); /* → #B4BFC7 — resting/disabled control border */

  /* ==========================================================================
     ACCENT ROLES  (→ --primary-500, DECIDED #D342F0 G0-1)
     --------------------------------------------------------------------------
     --accent IS A FILL AND A RING ROLE. IT IS NOT A TEXT ROLE. Stated as an
     interim ban 2026-08-02; RATIFIED BY THE FOUNDER 2026-08-03 (decision #3,
     OPTION A) and no longer interim. The ruling: accent magenta is BANNED as
     small text — links and emphasis that painted `color: var(--accent)` take an
     INK role instead, no new brand colour is minted, and accent KEEPS every
     non-text job (fills, rules, rails including the selected TAB rail, --focus-ring,
     the brandmark petal, the unread dot, icons and other non-text marks, and any
     text at 18.66px or larger). Every pair below is measured here, WCAG 2.x, not
     quoted:

       accent #d342f0 as small text on …          ratio   AA 4.5
       light card #ffffff                         3.6161   FAIL
       light tray #faf8fc                         3.4263   FAIL
       light page #f4f2f6                         3.2508   FAIL
       light stalled #f1ecf6                      3.1114   FAIL
       light plate #efeaf3                        3.0536   FAIL
       accent tint --primary-050 #fdf4ff          3.3683   FAIL
       accent tint --primary-100 #f9e8ff          3.1021   FAIL
       dark page #0f0715                          5.4707   pass
       dark tray #1e1029                          5.0005   pass
       dark plate #241830                         4.6520   pass
       dark stalled #2b1d36                       4.3607   FAIL
       dark card #322639                          3.9453   FAIL
       white #ffffff ON an accent fill            3.6161   FAIL below 18.66px

     SO: the accent fails AA as small text on ALL FIVE light planes, on both accent
     tints, and on the two lowest dark planes; and white-on-accent fails as small
     text too, which means an accent BUTTON's label is only AA at large-text size.
     Nine of the twelve pairs fail. There is no plane on which accent-as-13px-text
     is safe in light, so this is a ban and not a per-component judgement call.

     WHAT TO USE INSTEAD — the OPTION A mechanism, ruled 2026-08-03, no new colour:
       accent-coloured LINK           -> an INK role (--text-secondary at rest,
                                         --text-primary on hover, so hover still
                                         RAISES contrast the way accent→accent-hover
                                         did in both themes) PLUS a permanent
                                         underline, because a link that loses its
                                         colour must still read as a link. The
                                         pattern to copy is detail-list.css
                                         .pm-detail-list__add.
       accent-coloured LABEL          -> --text-primary (or --text-secondary for the
                                         subtle/description tier)
       accent as EMPHASIS / SELECTION -> keep the accent as the fill/rule/ring and
                                         put the ink on --text-primary
       accent BUTTON label            -> white is fine at ≥18.66px / ≥14px bold;
                                         below that the button needs a darker fill
       --accent-hover IS NOT AN ESCAPE HATCH. #bb25d4 is 4.0971 on the plate and
       4.1621 on the --primary-100 tint — it fails AA on three of the five light
       planes, and Option A bans accent-as-text on principle, not on contrast, so
       the accent FAMILY is out of the text lane entirely.
     THE OTHER OPTION WAS DECLINED: foundation-colour.md §7 rows 26-27 proposed
     repointing the LIGHT accent to --primary-700 #9e1bb0 / hover --primary-800
     #6a0085 (measured here at 5.4775 plate · 5.8311 page · 6.4865 card). Conflict
     C3 records the same proposal. The founder chose OPTION A instead on 2026-08-03:
     no new brand colour is minted and the accent VALUE below is UNCHANGED. FD-3 is
     answered by that ruling.
     ========================================================================== */
  --accent:       var(--primary-500); /* → --primary-500 #d342f0 — brand magenta accent [DECIDED #D342F0, G0-1]. FILL / RULE / RING ONLY — never a `color:` on text under 18.66px. RATIFIED BY THE FOUNDER 2026-08-03 (decision #3, Option A) — this is a standing rule, not the interim one it was on 2026-08-02. See the measured ban above */
  --accent-hover: var(--primary-600); /* → --primary-600 #bb25d4 — accent hover/pressed (button gradient bottom) */
  --focus-ring:   var(--primary-500); /* → --primary-500 #d342f0 — focus ring / --tw-ring-color */
  --primary-500-rgb: 211,66,240;      /* raw RGB triplet of --primary-500 (#d342f0 → 211,66,240) for rgba() washes where a token can't carry alpha — e.g. the dropdown current-item dark tint. MIRRORS marketing/m-tokens.css:12 (same 211,66,240) so component + marketing layers agree; not a new colour, just the decimal channels of the existing primitive. */
  --focus-ring-error: var(--shadow-error);   /* → --shadow-error #F2407B halo — invalid-field focus halo; pairs with --focus-ring (full box-shadow value, like --elevation-1/2/3) */

  /* ==========================================================================
     ELEVATION ROLES  (→ the 3 canonical landing shadows)
     ========================================================================== */
  --elevation-1: var(--shadow-soft); /* → --shadow-soft — low lift (soft ambient) */
  --elevation-2: var(--shadow-card); /* → --shadow-card — resting card */
  --elevation-3: var(--shadow-pop);  /* → --shadow-pop — popover / raised emphasis */

  /* ==========================================================================
     RADIUS ROLES
     --------------------------------------------------------------------------
     LADDER MOVED 2026-07-29 (mirrored from Figma, founder-approved). The old
     8px-control / 14px-card split is gone: both collapse to 12px, and a new
     18px TRAY tier appears above them. Provenance and the full Figma mapping
     live in tokens.css (RADIUS section) — this file only names the roles.

     HARD RULE carried down from that section
     (docs/2026-07-26-bridge-watch-direction-spec.html:620): "Any product
     element whose radius reaches half its height is a lint failure." 12px is
     therefore only legal above 24px tall, 18px only above 36px.
     ========================================================================== */
  --radius-hero:    var(--r-lg);   /* → --r-lg 26px — hero/large-card corner (marketing flagship) — UNCHANGED by the 2026-07-29 move */
  --radius-card:    var(--r-md);   /* → --r-md 12px — cards, panels, lists, tables, popovers, toasts. WAS 14px (--r-md → --r-chip) */
  --radius-control: var(--r-sm);   /* → --r-sm 12px — inputs/controls. WAS 8px (--r-sm → --r-ck) */
  --radius-tray:    var(--r-18);   /* NEW 2026-07-29 → --r-18 18px — trays, modals, sheets, carousels. The only tier that went UP. CONSUMER LANDED 2026-08-01: modal.css:129 .pm-modal__panel (the library's one dialog container) — see the migration note below */
  --radius-pill:    var(--r-pill); /* → --r-pill 100px — pill: MARKETING buttons, chips, badges, nav — UNCHANGED */
  /* G0-4: product buttons are rectangles at the control tier; pills are marketing-only */
  --radius-button-product: var(--r-sm); /* → --r-sm 12px — in-product buttons (rectangles, not pills). WAS 8px */
  /* tab-button is the one two-value corner: top 8px, bottom 0. It did NOT follow
     controls to 12px. Use --radius-tab as the whole border-radius shorthand. */
  --radius-tab-top: var(--r-tab-top);        /* NEW 2026-07-29 → 8px — tab-button top corners */
  --radius-tab:     var(--r-tab-top) var(--r-tab-top) 0 0;  /* NEW 2026-07-29 — the full shorthand: 8px 8px 0 0 */

  /* THE MARKS — ROLES NAMED 2026-08-01 (values unchanged since the 2026-07-29
     mirror; see tokens.css --r-rail/--r-rule/--r-focus for provenance).
     These are what the HARD RULE above leaves room for and the ladder did not:
     under 24px tall there is NO legal tier, so a short box has to be either grown
     past 24px or demoted to a mark. Both moves are now expressible.
     WHEN TO REACH FOR WHICH — the deciding question is "is this a box?":
       a real target that happens to be short (icon link, chip, strip)  -> GROW it
             past 24px with padding and keep --radius-control; that also buys the
             WCAG 2.5.8 24px floor, so it is the preferred fix.
       inline TEXT with a focus ring and no box of its own              -> --radius-focus
       a tick / bar / rail that IS a mark                               -> --radius-rule (or --radius-rail) */
  --radius-focus:   var(--r-focus); /* → 3px — focus ring on a text link; the link is not a control box */
  --radius-rule:    var(--r-rule);  /* → 2px — ticks and marks (checkbox tick box, skeleton--sm bar) */
  --radius-rail:    var(--r-rail);  /* → 1px — progress rails and 1-2px bars */
  /* MIGRATION STATUS (updated 2026-08-01, components/ side):
       DONE  modal.css:129 .pm-modal__panel  --radius-card → --radius-tray 18px.
             It is the only tray/modal/sheet/dialog CONTAINER in components/ —
             image-crop-modal renders INSIDE this panel and owns no corner, and
             there is no sheet/drawer/carousel component yet.
       DONE  tab-button/tab-button.css:58-59 now reads --radius-tab-top (8px).
       STAYS select.css:214, dropdown.css:94, location-search.css:140 and
             date-picker.css:397 are popovers/combobox lists, not trays — they
             correctly stay on --radius-card 12px. toast.css:173 likewise. */

  /* ==========================================================================
     MOTION ROLES  (→ the 2 canonical easings)
     ========================================================================== */
  --motion-standard: var(--ease);        /* → --ease cubic-bezier(0.22,0.61,0.18,1) — primary ease-out */
  --motion-spring:   var(--ease-spring); /* → --ease-spring cubic-bezier(0.34,1.32,0.46,1) — overshoot spring */
  --motion-duration: 150ms;              /* canonical component transition duration (100-250ms band) — minted R1 component loop 2026-07-07; components consume var(--motion-duration, 150ms) */
  --motion-enter: var(--ease-decelerate); /* → decelerate — elements appearing (open/reveal/in); separate role from --motion-standard so enters can diverge later (M0 specC) */
  --motion-exit:  var(--ease-accelerate); /* → accelerate — elements leaving (close/dismiss/out); the M3 fix — exits were backwards on ease-out (M0 specC) */
  --motion-dur-fast:     var(--motion-fast, 100ms);     /* micro / exit tier */
  --motion-dur-moderate: var(--motion-duration, 150ms); /* standard component tier (keeps existing 150ms alias) */
  --motion-dur-slow:     var(--motion-slow, 250ms);     /* expand/collapse tier */

  /* ==========================================================================
     DARK-SECTION ROLES
     ========================================================================== */
  --dark-bg:   var(--deep);  /* → --deep #0f0715 — dark-section base background (was #0b0410 before the 2026-07-29 plane move) */
  --dark-text: var(--white); /* → --white #ffffff — text on dark-section background */

}

:root{--shadow-lip: 0 -10px 30px 5px rgba(28,12,40,.10); /* dashboard folder lip (R3 mint) */
  --shadow-thumb:0 1px 2px rgba(28,12,40,.18),0 0 0 0.5px rgba(28,12,40,.08)}

:root{--dur-control:150ms; --dur-wash:120ms;--dur-exit:100ms}

/* ==========================================================================
   DARK THEME — single-swap repoint (M1). Every value is an existing primitive
   from tokens.css (RULE OF PROVENANCE). Applying [data-theme="dark"] to any
   ancestor flips all role aliases at once (Carbon theme-swap principle).
   Borders repoint to white-alpha overlays: opaque neutrals fail <3:1 on --deep.
   Radii and motion are theme-invariant — untouched here.
   ========================================================================== */
[data-theme="dark"] {
  /* THE FIVE PLANES — dark half of the role set minted in :root above. Values are
     the 2026-07-29 founder-approved ladder verbatim; nothing here is new colour and
     nothing here changes what any existing component renders. The matrix that proves
     all 15 ink×plane pairs clear AA on these five is in tokens.css (DEEP section):
     worst case 5.10:1, --text-muted on the card. */
  --surface-page:    var(--deep);      /* #0f0715 */
  --surface-tray:    var(--deep-2);    /* #1e1029 */
  --surface-plate:   var(--deep-4);    /* #241830 — had NO role until now ("No CSS role consumes it yet", tokens.css) */
  --surface-stalled: var(--deep-5);    /* #2b1d36 — had NO role until now */
  --surface-card:    var(--deep-6);    /* #322639 */

  --bg:            var(--surface-page); /* #0f0715 — surface/page. BYTE-IDENTICAL to the previous var(--deep); rewritten only so page has ONE flip point shared with the light theme. WAS #0b0410 (2026-07-29 plane move) */
  --surface-1:     var(--deep-2);      /* #1e1029 — surface/tray, layer-01 (lighter than bg, Carbon dark rule). WAS #150a1d */
  --surface-2:     var(--deep-6);      /* #322639 — surface/card, layer-02. REPOINTED 2026-07-29 from --deep-3, and it had to be: after the plane move --deep-3's old literal #1e1029 IS the new tray value, so leaving it here would paint layer-01 and layer-02 the same hex and collapse the card off the tray. --deep-6 is the card plane foundation-colour.md:157 already assigns to --surface-2, and the plane the contrast matrix measures as worst case (5.10:1, muted). NB this is a VISIBLE change: dark cards go #1e1029 -> #322639. */
  --surface-disabled: var(--neutral-800); /* #2A2F38 — muted dark disabled fill (M1 Amir decision: disabled no longer leaks the light #ECF0F3 box in dark; reads inert vs the purple-black surfaces) */
  --skeleton: rgba(255,255,255,.09); /* subtle light overlay — reads as a placeholder on any deep surface (light #D9E1E5 would glare white on dark) */

  --border:        rgba(255,255,255,.08); /* = --border-on-dark-shell alpha; hairline */
  --border-strong: rgba(255,255,255,.14); /* = --border-on-dark-card alpha */

  /* INK vs THE FIVE PLANES — re-measured 2026-07-29 against the new ladder
     (the old numbers here were measured against #0b0410/#150a1d/#1e1029 and no
     longer describe anything). Format below: page … card, card being worst. */
  --text-primary:   var(--white);        /* #ffffff 19.78 · 18.08 · 16.82 · 15.77 · 14.27 (was "20.21 on deep") */
  --text-secondary: var(--neutral-300);  /* #B4BFC7 10.57 · 9.66 · 8.99 · 8.42 · 7.62 (was "10.8") */
  --text-muted:     var(--neutral-400);  /* #909CA8 7.07 · 6.46 · 6.01 · 5.64 · 5.10 — the worst pair in the whole dark theme, and still AA (was "7.22"). neutral-500 #6F7A8A stays rejected: 3.28 on card */
  --text-on-dark:   var(--white);
  --text-positive:  var(--text-success); /* DEPRECATED alias → --green-bright #00c993 9.2093 · 8.4178 · 7.8311 · 7.3408 · 6.6415 (was "8.94"; green-text #007a5c is 3.3912 on the dark tray and 2.6756 on the dark card, so it still fails on dark). Re-pointed onto --text-success 2026-08-02 so the retired name has ONE flip point in both themes; value byte-identical */

  /* STATUS ROLES — repoint to a lighter EXISTING ramp stop that clears WCAG on the
     deep surfaces. Light -700/-600/-500 stops FAIL on dark (e.g. success-700 #008364
     = 3.82 border-only, fails as text; info-700 #232CD2 = 2.03 tray / 1.60 card —
     the "~1.3" written here before 2026-07-29 was never right at any plane). No invented hex — only
     ramp stops already in tokens.css. Mirrors the button dark rule "hover LIGHTENS
     on dark → -400".
     RE-MEASURED 2026-07-29. The numbers previously written here were all against
     #1e1029 — which is now the TRAY plane, so they survive as the tray column. The
     worst plane a status token can land on is no longer tray but CARD #322639
     (--surface-2 repointed above), so each row now states tray / card.
     ONE ROW NO LONGER CLEARS AA ON CARD: --text-info/-subtle info-400 = 4.31 on
     #322639. It was 5.46 when the worst plane was #1e1029. This is a real,
     measured consequence of the approved ladder, NOT something to quietly fix by
     inventing a stop — info-300 #96B0FA would clear it and is not part of the
     approved change. Flagged, not patched. */
  /* 2026-08-02: the three deprecated names now read their base role instead of
     repeating the primitive. BYTE-IDENTICAL — dark had already collapsed each
     family onto one stop on 2026-07-29; this only removes the second flip point,
     so light and dark retire the same names in the same way. */
  --text-error:          var(--error-400);   /* #F96D9F 6.64 tray / 5.24 card (was error-600, 3.94 FAIL) */
  --text-error-strong:   var(--text-error);  /* DEPRECATED alias → #F96D9F 6.64 / 5.24 (error-700 fails harder) */
  --text-error-subtle:   var(--text-error);  /* DEPRECATED alias → #F96D9F 6.64 / 5.24 (error-500 4.99 tray but 3.94 card; -400 unified) */
  --text-success:        var(--green-bright);/* #00c993 8.42 / 6.64 (success-700 3.82 FAIL) */
  --text-success-subtle: var(--text-success);/* DEPRECATED alias → #00c993 8.42 / 6.64 */
  --text-warning:        var(--warning-400); /* #F0C442 10.92 / 8.61 (warning-700 fails). Dark is UNAFFECTED by the light --warning-text #9d5011 repoint: measured, that stop reads 3.0906 on the dark tray and 2.4384 on the dark card, so it would fail AA here — which is why the light fix is a light-only repoint and this line still reads -400 */
  /* FIXED 2026-07-29. info-400 #6587F5 measured 4.31:1 on the new card plane
     #322639 — below AA. It passed at 5.46 only while the tray was the darkest
     plane a status text landed on; the purpler ladder moved the floor.
     info-300 is the next existing stop and clears every plane:
       card 6.72 · stalled 7.42 · plate ~7.9 · tray ~8.5 · page ~9.3
     No invented hex — info-300 is already in the ramp (tokens.css:183). */
  --text-info:           var(--info-300);    /* #96B0FA 6.72 on card (was info-400, 4.31 FAIL) */
  --text-info-subtle:    var(--info-300);    /* #96B0FA 6.72 on card — same fix */
  /* transport-mode on dark — D5. Same repointing as light: the -400 stops, which
     are the ones already proven on the deep surfaces above. Matches Figma
     mode/sea #6587F5, mode/land #25E2A9, mode/air #F96D9F exactly. */
  --mode-sea:  var(--info-400);     /* #6587F5 5.46 tray / 4.31 card (re-measured 2026-07-29) */
  --mode-land: var(--success-400);  /* #25E2A9 10.79 / 8.51 */
  --mode-air:  var(--error-400);    /* #F96D9F 6.64 / 5.24 */
  --mode-road: var(--mode-land);    /* DEPRECATED alias for --mode-land. */

  /* status control borders on dark (≥3:1 non-text — all four still clear it on
     every one of the five planes; re-measured 2026-07-29, card is worst) */
  --border-error:          var(--error-400); /* #F96D9F 6.64 tray / 5.24 card (error-500 4.99/3.94; -400 for parity w/ text) */
  --border-error-strong:   var(--error-400); /* #F96D9F 6.64 / 5.24 */
  --border-success:        var(--success-400);/* #25E2A9 10.79 / 8.51 (success-600 ok; -400 brighter signal) */
  --border-success-strong: var(--success-400);/* #25E2A9 10.79 / 8.51 */

  /* support tints on dark — the light -50 pastels are near-white and blow out on
     deep; repoint to the deep-900 status stops (subtle dark-tinted fills, existing
     ramp). Only consumed once a status chip adopts --support-*; kept airtight now. */
  --support-error:   var(--error-950);   /* #530416 subtle dark red fill */
  --support-success: var(--success-950); /* #003027 subtle dark green fill */
  --support-warning: var(--warning-950); /* #411D07 subtle dark amber fill */
  --support-info:    var(--info-950);    /* #191A52 subtle dark blue fill */

  /* resting/disabled control edge on dark — the white-alpha overlay (opaque
     neutral-300 #B4BFC7 would sit ~1.1:1 muddy). Same overlay family as
     --border-strong (.14) so a control edge stays as visible as an emphasis edge. */
  --field-border:    rgba(255,255,255,.14);

  --accent:        var(--primary-500);   /* #d342f0 — brand hue theme-stable. FILL / RULE / RING ONLY — never a `color:` on text under 18.66px; RATIFIED BY THE FOUNDER 2026-08-03 (decision #3, Option A) — a standing rule now, not the interim one it was on 2026-08-02. DARK IS NOT EXEMPT: accent-as-text passes on the three highest dark planes, but Option A bans accent-as-text on principle rather than on contrast, so dark links and dark labels take the same INK role as light ones and there is no dark-only accent-text override anywhere in the kit. See the measured twelve-pair ban at the ACCENT ROLES block in :root. Re-measured 2026-08-02 against the five dark planes: 5.4707 page · 5.0005 tray · 4.6520 plate · 4.3607 stalled · 3.9453 CARD — so accent-as-small-text fails on the two lowest dark planes as well as on all five light ones. (2026-07-29 wrote "5.47 / 5.00 / 3.95" for page/tray/card; those three reproduce, the two middle planes were simply never printed. The older "5.31:1" was against the retired #0b0410.) */
  --accent-hover:  var(--primary-400);   /* #e26bff 7.33 page / 5.29 card — hover LIGHTENS on dark */
  --focus-ring:    var(--primary-500);

  /* QA-fix 2026-07-09: 3 DISTINCT dark tiers (was: 1 & 2 identical → collapsed on
     the black canvas). Black shadows barely read on dark, so each tier adds a
     growing hairline top-light ring — the standard dark-elevation cue. */
  --elevation-1:   0 1px 3px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.03);
  --elevation-2:   0 8px 24px -8px rgba(0,0,0,.6), 0 0 0 1px rgba(255,255,255,.06);
  --elevation-3:   0 18px 44px -12px rgba(0,0,0,.72), 0 0 0 1px rgba(255,255,255,.09);
}
