/* ============================================================
   Alleaves Design System v2 — design tokens
   ------------------------------------------------------------
   The single source of truth for the redesign's color, type,
   spacing, radius, elevation and motion.

   >> PROVENANCE — READ THIS BEFORE TRUSTING A VALUE. <<
   These tokens were ORIGINALLY transcribed from the `_ds_v2` canvas
   on the assumption it mirrored the PROTOTYPE. It does not — `--al-pad-cell`
   was a pure fabrication (axes transposed, 0 uses). But the FIRST re-mine
   (T10) then read only the TRUNCATED 262KB prototype and introduced its own
   errors — e.g. it "corrected" `--al-shadow-lg` AWAY from its real value.
   The full 1.7MB prototype now lives at
   `.specs-local/design/alleaves-platform-redesign/project/` and every token is
   being re-baselined against it in Phase 2 with the verifier at
   `.specs-local/tools/token-verify.js` (P2-T1). Markers: [P:n] mined (n = real +
   VM uses in the full file) · [OURS] our decision · [UNVERIFIED] no basis.
   THE PROTOTYPE IS THE AUTHORITY. `_ds_v2` is not evidence of anything.

   >> THE PROTOTYPE HAS A TEMPORAL SEAM (~line 855). <<
   The designer refined as they authored and never backfilled. Four unrelated
   properties flip at one boundary (primary weight 600->700; danger fill
   #c0463f->#b23b39; danger border -> #e7c7c2; danger label -> #b23b39).
   Three of the four have ZERO exceptions either side; the fourth has 3 —
   strong evidence, not perfect. Meanwhile the secondary button's weight
   deliberately does NOT change, which is what proves refinement rather than
   intent. THE LATE VALUE WINS. Our original tokens were transcribed from the
   stale side.
   >> SCOPE: the seam governs the destructive BUTTON. It says nothing about
   other roles — see --al-error-47, where over-applying it destroyed a
   confirmed value.

   >> VERIFICATION MARKERS. Tokens carry one of these where their provenance
      is known or contested (roughly 60 uncontroversial scale steps — the
      space/radius ramps — are unmarked): <<
     [P] / [P:n]  mined from the prototype (present, and dominant for the role
                  the comment claims). The number n is INDICATIVE only — a
                  snapshot from when the token was last checked, and many are
                  stale/understated. For the EXACT count and the role breakdown,
                  run the verifier: node .specs-local/tools/token-verify.js
                  It is the deterministic source of truth for counts; the inline
                  n is not, and must not be trusted as precise.
     [UNVERIFIED]  zero basis in the reachable prototype — inherited from
                   _ds_v2. (There should be NONE left after the P2 re-baseline.)
     [OURS]  a deliberate decision we made because the prototype is
             structurally silent (it is a static mockup: 0 :hover rules,
             0 :active, 1 :focus). Ours to own, not the design's.
   The prototype is TRUNCATED at 256KiB, so absence never proves absence.

   NAMESPACE: every token is prefixed `--al-` (Alleaves) so it can
   never collide with the POS / Go React bundles' own custom
   properties (they share the same DOM).

   Two tiers:
     1) Primitives  — raw ramps (--al-primary-45, --al-neutral-10 …)
     2) Semantics   — role aliases (--al-accent-primary, --al-text-body …)
   COMPONENTS CONSUME THE SEMANTIC ALIASES, never a raw hex/primitive.
   That is what makes "change the green" one line — and what will make
   a future dark theme a single scoped override of the aliases.

   Loaded once in the controller <head> (_layout / _layout_fullscreen /
   _spa_layout). Because the POS + Go React apps mount in the SAME
   document (a <div>, not an iframe), these :root vars cascade into
   them too — they consume var(--al-…) with no value duplication.
   ============================================================ */

:root {
	/* ========================================================
	   1 · COLOR PRIMITIVES  (raw ramps — do not use in components)
	   ======================================================== */

	/* ---------- Brand: Emerald (PRIMARY) ---------- */
	--al-primary-35: #0f5f3f; /* [OURS] 0 real uses — the prototype specifies no
	                              hover for any filled button, so this rung backs
	                              the decided --al-accent-primary-hover. Not a
	                              phantom; a deliberate derived value. */
	--al-primary-45: #157a52; /* [P:124] PRIMARY — the anchor of the system  */
	--al-primary-54: #1e9268; /* [P:4] rail expand badge                    */
	--al-primary-71: #5cc28e; /* 0 consumers. The active-on-dark role moved to
	                              --al-ref-emerald-300 so it follows the brand ramp. */
	--al-primary-95: #e9f4ef; /* [P] tint — icon chip bg, ghost hover fill   */
	--al-primary-98: #f3faf6; /* [P:5] faintest wash                         */
	--al-primary-86: #bfe0d0; /* [P] border on tinted surfaces            */
	--al-primary-border-interactive: #9ccbb5; /* [P:3, zero variance] the
	       outlined-button border. Sits exactly between emerald-400 and
	       emerald-border — a real rung the ramp was missing. */

	/* 0 consumers. rgb(from var(--al-accent-primary) r g b / a) chains to the
	   live brand; a frozen channel triple cannot. */
	--al-accent-primary-rgb: 21, 122, 82;

	/* ---------- Ink (cool slate — text + dark chrome) ---------- */
	/* 0 consumers. The dark chrome sat on this literal; it chains to the recipe's
	   slate ramp now so a theme can steer it. Kept, unreferenced, for the hygiene
	   pass that clears the ramp's orphans in one go. */
	--al-neutral-6: #0f1622;
	--al-neutral-7: #101720; /* [P:21] near-black text (full file; the truncated
	                          read wrongly showed 0)                       */
	--al-neutral-10: #161b24; /* [P] STRONG text / headings                   */
	--al-neutral-14: #1e2530; /* [P:63] text (truncated read showed 0)        */
	--al-neutral-20: #27313c; /* [P:37] body-strong text                      */
	--al-neutral-29: #3d4550; /* [P] DEFAULT body text                        */
	--al-neutral-41: #54607a; /* [P:30] text (truncated read showed 0)        */
	--al-neutral-48: #6b7480; /* [P] muted / secondary text                   */
	--al-neutral-60: #8a92a0; /* [P:171] faint / icon                         */
	--al-neutral-66: #98a0ab; /* [P:7] icon grey                              */
	--al-neutral-83: #cbd0d8; /* [P:30] the FAINTEST text grey — breadcrumb
	       separators, disabled pagination chevrons (text:25, bg:0). NOT the same
	       as --al-neutral-84 #cdd2db, which is a SURFACE grey (bg/border + the
	       scrollbar thumb, text:0). Two units apart, two different roles — do
	       not collapse them. */
	--al-neutral-73: #aeb4be; /* [P:50] the HEX appears 50x as muted text. But the
	                          "placeholder / disabled" ROLE is still NOT sourced
	                          from the prototype: it has zero ::placeholder rules,
	                          so #aeb4be-as-placeholder is our inference. ~1.9:1
	                          on white. */

	/* ---------- Neutrals (cool gray — surfaces + borders) ---------- */
	--al-neutral-100: #ffffff;
	--al-neutral-99: #fafbfc; /* [P] raised card wash                         */
	--al-neutral-98: #f8f9fb; /* [P] table header, sunken panels             */
	--al-neutral-96: #f2f4f6; /* [P:8] was #f3f5f8 [0 uses] — repointed to the
	                           real fourth divider grey                     */
	--al-neutral-95: #eef0f3; /* [P:71] subtle divider / row hairline        */
	--al-neutral-92: #e4e7ec; /* [P] DEFAULT card border                     */
	--al-neutral-86: #d3d8e0; /* [P] input border / strong hairline          */
	--al-neutral-84: #cdd2db; /* [P] scrollbar thumb                         */
	--al-neutral-97: #f5f6f8; /* [P] app canvas behind cards                   */
	--al-surface-addon-bg: var(
		--al-sys-color-surface-sunken
	); /* [P:6] input affix. TRAP: one hex digit
	       from --al-neutral-97 #f5f6f8. Unrelated roles — do not "fix" it. */

	/* ---------- Danger (cool red) ---------- */
	/* THE SEAM applies to the destructive BUTTON only. The settled button red is
	   #b23b39 (post-seam: 4 fills + 5 labels); #c0463f appears once as a fill,
	   pre-seam, on the only filled button in the file whose border matches its
	   own background. So #b23b39 wins FOR THE BUTTON.
	   But #c0463f is NOT a draft to be deleted — it has 12 uses file-wide,
	   including a POST-seam one (L1680), and it is the exact, confirmed colour
	   of the KPI down-delta (L377/L379: `text-align:right; color:#c0463f">50%`).
	   The seam says nothing about a KPI delta. An earlier pass deleted this
	   primitive and repointed --al-delta-down onto #b23b39 — replacing a
	   confirmed value with one the design never uses for that role. */
	/* >> DANGER, RE-BASELINED ON THE FULL FILE (P2-T5). The whole family had been
	   built (T10, then T2) on the "temporal seam" — which the full 13,317-line
	   file proves was an ARTIFACT of the truncated read. By role across the whole
	   design: #c0463f dominates everything (bg 16, text 92, border 19 = 138),
	   #b23b39 is a minor darker variant (bg 4, text 12 = 30), #e3a9a5 is THE
	   border (31, all border), #fbeceb the bg. So #c0463f is the danger red
	   (fill AND text; white on it = 5.01:1 AA, and the design uses white on it
	   ×15), #b23b39 is the darker hover rung, #e3a9a5 the border. This is the
	   ORIGINAL _ds_v2 structure; T10 inverted it on partial data. */
	--al-error-47: #c0463f; /* [P:138] THE danger — fill AND text          */
	--al-error-43: #b23b39; /* [P:30] darker rung — the solid button's hover */
	--al-error-74: #e3a9a5; /* [P:31] border. Reverted from #e7c7c2 [P:8],
	                             which T2 chose off the false seam            */
	--al-error-95: #fbeceb; /* [P:12] bg                                   */

	/* ---------- Warning (amber) ---------- */
	/* >> THE PROTOTYPE HAS *THREE* SEPARATE AMBER TRIADS, NOT ONE SCATTERED
	   ROLE. Each is internally consistent — the design never mixes them:
	     A · badge/chip : bg #fbf1dd [4] + fg #9a6a12 [3] + border #ecd6a3 [2]
	     B · callout    : bg #fdf6e3 [1] + fg #8a6d1e [1] + border #f0dca8 [2]
	     C · expired    : bg #f6ecd9 [3] + fg #8a5a14 [2] + border #e2c893 [1]
	   C is tokenised separately below as --al-expired-*.
	   This group is TRIAD B (callout/alert). The badge tier is --al-warn-badge-*.
	   An earlier pass assembled one chimeric ramp out of parts of A and B, so
	   warning-bg + warning-fg painted a pairing that occurs ZERO times in the
	   design. Keep each triad whole; never pair across them. */
	--al-warning-48: #8a6d1e; /* [P:1] callout fg. Was #9a6a00 — which has
	       ZERO uses: an invented value, the exact sin this file exists to fix */
	--al-warning-55: #b07823; /* [OURS] hover for the SOLID warning button —
	       the design has no warning-button hover, so this is derived:
	       --al-warning-62 shifted by the delta our primary's own hover uses
	       (L −6.5, S +2.1). (Danger's hover, by contrast, is a REAL design value,
	       #b23b39; warning/info have none, so theirs are derived.) Every solid
	       tier has its own hover rung so .btn-*:hover never borrows the fg. */
	--al-warning-62: #c98a2b; /* [P] icon / accent / solid                */
	--al-warning-88: #f0dca8; /* [P:2] callout border — L1559 (on the #fdf6e3
	       callout bg), L1640 (on #fff). NOT a coin flip against #ecd6a3, as an
	       earlier comment here wrongly claimed: the two are borders of DIFFERENT
	       components and the prototype never mixes them (#ecd6a3 sits only on
	       the #fbf1dd badge, 2/2). Both of these are also POST-seam, so the seam
	       endorses them too. There was no coin to flip — it was a role split. */
	--al-warning-97: #fdf6e3; /* [P:1] callout bg. Was #fdf5e3 — one hex digit
	                              off; nobody chose that, the provenance broke */

	/* ---------- Warning · badge tier (TRIAD A — keep whole) ---------- */
	/* The most-evidenced amber in the design (9 data points vs the callout's 4),
	   and it had no tokens at all. This is the "Low stock" / "Low threshold"
	   chip — the sibling swatch to --al-expired-* in the prototype's own legend,
	   which renders the two side by side precisely to distinguish them. */
	--al-warn-badge-bg: var(--al-sys-color-status-warning-tint); /* [P:4]                                   */
	--al-warn-badge-fg: var(--al-sys-color-status-warning-text); /* [P:3]                                   */
	--al-warn-badge-border: var(--al-sys-color-status-warning); /* [P:2]                               */

	/* ---------- Info / Link (blue) ---------- */
	/* The info ramp IS real (the full prototype has it; the truncated read is
	   what showed "0 uses"). Blue is SECONDARY in this green system and it DRIFTS
	   — the design uses ~5 blues (#1667c9 ×7, #2a6fdb ×6, #2563c9 ×5, #2563b6 ×4,
	   #2f6fd0 ×3) for roughly one idea. The values below are the coherent
	   info-CALLOUT set (bg #eaf1fb + border #cfe0f7 + text) actually found in the
	   file; #2563c9/#2a6fdb are confirmed. The other blues are drift, not roles. */
	--al-info-42: #1f60c5; /* [OURS] hover for the solid info button, derived by
	       the primary's hover delta. The prototype has no info hover; ours. */
	--al-info-44: #2563c9; /* [P:5] info text / icon (the design also drifts to
	                           #1667c9 for links — see note above)             */
	--al-info-48: #2a6fdb; /* [P:6] solid blue (info button bg)              */
	--al-info-89: #cfe0f7; /* [P] info-callout border. Was #c4d8f5 [0 uses] —
	                           corrected to the real border found beside the bg  */
	--al-info-95: #eaf1fb; /* [P:3] info-callout bg. Was #eaf1fc — one digit off,
	                           0 uses; the real light-blue callout bg is #eaf1fb  */

	/* ---------- Expired (amber, distinct from warning) ---------- */
	/* [P] The prototype ships a legend rendering two amber swatches SIDE BY
	   SIDE, labelled "Expired" vs "Low threshold". Collapsing them onto the
	   warning ramp destroys information the design deliberately conveys. */
	--al-expired-94: #f6ecd9;
	--al-expired-42: #8a5a14;
	--al-expired-82: #e2c893;

	/* >> INFO BADGE TIER (P4-T5). Same split the amber triads already document:
	   the PILL blue is not the CALLOUT blue.
	     badge/chip : bg #e8f0fb + fg #2a6fdb   (4 measured pill instances)
	     callout    : bg #eaf1fb                (--al-info-95, above)
	   Two hex digits apart, two different roles. Measured by rendering the
	   prototype, not mined: node .specs-local/tools/design-measure.js buttons
	   The fg is --al-info-48 (#2a6fdb) exactly, so only the bg is new here. */
	--al-info-badge-bg: var(--al-sys-color-status-info-tint); /* [P:4] pill blue — NOT --al-info-95      */

	/* [P9-STA-LOUD-POS #5] the POS 'loud' status values — tokenized but kept LOUD (Jeff's
	   call). Purple collapses the two drifted purples (#8567b6 / #9b59b6) to one; the loud
	   amber is the bright caution flag (residency/SALE), always paired with ink-800 text. */

	/* ========================================================
	   2 · COLOR SEMANTIC ALIASES  (PREFER THESE in components)
	   ======================================================== */

	/* text */
	/* THE SHIM. These 65 declarations no longer hold values; they point at the recipe.
   Every one of the 2,640 var(--al-*) uses across 180 files moves with the recipe from
   here, without a single template being edited. It is SCAFFOLDING, not a second naming
   system: each page pass replaces old names with recipe roles, the count only ever
   falls, and when it reaches zero this whole file is deleted.

   COLOUR AND FONT WEIGHT ONLY, deliberately. Font size, line height, icon size, spacing,
   padding and radius all move layout, and a layout change wants eyes on it, so they stay
   page-pass work. The effect is intended: a conformed page and an unconformed one share
   a palette, and the unconformed one reads as UNFINISHED rather than broken. */
	--al-text-body: var(--al-sys-color-text-primary);
	--al-text-body-strong: var(
		--al-sys-color-text-primary
	); /* [P:37] 37 places previously
	       had no alias to reach for — i.e. 37 invitations to break the
	       "never consume a primitive" rule. */
	--al-text-strong: var(--al-sys-color-text-primary);
	--al-text-muted: var(--al-sys-color-text-secondary);
	--al-text-faint: var(--al-sys-color-text-muted);
	--al-text-icon: var(--al-sys-color-text-muted); /* [P:7] icon grey — was a primitive
	                                      with no semantic name */
	--al-icon-faint: var(--al-sys-color-text-muted); /* [BEDROCK C#5] faint decorative/disabled/empty-state icon foreground */
	--al-text-placeholder: var(
		--al-sys-color-text-placeholder
	); /* [P] value real (see ink-200);
	                                             the placeholder ROLE is inferred */
	--al-text-on-dark: var(
		--al-nav-text
	); /* on-dark bright text — same role as
	       the sidebar's. Was #e9ebef, which is actually a light-card DIVIDER, not
	       on-dark text; realigned to the real on-dark text value. */
	--al-text-on-dark-muted: #9aa3b4; /* [P:n=1] thin                       */
	--al-text-link: var(
		--al-sys-color-accent-primary-line
	); /* EMERALD link (Foundations #7) — was info-blue; note MOST links in
	       this green system are the accent (#157a52); blue is for specific ones.
	       The design's clearest link blue is #1667c9; we alias the info fg. */
	--al-text-heading-accent: var(--al-sys-color-accent-primary-line);
	--al-text-separator: var(
		--al-sys-color-border
	); /* [P:30] #cbd0d8 — breadcrumb
	       separators + disabled chevrons. Lighter than --al-text-faint.       */

	/* surfaces */
	--al-surface-canvas: var(--al-sys-color-surface-page);
	--al-surface-card: var(--al-sys-color-surface);
	--al-surface-raised: var(--al-sys-color-surface-raised);
	--al-surface-sunken: var(--al-sys-color-surface-sunken);
	--al-surface-nested: var(
		--al-sys-color-surface-sunken
	); /* [Cards #1] nested entry cards inside a white card — distinct from canvas/sunken so nesting reads even on the canvas */
	--al-surface-addon: var(--al-sys-color-surface-sunken); /* input affix           */
	--al-surface-nav: var(--al-nav-bg);
	--al-surface-nav-active: var(--al-ref-slate-900); /* active sidebar item fill */

	/* nav / dark chrome (sidebar + on-dark surfaces)

	   THIS GROUP CHAINS TO THE NEUTRAL RAMP, and that is the point of it. It used to
	   be --al-neutral-6 (#0f1622) and five raw hexes beside it: a second, private
	   dark palette that no theme could reach. Repointing the neutrals repainted the
	   whole product and left the sidebar the colour it had always been, which is
	   exactly the failure the --al-nav-active-fg note below describes for the accent.
	   A ramp you cannot steer is folklore, not a token.

	   The ramp has four rungs at the dark end and this group wants five values, so
	   the flyout — the one step the ramp genuinely has no rung for — is a mix of the
	   two either side of it rather than a sixth literal. Everything else lands on a
	   real rung, and the two that landed on the same one (the raised panel and the
	   active row fill) were three points apart to begin with.

	   The ladder, darkest first: ground -> flyout -> panel/active -> border. */
	--al-nav-bg: var(--al-ref-slate-950);
	--al-nav-raised: var(--al-ref-slate-900);
	--al-nav-active-bg: var(--al-surface-nav-active);
	--al-nav-child-active-bg: rgb(from var(--al-accent-on-dark) r g b / 0.14); /* [P] active CHILD row = emerald WASH (Proto:9990), not the dark item fill */
	--al-nav-border: var(--al-ref-slate-800);
	/* TWO on-dark text values, and they are DIFFERENT ROLES — do not collapse them.
	   P2-T6 did exactly that (pointed nav-text at #f0f2f6 because it "won" the
	   on-dark-text plurality) and silently shifted the account name, which the
	   design puts at #e6e9ef. Worse, the location title was already getting
	   #f0f2f6 from a hardcoded hex, so the token change bought nothing and only
	   broke .acct-name. Plurality never crosses a role boundary. */
	--al-nav-text: #e6e9ef; /* [P:1] the ACCOUNT NAME on dark (Proto:96)      */
	--al-nav-text-bright: #f0f2f6; /* [P:4] the brighter on-dark label — location
	       title (Proto:45) + active nav labels. Replaces a raw hex in _sidebar.css */
	--al-nav-text-muted: #9aa3b4;
	--al-nav-text-faint: #6b7689;
	--al-nav-header: #566074;
	/* rail flyout — a DISTINCT surface, not the sidebar's. It floats above the dark
	   chrome and sits between the sidebar's ground and the raised panel, with a
	   heavier shadow and brighter row text. Same reasoning as the account menu's own
	   shadow: a panel overlaying dark chrome needs more separation.
	   (Prototype.html:104-110) */
	--al-nav-flyout-bg: color-mix(in srgb, var(--al-ref-slate-900) 45%, var(--al-ref-slate-950));
	--al-nav-flyout-border: var(--al-ref-slate-800); /* panel border            */
	--al-nav-flyout-header: #5a6478; /* [P] its uppercase label — a touch lighter
	       than --al-nav-header, because it sits on the darker panel            */
	--al-nav-flyout-text: #cdd3de; /* [P] row text — brighter than the sidebar's
	       --al-nav-text-muted, for the same reason                             */
	--al-nav-flyout-dot: var(--al-ref-slate-700); /* inactive row dot            */
	--al-nav-flyout-active-bg: rgb(from var(--al-accent-on-dark) r g b / 0.16); /* [P] active row fill */
	--al-nav-flyout-hover-bg: rgba(255, 255, 255, 0.06); /* [P] row hover       */
	/* chain to the SEMANTIC accent, not the emerald primitive — otherwise the
	   sidebar's active colour is a second, unsteerable name for the same idea
	   and "change the brand in one place" quietly stops being true */
	--al-nav-active-fg: var(--al-accent-on-dark);

	/* borders */
	--al-border-subtle: var(--al-sys-color-border); /* folded #eef0f3 → #e4e7ec: ONE hairline (decision A, 2026-08-13) */
	--al-border-default: var(--al-sys-color-border);
	--al-border-input: var(--al-sys-color-border-control);

	/* border widths — 2px is the tab active indicator; it was a magic number */
	--al-bw-1: 1px;
	--al-bw-2: 2px; /* [P:6] tab active indicator                            */

	/* ---------- THE primary accent (single source of truth) ---------- */
	--al-accent-primary: var(--al-sys-color-accent-primary);
	--al-accent-primary-hover: var(
		--al-sys-color-accent-primary-strong
	); /* [OURS] the prototype
	       has ZERO hover rules. This is our decision, not the design's. */
	--al-accent-primary-tint: var(--al-sys-color-row-tint-selected);
	--al-accent-primary-wash: var(--al-sys-color-row-tint-selected); /* [P:5] faint wash bg    */
	--al-accent-primary-border: var(--al-sys-color-accent-primary-line);
	--al-accent-border-interactive: var(--al-sys-color-accent-primary-line);
	--al-accent-on-primary: var(--al-sys-color-text-on-accent);
	--al-accent-on-dark: var(--al-ref-emerald-300);
	--al-accent-interactive: var(
		--al-sys-color-accent-primary-line
	); /* [P] #1e9268 — the clickable
	       green on LIGHT surfaces: breadcrumb links (Proto buildCrumbs), the rail
	       expand badge. Distinct from --al-accent-primary (#157a52), which is the
	       fill/brand green.                                                    */

	/* focus ring — CHAINS to the accent via its channels, so re-branding moves
	   the ring with it. Previously both rings froze rgba(21,122,82,…) as
	   literals, which is the same defect as pointing at a primitive: ~20 focus
	   rings that could never re-theme. */
	/* .18 is the ring. The prototype also carries rgba(21,122,82,.12) in six
	   style-focus="…" attributes (L177-200), but style-focus is not a real HTML
	   attribute — it is inert and has never rendered in any browser. The .18 is
	   in the <style> block as actual CSS, so it is what the design LOOKS like.
	   Recorded only so nobody greps up the .12, counts six of them, and thinks
	   they found the spec: dead markup does not outvote a rule that renders. */
	--al-focus-ring: var(--al-sys-color-focus-ring); /* [P] renders  */

	/* ---------- interaction state layer  [OURS — recipe addition, Jeff 2026-08-21] ----------
	   Jeff's call (F4): ONE overlay for every button, instead of a named hover and
	   press colour per button kind. A translucent film fades in over whatever colour
	   the button already is. One rule covers hover AND press, in every colour, so a
	   new button kind needs no new tokens and cannot disagree with its neighbours —
	   which is exactly what went wrong on the POS queue screen, where two buttons
	   side by side had different ring/hover treatments.
	   >> THE BLACK FILM CLAIM ABOVE WAS WRONG (PASS6-F14 / amendment 16). <<
	   "A single layer genuinely serves the whole taxonomy" is the thing that failed.
	   Jeff, testing it: "the press is real subtle on the primary, looks good on the
	   secondary... I think the problem is you're painting everything with the same
	   brush." He is right, and it is measurable: 8% black over emerald #157a52 moves
	   luminance ~4%; the same 8% over a white secondary moves it 8% from a far
	   brighter start. One opacity cannot serve both, because a dark fill has less
	   luminance left to lose.

	   THE FINDING SURVIVES; THE FIX DID NOT. One opacity cannot serve both grounds, and
	   that is still why there are two pairs below. But the first answer to it -- make the
	   layer the container's own ON colour, so a dark fill LIGHTENS -- had a solid button
	   going further toward white the harder it was pressed, taking its white label's
	   contrast with it. The recipe splits the ALPHAS instead and keeps the film dark over
	   an accent fill, which is the same insight with the label kept readable.

	   The defaults here are the ON-SURFACE pair, because what reaches them is a control
	   grounded on the canvas. Fill-grounded variants set their own, next to the colour
	   that decides which pair they need (bootstrap-style-overrides.css). */
	--al-state-layer: var(--al-text-strong);
	--al-state-hover: var(--al-sys-state-hover-opacity-on-surface);
	--al-state-press: var(--al-sys-state-press-opacity-on-surface);

	/* ---------- Status roles ---------- */
	/* success IS the brand green: the prototype's green badges use #157a52
	   (16 uses); #0f5f3f appears zero times. */
	--al-success-fg: var(--al-sys-color-status-success-text);
	--al-success-bg: var(--al-sys-color-status-success-tint);
	--al-success-border: var(--al-sys-color-status-success);
	--al-success-solid: var(--al-sys-color-status-success);

	/* danger fg and solid are the SAME red (#c0463f = danger-600) — the design
	   uses one danger red for both destructive text and fills. The solid button's
	   hover darkens to the real #b23b39 (danger-700), a genuine design value, not
	   a derived rung. */
	--al-danger-fg: var(--al-sys-color-status-error-text);
	--al-danger-bg: var(--al-sys-color-status-error-tint);
	--al-danger-border: var(--al-sys-color-status-error);
	--al-danger-solid: var(--al-sys-color-status-error);
	--al-danger-solid-hover: var(--al-sys-color-accent-danger-strong);

	/* the callout triad (B) — keep these together; do NOT pair them with the
	   badge tier's values (see the warning primitives for why). */
	--al-warning-fg: var(--al-sys-color-status-warning-text);
	--al-warning-bg: var(--al-sys-color-status-warning-tint);
	--al-warning-border: var(--al-sys-color-status-warning);
	--al-warning-solid: var(--al-sys-color-status-warning);
	--al-warning-solid-hover: var(--al-sys-color-status-warning); /* [OURS] — see below   */

	/* the badge triad (A) — the most-evidenced amber in the design */
	--al-warn-badge-fg-role: var(--al-sys-color-status-warning-text);
	--al-warn-badge-bg-role: var(--al-sys-color-status-warning-tint);
	--al-warn-badge-border-role: var(--al-sys-color-status-warning);

	--al-info-fg: var(
		--al-sys-color-status-info-text
	); /* [P9-STA-TRIAD-ADM] info fg = the ONE blue #2a6fdb (was the 2nd blue --al-info-44 #2563c9) */
	--al-info-bg: var(--al-sys-color-status-info-tint);
	--al-info-border: var(--al-sys-color-status-info);
	--al-info-solid: var(--al-sys-color-status-info);
	--al-info-solid-hover: var(--al-sys-color-status-info); /* [OURS] — see below        */

	/* scrim / backdrop — there was NO backdrop token, which is exactly why the
	   prototype drifted into three different scrims. Naming it stops that. */
	--al-scrim: var(--al-sys-color-scrim); /* [P:6] canonical                    */

	/* ========================================================
	   CATEGORICAL PALETTE  [OURS — recipe addition, Jeff 2026-08-21]
	   ========================================================
	   Colors whose job is IDENTITY ("which one is this?"), not STATE ("is this
	   good or bad?"). Jeff's call, and it is the right one: the brand hues are
	   already spoken for — emerald means "primary action", amber means "warning",
	   red means "danger" — so borrowing them to tell categories apart makes a chip
	   say something it does not mean. A cultivation phase is not a warning.

	   These 8 are MEANING-FREE paint, like the primitives above. Components never
	   touch them; they consume a role (--al-phase-* etc.) that points here.

	   VALIDATED, not eyeballed (scripts/validate_palette.js, --mode light):
	   lightness band PASS · chroma floor PASS · CVD separation PASS (worst adjacent
	   pair ΔE 9.6 deutan/protan, 12.3 tritan) · normal-vision PASS (worst 19.3).
	   Two earlier attempts FAILED: a muted "premium" set fell under the chroma floor
	   and read gray, and rose-vs-moss was indistinguishable to deuteranopes.
	   Text contrast was computed per slot; -on tokens below are the passing choice
	   (all ≥ 4.5:1). Order matters — adjacent slots are the pairs that were checked,
	   so assign in order and do not reshuffle without re-running the validator. */
	--al-cat-1: #3d72b8; /* blue       */
	--al-cat-2: #b0552a; /* terracotta */
	--al-cat-3: #00806b; /* teal       */
	--al-cat-4: #c39424; /* gold       */
	--al-cat-5: #8f52a3; /* plum       */
	--al-cat-6: #5a9440; /* moss       */
	--al-cat-7: #5257b5; /* indigo     — held for the next category set */
	--al-cat-8: #a94e64; /* rose       — held for the next category set */
	/* text ON a categorical chip. Gold and moss are light enough to need dark ink;
	   white on gold is the unreadable pair the Grow screens ship today. */
	--al-cat-on-light: var(--al-neutral-10);
	--al-cat-on-dark: var(--al-neutral-100);

	/* ---- cultivation phase roles ----
	   Pinned to the phase NAME, never its position. The old code handed colors out
	   by array index (color_list[i % 7]) on one screen and by name on another, so the
	   same phase rendered two different colors depending where you looked, and adding
	   a phase re-colored everything after it. */
	--al-phase-germination: var(--al-cat-1);
	--al-phase-seedling: var(--al-cat-2);
	--al-phase-vegetative: var(--al-cat-3);
	--al-phase-pre-flowering: var(--al-cat-4);
	--al-phase-flowering: var(--al-cat-5);
	--al-phase-harvested: var(--al-cat-6);
	/* Destroyed is the one phase whose job IS state — it means "this is a loss".
	   It gets its OWN role that happens to equal the danger paint, rather than
	   pointing at --al-danger-solid: same color today by coincidence, not the same
	   meaning. Re-theming danger must not repaint a cultivation phase, and this must
	   be free to move without dragging every delete button with it. (Jeff's call.) */
	--al-phase-destroyed: var(--al-error-47);
	/* on-text per phase, so a consumer never has to work it out */
	--al-phase-germination-on: var(--al-cat-on-dark);
	--al-phase-seedling-on: var(--al-cat-on-dark);
	--al-phase-vegetative-on: var(--al-cat-on-dark);
	--al-phase-pre-flowering-on: var(--al-cat-on-light);
	--al-phase-flowering-on: var(--al-cat-on-dark);
	--al-phase-harvested-on: var(--al-cat-on-light);
	--al-phase-destroyed-on: var(--al-cat-on-dark);

	/* ---- Metrc import column-group roles ----
	   One hue per group of columns on the import grid, pinned to the group name. Used
	   only as a tint mixed into the grid surface, never as a solid fill. */
	--al-import-group-item: var(--al-cat-1);
	--al-import-group-details: var(--al-cat-7);
	--al-import-group-strain: var(--al-cat-5);
	--al-import-group-batch: var(--al-cat-3);
	--al-import-group-retail: var(--al-cat-4);
	--al-import-group-test: var(--al-cat-6);
	--al-import-group-shipment: var(--al-cat-2);

	/* ---------- neutral / inverse roles ---------- */
	/* [OURS] The prototype has no vocabulary for a neutral-solid button or an
	   inverse surface. These exist so components stop reaching for the ink/gray
	   PRIMITIVES directly — which is the defect that froze the sidebar's green
	   and every disabled button. Consumers: .btn-dark (6 uses), .btn-light
	   (0 uses — dead, flagged for removal in T15), the tooltip. */
	--al-neutral-solid: var(--al-neutral-41);
	--al-neutral-solid-hover: var(--al-neutral-29);
	--al-neutral-solid-active: var(--al-neutral-20);
	--al-surface-neutral: var(--al-sys-color-surface-sunken);
	--al-surface-neutral-strong: var(--al-sys-color-border);
	--al-surface-inverse: var(--al-neutral-10); /* tooltip / on-dark popover    */
	--al-surface-inverse-hover: var(--al-neutral-14); /* [BEDROCK C#3] hover shade of the dark POS chrome (finishes the T7 ink-700 split) */
	--al-scrollbar-thumb: var(
		--al-neutral-84
	); /* [P] #cdd2db — the prototype
	       styles scrollbars globally and this is the thumb it uses, on light
	       surfaces AND on the dark sidebar. It never styles the track. */

	/* data deltas (dashboard KPIs) — the down-delta is the danger red #c0463f
	   (= --al-error-47), same as --al-danger-solid. The full file shows the
	   design uses ONE danger red for data, text and fills; the earlier claim that
	   deltas and fills were different reds was an artifact of the truncated seam. */
	--al-delta-up: var(--al-sys-color-status-success-text);
	--al-delta-down: var(--al-sys-color-status-error-text);

	/* ========================================================
	   3 · TYPOGRAPHY
	   (Public Sans 13px body 600-heavy; Roboto Mono for IDs.)
	   ======================================================== */

	/* families */
	--al-font-sans: 'Public Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
	--al-font-mono: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

	/* weights */
	--al-fw-regular: var(--al-sys-font-weight-body); /* [P:4] body / grid cell default                 */
	--al-fw-medium: var(--al-sys-font-weight-medium);
	--al-fw-semibold: var(--al-sys-font-weight-control); /* [P] labels, secondary buttons — workhorse      */
	--al-fw-bold: var(
		--al-sys-font-weight-heading
	); /* [P] headings, KPIs. NB primary buttons DRIFT 600/700
	       (58 vs 66 full-file) — no settled weight; the "seam" that suggested
	       700 was a truncation artifact. P4 picks the button weight. */
	--al-fw-extrabold: 800;

	/* sizes (rem off 16px root; body renders ~13px) */
	--al-fs-2xs: 0.625rem; /* [P] 10px  — micro meta                        */
	--al-fs-table-head: 0.65625rem; /* [P:40] 10.5px — grid header. A real
	       step the scale was missing entirely. */
	--al-fs-xs: 0.6875rem; /* [P] 11px  — badges, eyebrow                   */
	--al-fs-xs-plus: 0.71875rem; /* [P:47] 11.5px — the small/row-action
	       tier. The design genuinely works in half-pixel steps; 47 uses
	       out-earns several tokens we already ship. */
	--al-fs-12: 0.75rem; /* [P:56] 12px                                     */
	--al-fs-sm: 0.78125rem; /* [P] 12.5px — meta, grid cell                 */
	--al-fs-base: 0.8125rem; /* [P] 13px  — BODY DEFAULT                    */
	--al-fs-md: 0.875rem; /* [P] 14px  — tabs, emphasis                     */
	--al-fs-15: 0.9375rem; /* [P:5] 15px — card-header title                */
	--al-fs-lg: 1rem; /* [P] 16px  — card heading                           */
	--al-fs-2xl: 1.25rem; /* [P] 20px  — record / page title                */
	--al-fs-3xl: 1.375rem; /* [P] 22px  — large page title                  */
	--al-fs-4xl: 1.5rem; /* [P:2] 24px — was 30px [0 uses]                  */
	--al-fs-5xl: 2.625rem; /* [P:1] 42px — real hero metric. Was 34px, which
	       was an ICON size mis-mined as type. */

	/* ICON sizes — NOT type. 128 icon declarations in the prototype were
	   previously mined as if they were font sizes, which is what produced the
	   bogus --al-fs-xl (18px: 43 uses, ALL of them icons, ZERO text) and the
	   34px "hero metric". Icons are sized here; text is sized above. */
	--al-icon-sm: 16px;
	--al-icon-md: 18px; /* [P:43] the workhorse                             */
	--al-icon-lg: 20px;
	--al-icon-xl: 24px;

	/* line heights */
	--al-lh-tight: 1.4; /* [P:8] was 1.2 [0 uses] — the design's real tighter-
	                       than-base line-height is 1.4                       */
	--al-lh-snug: 1.35; /* [P:3]                                             */
	--al-lh-base: 1.5; /* [P:27] body / alerts. (The design also uses 1.55 ×30
	       and 1.4/1.6 ×8 each — line-height drifts; 1.5 is the round near-
	       plurality. Earlier [P:57] wrongly conflated 1.5 and 1.55.) */

	/* letter spacing */
	--al-ls-tight: -0.02em; /* [P:1] was -0.01em [0 uses]                   */
	--al-ls-normal: 0;
	--al-ls-table-head: 0.04em; /* [P:44] the most common tracking in the
	       prototype — it previously had no token of its own. */
	--al-ls-badge: 0.03em; /* [P:22]                                        */
	--al-ls-wide: 0.06em; /* [P] uppercase section eyebrow                  */
	--al-ls-wider: 0.08em; /* [P:51] wide uppercase tracking (truncated read
	                          wrongly showed 0)                              */

	/* numeric alignment — a real typographic role we did not model at all.
	   Without it every ported grid silently loses digit alignment. */
	--al-numeric-tabular: tabular-nums; /* [P:42]                           */

	/* ========================================================
	   4 · SPACING  (4px base scale)
	   ======================================================== */
	--al-space-0: 0;
	--al-space-1: 0.25rem; /* 4px  */
	--al-space-1-5: 0.375rem; /* 6px  */
	--al-space-2: 0.5rem; /* 8px */
	--al-space-2-5: 0.625rem; /* 10px */
	--al-space-3: 0.75rem; /* 12px */
	--al-space-3-5: 0.875rem; /* 14px */
	--al-space-4: 1rem; /* 16px */
	--al-space-4-5: 1.125rem; /* 18px */
	--al-space-5: 1.25rem; /* 20px */
	--al-space-6: 1.5rem; /* 24px */
	--al-space-8: 2rem; /* 32px */
	--al-space-10: 2.5rem; /* 40px */
	--al-space-12: 3rem; /* 48px */
	--al-space-16: 4rem; /* 64px */

	/* ---------- spacing role aliases ---------- */

	/* page gutter — a systematic layout constant (padding:18px 22px x16).
	   Implement 20 or 24 instead and tabs visibly misalign with body content
	   on every detail screen. */
	--al-gutter-page: 22px; /* [P:16]                                       */

	/* card */
	--al-pad-card: 18px 20px; /* [P] card body — 23/26 agree, well settled  */
	--al-pad-card-head: 12px 16px; /* [P:5] CARD header — distinct from the
	       MODAL header (--al-pad-modal-head, 18px 22px), because modal chrome is
	       deliberately roomier than card chrome.
	       >> HOW THIS WAS GOT WRONG TWICE, so nobody repeats it: the original
	       value (15px 18px) was a mis-transcription and appears ZERO times. The
	       first correction then set 18px 22px on a claimed count of 16 — but
	       `grep -o 'padding:18px 22px'` PREFIX-MATCHES and silently swallowed
	       the three-value page-container paddings (18px 22px 40px x5, plus 96px,
	       46px, 44px). Terminating the match gives 8, and those 8 are modal
	       heads and page sections, not card headers. Count full declarations:
	           grep -oE 'padding: ?18px 22px[;"]'
	       The card header is genuinely the prototype's least-settled surface
	       (compare the card BODY, where 23/26 agree — the body was designed, the
	       header improvised), but 12px 16px is its real plurality. */

	/* grid cell — TWO real densities, near-tied. The old --al-pad-cell
	   (10px 8px) appears ZERO times in 262KB: its axes were transposed. */
	--al-pad-cell: 9px 10px; /* [P:74] dense                                */
	--al-pad-cell-relaxed: 11px 10px; /* [P:65] relaxed                     */
	--al-pad-row: 11px 14px; /* [P:20] table/list row — was wrongly marked
	       UNVERIFIED; it is the 8th most common padding in the prototype  */

	/* button padding — there was NO button padding token of any kind, which is
	   the direct cause of 13 distinct paddings across 29 primaries in the
	   prototype.

	   >> CORRECTED P4-T2 (2026-07-18) BY MEASUREMENT, NOT MINING. <<
	   This block used to claim "the 20/16 split is real and consistent: the
	   outlined button is deliberately 4px tighter than the primary beside it."
	   NOT SUPPORTED. The prototype HYDRATES in a browser (it ships a support.js
	   runtime), so its buttons can be RENDERED and read with getComputedStyle
	   instead of grepped out of the source. Across 23 reachable screens, 103
	   rendered buttons resolve to 29 distinct looks, and 9px 20px vs 9px 16px
	   does NOT track primary-vs-outlined — BOTH sit on primary solids
	   ("Apply Filter", "Receive inventory" at 20; "Add Discount", "New Strain"
	   at 16). Measured outlined buttons are 8px 14px / 8px 15px / 9px 18px.
	   Re-measure any time:  node .specs-local/tools/design-measure.js buttons

	   >> THE DESIGN IS GENUINELY INCONSISTENT HERE. 29 looks for 103 buttons is
	   a hand-tuned mockup, not a system. Normalising that is the entire point of
	   having tokens, so we take the measured plurality per tier and apply it
	   uniformly. Divergence from any individual prototype screen is DELIBERATE
	   and is not a parity bug. */
	/* SUPERSEDED — kept as the record of how the drift got in, because it is a clean
	   example of the pattern. It argued for 8px 15px because that "renders 31px" and
	   gives "a real 31 / 37 progression": a measurement of the OLD app, reasoned about
	   carefully, and mistaken for a decision. The recipe locks the heights directly
	   (36/28/44), so a padding chosen because of the height it happens to produce is
	   exactly backwards. See the retirement note below. */
	/* [PASS6-F12 / amendment 13] The four --al-pad-btn* tokens are RETIRED.
	   Their own comments recorded what was wrong with them: "31px tall, measured",
	   "[P:7] page-header CTA" — values mined out of the old app rather than chosen.
	   The recipe locks a 36/28/44 height and `line-height: 1`, which forces vertical
	   padding to ZERO; any token carrying vertical padding fights the locked height.
	   Buttons now take `padding: 0 16px / 0 11px / 0 22px` literally in the tier rules
	   (bootstrap-style-overrides.css), so nothing can re-adopt the measured values.
	   Deleted rather than repointed on purpose: a token nobody consumes is a trap. */

	/* badge / modal chrome */
	--al-pad-badge: 2px 9px; /* [P:17]                                      */
	--al-pad-modal-head: 18px 22px; /* [P:3] modal chrome is deliberately   */
	--al-pad-modal-body: 20px 22px; /* [P:3] roomier than card chrome —     */
	--al-pad-modal-foot: 14px 22px; /* [P:3] do not stretch card tokens     */

	/* controls */
	--al-pad-control: 0 12px; /* [P] input horizontal padding               */
	/* SPLIT from the old --al-h-control:36px, which satisfied NEITHER
	   consumer: inputs cluster hard on 38px (57 uses vs 36px's 18), and
	   buttons do not set a height at all (1 of 82) — they are padding-sized to
	   ~34px. 36px was a compromise nobody designed.
	   >> NO LONGER TRUE (PASS6-F12): buttons set a hard `height` from
	   --al-h-control / -sm / -lg, and --al-pad-btn is retired. <<

	   >> SPLIT AGAIN P4-T4a (2026-07-19) BY MEASUREMENT. <<
	   "input / select height: 38px" conflated two controls that the design sizes
	   DIFFERENTLY. Rendering the prototype across 28 screens and reading
	   getComputedStyle on 50 real fields:
	       <input>   24x 34px · 6x 37px · 5x 32px · 2x 33px · 2x 38px
	       <select>   7x 38px · 2x 34px · 2x 35px
	   Text inputs are 34px; selects are 38px, and the extra 4px is the chevron
	   well. The mined "[P:57]" was counting both together, so it reported the
	   select value for everything. Safe to correct: --al-h-input had ZERO
	   consumers outside this file — it was declared and never used.
	   Re-measure:  node .specs-local/tools/design-measure.js fields

	   HEIGHT IS DECLARED HERE, NOT COMPUTED — and that is the opposite of
	   buttons. Measured inputs have padding-top:0 and line-height:normal (~15px
	   at 13px) yet compute to 34px, which is only possible with an explicit
	   height. Do NOT "fix" this by converting to vertical padding. */
	/* >> [Jeff · Inputs #8, 2026-08-13] ONE control height = 36px, everywhere.
	   Deliberate override of the measured 34px-input / 38px-select split above —
	   Jeff chose a single unified 36px over the prototype's two-value measurement. */
	--al-h-control: 36px; /* THE control height — inputs, selects, buttons     */
	--al-h-input: 36px; /* was 34px → 36 (unified to --al-h-control)          */
	--al-h-select: 36px; /* was 38px → 36 (unified to --al-h-control)          */
	--al-pad-field: 0 11px; /* [P] measured 9x; --al-pad-control's 0 12px is
	                           the same role mined a pixel wider. Kept separate
	                           rather than churn a token with consumers.      */
	--al-h-control-sm: 28px; /* [PASS6-F12 / amendment 19] the sm tier. Was a bare
	                            literal in the .btn-sm rule while 36 and 44 were
	                            tokens; three tiers, three tokens.            */
	--al-h-control-lg: 44px; /* [P:15] larger control / touch target        */
	--al-sidebar-w: 232px; /* [OURS] our P1 sidebar width — the prototype
	                          templates it (width:{{ sidebarW }}), so the literal
	                          never appears; not a phantom.                    */
	--al-sidebar-w-rail: 64px; /* [OURS] P1                                 */

	/* ---------- z-index scale ---------- */
	/* 61 floating elements across 7 ad-hoc layers, with a LIVE collision (the
	   modal scrim and the rail flyout both sit at 60). Preserve the
	   catcher-just-below-panel RELATIONSHIP, not the literal numbers. */
	--al-z-popover-catch: 15;
	--al-z-popover: 20;
	--al-z-sticky: 40;
	--al-z-modal: 50;
	--al-z-flyout: 60;
	--al-z-takeover: 300;

	/* ========================================================
	   5 · RADIUS · BORDERS · ELEVATION · FOCUS · MOTION
	   ======================================================== */

	/* corner radius */
	/* >> RADIUS SCALE COLLAPSED TO 8px EVERYWHERE (Foundations #4, 2026-08-13 lock).
	   Controls, cards AND modals are one radius now; the role comments below are
	   HISTORICAL (the pre-collapse prototype values). pill + circle are exempt. */
	--al-radius-xs: 8px; /* was 4px — micro chips                            */
	--al-radius-sm: 8px; /* was 6px — small controls, pagination            */
	--al-radius-md: 8px; /* was 7px — DEFAULT: buttons, inputs, chips        */
	--al-radius-lg: 8px; /* [P] popovers, alerts, inset containers          */
	--al-radius-xl: 8px; /* was 10px (collapsed) — cards, panels. NOTE the prototype also
	       renders the SAME table card at 8px (16 uses) — on ADJACENT TABS of
	       the same screen (Order History 8px, Credit Ledger 10px). Drift, not
	       intent; 10px wins on count. */
	--al-radius-menu: 8px; /* was 9px (collapsed) — floating menus/panels (the account menu). A
	       real third radius sitting between lg 8px and xl 10px — 77 uses, so it is
	       not drift. Role-named rather than jammed into the t-shirt scale. */
	--al-radius-2xl: 8px; /* was 14px (collapsed to 8 — Foundations #4) — MODALS. Historical: [P:8], was 12px, which loses 8-to-1 (the
	       lone 12px modal is pre-seam). */
	--al-radius-pill: 999px; /* [P:24] pills, badges                        */
	--al-radius-circle: 50%; /* avatars, icon chips                         */

	/* borders */
	--al-border-hairline: 1px solid var(--al-border-subtle);
	--al-border-card: 1px solid var(--al-border-default);
	--al-border-control: 1px solid var(--al-border-input);

	/* ---------- elevation ---------- */
	/* >> CARDS ARE FLAT — re-confirmed on the FULL file: of 117 white radius-10px
	   cards, ZERO carry a shadow. Buttons: 0 of 82. Shadows are ONLY on floating
	   things (dropdowns, popovers, modals, the save bar) and a couple of toggle
	   knobs. Do NOT add card/button elevation.
	   >> P2-T3 (full file) corrected T10, which had run on the truncated read:
	   the popover shadow the design actually uses most is 0 12px 30px
	   rgba(16,24,42,.18) (×33) — the value T10 wrongly DELETED as "an invention"
	   in favour of the ×25 variant. The design drifts across three near-identical
	   popover shadows (…30px .18 ×33, …28px .16 ×25, …32px .16 ×13, all on
	   radius-8/9 absolute menus); we standardise on the plurality.
	   Deleted the xs/sm/card rungs — _ds_v2 phantoms for a small-card elevation
	   the design does not have. */
	--al-shadow-none: none;
	--al-shadow-md: 0 6px 18px rgba(16, 24, 42, 0.08); /* [P:5] soft raised panel
	       (radius-9). Was mislabelled a phantom on the truncated read.        */
	--al-shadow-lg: 0 12px 30px rgba(16, 24, 42, 0.18); /* [P:33] dropdowns /
	       popovers — the design's plurality floating shadow. Reverted from
	       T10's truncation-era 0 12px 28px rgba(0,0,0,.16) (×25, the same role,
	       a drift variant). Consumed by the sidebar flyout + tooltip.          */
	--al-shadow-flyout: 0 14px 34px rgba(4, 8, 14, 0.5); /* [P] the rail flyout —
	       the deepest shadow in the chrome, because it floats over the dark rail. */
	--al-shadow-menu: 0 10px 28px rgba(8, 12, 20, 0.32); /* [P:1] the account menu.
	       Deliberately darker/tighter than --al-shadow-lg because it is the one
	       floating panel that overlays the DARK sidebar and needs the separation. */
	--al-shadow-xl: 0 24px 60px rgba(0, 0, 0, 0.28); /* [P:19] modal / large overlay */
	--al-shadow-bar-bottom: 0 -4px 16px rgba(16, 24, 42, 0.08); /* [P:25] the save
	       bar's upward shadow. (Named for the save bar, its only consumer — not
	       "drawer"; there is no drawer in the design.)                         */
	--al-shadow-hover-accent: 0 4px 14px rgb(from var(--al-accent-primary) r g b / 0.1);
	/* [P:2] the SELECTABLE-card hover — emerald-tinted, paired with
	   border-color:#157a52. Not a resting elevation (cards are flat); it is the
	   hover gesture. A neutral shadow would lose it. */
	/* NOTE — a deeper menu shadow exists in the design: 0 18px 50px
	   rgba(15,22,34,.3) (×14, radius-13 large menus). No token yet; add one when
	   a P4 component needs it, rather than shipping an unused rung. */

	/* focus (v2 ring is EMERALD — and now actually chains to it) */
	--al-ring-focus: 0 0 0 3px var(--al-focus-ring);
	--al-ring-focus-strong: var(--al-ring-focus); /* retired the .28 strong variant → one ring, one alpha (Foundations #6) */
	/* [OURS] the design has ONE focus ring (.12 inline / .18 in its <style>
	   block); the .28 "strong" variant is our choice, for a more prominent ring
	   on buttons than on inputs. Whether to keep a strong variant at all — and
	   the ring's REACH — is a P3 (chrome/focus) decision: the prototype's sole
	   focus rule selects `input`, so selects, textareas and all buttons get no
	   ring and 31 fields set outline:none. P3 applies the ring to
	   input/select/textarea/button and to :focus-within on addon wrappers. */

	/* motion — the design barely animates, and where it does the vocabulary is
	   tiny: durations .15s (×26, the workhorse), .12s (×2), .18s (×1); the ONLY
	   easing is the bare `ease` keyword. The former cubic-bezier curves and the
	   .28s "slow" rung were _ds_v2 inventions with zero prototype basis — removed. */
	--al-ease-standard: ease; /* [P] the design's one easing                  */
	--al-dur-fast: 0.12s; /* [P:2]                                            */
	--al-dur-base: 0.15s; /* [P:26] the workhorse. Was 0.18s (×1 — an outlier) */
	/* [OURS — recipe extension, Jeff 2026-08-20] STRUCTURAL motion: a panel,
	   drawer or the sidebar changing SIZE or POSITION. The prototype never
	   animates structure, so the recipe had no rung for it and every component
	   invented its own (0.2s ×17, 0.3s ×28, 0.4s ×30 — 24 of those are the
	   sidebar's `transition: width` alone). This is the ONE rung being added;
	   deliberately not a full MD3 scale, and no new easings — the .28s "slow"
	   rung and the cubic-bezier curves were _ds_v2 inventions already removed
	   once for having zero prototype basis. Micro-motion still uses -base. */
	--al-dur-structural: 0.3s;
}
