[
  {
    "description": "Color system (HSL components) — the reference design: warm hue-60 neutral spine, a NEUTRAL INK primary (v32, gh#1220), 和色/wa-iro semantics. The neutral spine still carries SmartHR's values and says so per line. The GoDX identity colour is a preset now, not a default: `@godxjp/ui/themes/godx.css` (emerald-teal #008066 since gh#1345). #fdfdfb warm off-white",
    "name": "--background",
    "tier": "foundation",
    "value": "60 33% 99%"
  },
  {
    "description": "#23221e SmartHR TEXT_BLACK",
    "name": "--foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "── THE TRANSLUCENCY AXIS, SEPARATE FROM THE COLOUR AXIS (gh#901) ────────────────────────── A surface role says WHAT COLOUR; these say HOW OPAQUE. They are two different questions and conflating them is what made a translucent theme unable to have a polarity. Measured before this existed: the glass theme carried 184 declarations, and 50 of them were a role restated for no reason but to append an alpha — the card role set to a bare white at 12%. Restating the COLOUR is what shadows the library's own `.dark` block, because a declaration on the theme's scope beats an inherited value from `:root` whatever the specificity. So a theme that wanted frosted panes lost dark mode, and had to hand-author a second polarity it should never have owned. Of the 139 tokens only that theme declared, 109 are `initial` in their tier and DERIVE at the call site — they would all have followed the polarity for free if the roles had. With the alpha split out, a theme sets `--card-alpha: 12%` and never touches `--card`, so `--card` goes on flipping light/dark from the block below and every derived token follows. A ROLE MUST THEREFORE NOT CARRY ITS OWN ALPHA any more: `hsl(var(--card) / var(--card-alpha))` with a role that already carries one reads as two slashes — invalid at computed-value time, and the surface silently keeps the colour it had. That is this repo's documented number-one silent failure, and it is why the alpha has a home of its own now.",
    "name": "--card-alpha",
    "tier": "foundation",
    "value": "100%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--popover-alpha",
    "tier": "foundation",
    "value": "100%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--input-alpha",
    "tier": "foundation",
    "value": "100%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--secondary-hover-alpha",
    "tier": "foundation",
    "value": "100%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--secondary-active-alpha",
    "tier": "foundation",
    "value": "100%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--card",
    "tier": "foundation",
    "value": "60 33% 99%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--card-foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--popover",
    "tier": "foundation",
    "value": "60 33% 99%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--popover-foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "NEUTRAL INK (v32 decision A1, gh#1220) — ≈ zinc-900 #18181b. A neutral fits any brand and is one token to override; a blue default would itself be a brand choice. Near-white label on it: 17.4:1. The GoDX violet #7A00FF moved to `themes/godx.css`. Guarded by src/tokens/__tests__/neutral-primary-1220.test.ts.",
    "name": "--primary",
    "tier": "foundation",
    "value": "240 6% 10%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--primary-foreground",
    "tier": "foundation",
    "value": "60 33% 99%"
  },
  {
    "description": "#f4f3f0",
    "name": "--secondary",
    "tier": "foundation",
    "value": "45 15% 95%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--secondary-foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--muted",
    "tier": "foundation",
    "value": "45 15% 95%"
  },
  {
    "description": "39% chứ không phải 42%. Ở 42% chữ mờ chỉ đạt 4,63 trên chính --muted, tức SÁT SÀN 4,5, nên bất kỳ bề mặt nào đậm hơn nền trang một chút cũng đẩy nó xuống dưới chuẩn: 4,23 trên --accent, 4,28 trên nền alert tô destructive 5%, 4,47 trên nền warning. Ba lỗi tương phản riêng biệt đã được báo về đều quy về đúng một con số này. Ở 39% mọi bề mặt đó đạt từ 4,75 trở lên, tức có biên thật thay vì vừa đủ.",
    "name": "--muted-foreground",
    "tier": "foundation",
    "value": "44 5% 39%"
  },
  {
    "description": "#ebe9e5",
    "name": "--accent",
    "tier": "foundation",
    "value": "40 13% 91%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--accent-foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "茜 #b7282e",
    "name": "--destructive",
    "tier": "foundation",
    "value": "357 64% 44%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--destructive-foreground",
    "tier": "foundation",
    "value": "60 33% 99%"
  },
  {
    "description": "DECORATIVE CHROME — antd's `colorBorderSecondary`, not its `colorBorder`. antd ships TWO neutral border tiers and uses them for different things: `colorBorder` (`darken(#fff, 15)` → #d9d9d9) is the edge that IS a control — Input, Select, the outline Button — and `colorBorderSecondary` (`darken(#fff, 6)` → #f0f0f0) is chrome: the Tabs hairline, Card edges, Table cell rules, Divider. This token is the SECOND of those. The first is `--input` below, which is held to WCAG 2.2 SC 1.4.11's 3:1 and therefore sits far darker than antd's — a deliberate, measured deviation recorded there. It shipped at 83%, a 16-point gap from the ground, which is antd's CONTROL value (15 points) being used for everything antd paints with the split value — so every hairline, card edge and table rule in the system was one tier too dark. Reported from a screenshot of the Tabs line strip: \"ant design đường xám mờ hơn mà\". 93% is antd's own proportion — its secondary sits at 6/15 = 40% of the control tier's gap, and 40% of our 16 points is 6.4 → 92.6%, rounded onto the scale. Measured: 1.15:1 on --background where antd's #f0f0f0 on #fff is 1.14:1. NOT a contrast regression to defend: a divider is decorative, nothing about it is \"required to identify a component or its state\", so 1.4.11 does not reach it — and the JP-dense table grid reads better for it. `check:contrast`'s rail pass measures one-sided borders of 3px or more, so a 1px hairline was never in its sample either way. #eeedec — antd colorBorderSecondary tier",
    "name": "--border",
    "tier": "foundation",
    "value": "30 7% 93%"
  },
  {
    "description": "CONTROL BOUNDARY role — deliberately NOT the same value as --border (gh#315). The two roles answer different questions and are held to different bars: · --border is DECORATIVE chrome — table rules, card edges, section dividers. WCAG 2.2 SC 1.4.11 does not reach it (nothing about a divider is \"required to identify a component or its state\"), and darkening it would make the JP-dense table grid roar. It stays exactly where it is. · --input is the boundary that IS the control — the 1px edge of Input, Textarea, Select, the outline Button, TagInput, the composite date field, the topbar search. `--input` also fills the Switch's unchecked track. A text field here has NO fill of its own (`background: hsl(var(--background))`) and NO shadow to speak of, so that edge is the only thing that says \"you may type here\". That is squarely SC 1.4.11's 3:1 minimum. They shipped sharing `30 7% 83%`, which measured 1.46:1 on --background/--card — the one live WCAG failure a full DXS Platform sweep turned up. The modern refresh uses 51% lightness: the previous 53% passed the translucent hovered row but fell below 3:1 on the full --accent ground. The boundary test now includes that ground in both themes. Guarded by src/tokens/__tests__/input-boundary-contrast.test.ts. #8b8279 — control boundary, ≥3:1 (WCAG 2.2 SC 1.4.11)",
    "name": "--input",
    "tier": "foundation",
    "value": "30 7% 51%"
  },
  {
    "description": "STATUS FILLS AND THE INK THAT RIDES ON THEM. The FILLS are the palette and they do not move: 若竹, 山吹, 群青, 朱 are named colours, every solid success/attention surface in every consumer is one of them, and a chip that changes hue on upgrade is a different design. What moved is the INK, and only where it failed to be readable (gh#643). Measured from these very tokens (src/tokens/__tests__/status-fill-contrast.test.ts, and confirmed in Chromium by `check:frame-axe` on /isolate/foundation-colors at 320/375/1440): role fill WAS near-white ink dark ink (48 8% 13%) success #68be8d 2.19:1 ✗ 7.08:1 ✓ attention #eb6101 3.32:1 ✗ 4.68:1 ✓ warning #f8b500 1.74:1 ✗ 8.91:1 ✓ (already dark — the precedent) primary #18181b 17.45:1 ✓ (the GoDX preset #008066: 4.86:1) destructive … 6.10:1 ✓ info #4c6cb3 5.00:1 ✓ Two of the eight light-theme fills carried an ink their own lightness cannot support, and the package already knew the answer twice over: --warning-foreground has always been this same near-black on the equally pale 山吹, and the DARK theme flips --success-foreground / --attention-foreground to 48 9% 9% for exactly this reason. The light block was the outlier. REJECTED — darkening 若竹 and 朱 so the near-white ink clears 4.5:1. A fill needs luminance ≤ 0.183 for that; 若竹 sits at 0.422, so \"keep the white text\" means a different green, not a darker one. That is the palette change this deliberately is not. 若竹 #68be8d",
    "name": "--success",
    "tier": "foundation",
    "value": "146 40% 58%"
  },
  {
    "description": "7.08:1 on the fill — near-white was 2.19:1 (gh#643)",
    "name": "--success-foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "山吹 #f8b500",
    "name": "--warning",
    "tier": "foundation",
    "value": "44 100% 49%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--warning-foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "群青 #4c6cb3",
    "name": "--info",
    "tier": "foundation",
    "value": "221 40% 50%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--info-foreground",
    "tier": "foundation",
    "value": "60 33% 99%"
  },
  {
    "description": "朱 #eb6101",
    "name": "--attention",
    "tier": "foundation",
    "value": "25 99% 46%"
  },
  {
    "description": "4.68:1 on the fill — near-white was 3.32:1 (gh#643)",
    "name": "--attention-foreground",
    "tier": "foundation",
    "value": "48 8% 13%"
  },
  {
    "description": "IDENTITY role — the PRODUCT MARK colour (Logo `tone=\"success\"`, its wordmark, the email brand capsule). Neutral ink by default since v32 (gh#1220); the GoDX preset (`themes/godx.css`) sets it back to the violet of identity v2.3. It is deliberately distinct from two neighbours it keeps being confused with: · from --primary — a service re-theming its action colour must never recolour the mark. They hold the SAME VALUE by default and are still separate declarations; `brand-identity-role.test.ts` asserts on the DECLARATION, not the value, that this one never reads `var(--primary)` (gh#250). · from --success — 若竹 #68be8d is the STATUS green (badges, progress, \"saved\" text) and stays exactly as it is. The mark borrowed it once, rendering the identity at #69bf8e — ΔE76 ≈ 17.5 from the identity of the day, a plainly wrong brand colour (gh#250/#214). If the identity moves again, THIS COMMENT MOVES WITH IT. There is no Tailwind `bg-brand` utility on purpose: `--color-brand` is already taken by --text-brand, so identity surfaces read `hsl(var(--brand))` directly in component CSS. neutral ink. Same value as --primary by default, NOT an alias of it: re-theming the action colour must still leave the identity alone, which is what brand-identity-role.test.ts checks on the DECLARATION rather than the value.",
    "name": "--brand",
    "tier": "foundation",
    "value": "240 6% 10%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--brand-foreground",
    "tier": "foundation",
    "value": "60 33% 99%"
  },
  {
    "description": "Extended text hierarchy (beyond --foreground / --muted-foreground) — themeable per service. Roles primitives bake in today: caption/meta, disabled, inline link, brand numerals. lighter than muted-foreground — captions / meta",
    "name": "--text-tertiary",
    "tier": "foundation",
    "value": "44 5% 55%"
  },
  {
    "description": "disabled control text",
    "name": "--text-disabled",
    "tier": "foundation",
    "value": "40 6% 68%"
  },
  {
    "description": "Status TEXT colours — darker than the fill roles so small coloured text (a StatCard delta, an outline status badge label) clears WCAG AA 4.5:1 on white. The fill roles (--success/--warning/ --info) stay the brighter wa-iro for badges/bars; only TEXT reads these via text-*-strong. deep 若竹 — AA green text on white",
    "name": "--text-success",
    "tier": "foundation",
    "value": "152 84% 22%"
  },
  {
    "description": "dark 山吹 amber — yellow can never pass as text",
    "name": "--text-warning",
    "tier": "foundation",
    "value": "36 100% 28%"
  },
  {
    "description": "deep 群青 — AA blue text on white",
    "name": "--text-info",
    "tier": "foundation",
    "value": "221 70% 38%"
  },
  {
    "description": "deep 茜 — AA red text on white",
    "name": "--text-error",
    "tier": "foundation",
    "value": "357 75% 38%"
  },
  {
    "description": "Status MARK colours — the third tier, and the one whose absence shipped a defect. A tone can be painted three ways and each has its own contrast contract: FILL (--success/--warning/…) a solid chip or bar, judged against the label ON it. TEXT (--text-success/…) small coloured type, 4.5:1 against the surface behind it. MARK (these) a thin shape that CARRIES MEANING with nothing written on it — a Card accent rail, a DataTable row rail. WCAG 1.4.11 puts those at 3:1 against their own surface. The rails were reading the FILL tier, and two of them were effectively invisible. Measured in Chromium on the light card, before this tier existed: warning 1.74:1 · success 2.18:1 (both below the 3:1 non-text floor) primary 5.04 · info 4.97 · attention 3.32 · destructive 6.10 `check:contrast` was green throughout: its non-text pass only measures elements 24×24px or smaller, and a rail is 6px wide by the full height of a card, so it never qualified. These resolve THROUGH the text tier rather than restating its numbers, so a theme retunes one place and both tiers follow — and because a mark's floor (3:1) is looser than text's (4.5:1), anything legible as text is legible as a mark by construction. `attention` has no text-tier entry and its fill already clears the floor in both themes (3.32 / 6.75), so it stays on the fill. Raw HSL components, not a finished colour: callers wash them at an alpha. KNOBS, NOT BINDINGS (the gh#687 freeze rule). These read `var(--text-*)` at their CALL SITES, not here. Written here as `--mark-primary: var(--text-primary)` they computed ONCE at `:root` and every descendant inherited that answer — measured: a `[data-tenant]` setting `--text-primary: 140 80% 25%` kept `--mark-primary` at `268 100% 34.5%` and painted a VIOLET rail on a green brand. The guard did not catch it because its role list never covered the text tier. Set any of these to pin a mark independently of its text role.",
    "name": "--mark-primary",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--mark-success",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--mark-warning",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--mark-info",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--mark-destructive",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--mark-attention",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Status SURFACE colours — the FOURTH tier, and the one a brand could not express at all (gh#866). The three tiers above are all INK. A tone is also painted as a pale GROUND that content sits on — an Alert's tint, a status Badge's chip, a toned DataTable row, a toast, a ChatBubble, a toned overlay header, an EmptyState medallion. Every one of those DERIVED that ground from the tone's own fill or text colour through an alpha (`--alert-bg-alpha`, `bg-success/10`, `--table-row-tone-wash-alpha`, `--chat-bubble-tone-background-alpha`, 0.12 …). DERIVATION TIES THE GROUND'S HUE TO THE INK, AND A BRAND'S PAIR IS NOT A DERIVATION. The Caimono kit that opened the issue specifies eight colours, four inks and four INDEPENDENTLY CHOSEN grounds: `--success #126342` with `--success-soft #E8F5EF`. #E8F5EF is not #126342 at any alpha — it is a separately chosen mint. The only move the system offered was to lighten the success TEXT until its 5% wash matched the mint, i.e. damage the ink's contrast to fix the colour of the ground. `--card-background` could STORE one such colour on a scope, but nothing consumed it: Badge, Alert, the row tone and the other five each derived their own. FINISHED COLOURS, NOT HSL COMPONENTS — the one place this tier differs from the three above. A brand hands over `#E8F5EF`, and every fallback these replace is already a composited colour (`hsl(var(--success) / 0.05)`, a `color-mix()` into `--popover`), so the call sites read `var(--surface-success, <today's formula>)` with no `hsl()` wrapper. Same shape as `--surface-recessed` / `--badge-tint-surface`, which are also finished colours. KNOBS, NOT BINDINGS (the gh#687 freeze rule), for the same reason `--mark-*` above are: a `:root` binding substitutes on `<html>` and a scoped `[data-tenant]` below it would inherit root's answer. `initial` here, formula at the call site — see `status-surface-role-866.test.ts` for the consumer list the rule is measured against. ONLY THE FOUR STATUSES. `primary` and `attention` are tones a surface may carry too, but they are not what a brand ships a \"soft\" pair for, and inventing two more roles nobody asked for is how a vocabulary stops being learnable. They stay derived, deliberately. NOT A BORDER ROLE EITHER. `--alert-border-alpha` and `--chat-bubble-tone-border-alpha` keep deriving their edge from the ink: the kit supplies no border colours, and a brand that wants one already has the per-component alpha.",
    "name": "--surface-success",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "default = 0.12 at the call site",
    "name": "--surface-success-alpha",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--surface-warning",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "default = 0.12 at the call site",
    "name": "--surface-warning-alpha",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--surface-info",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "default = 0.12 at the call site",
    "name": "--surface-info-alpha",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--surface-destructive",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "default = 0.05 at the call site",
    "name": "--surface-destructive-alpha",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Interaction ramp — hover / active steps. The BRAND steps (--primary-* and --destructive-*) live in the DERIVED tier: they hang off the seeds above and are held to a 4.5:1 floor against their own label by __tests__/interactive-fill-contrast.test.ts. See src/tokens/derived.css. The NEUTRAL steps stay HERE, because they are not derivable the same way: the conventional derivation for a neutral interaction state is a translucent alpha fill (`rgba(0,0,0,0.06)`), which has no opaque equivalent to compute — so an opaque `--secondary-hover` has to be authored.",
    "name": "--secondary-hover",
    "tier": "foundation",
    "value": "45 15% 91%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--secondary-active",
    "tier": "foundation",
    "value": "45 15% 88%"
  },
  {
    "description": "和色 (wa-iro) — traditional Japanese accent palette for charts, tags, decoration. Decorative hex (NOT semantic): never remap a wa-iro to a semantic role beyond the five canonical mappings used above. 藍 indigo",
    "name": "--wa-ai",
    "tier": "foundation",
    "value": "#165e83"
  },
  {
    "description": "群青 ultramarine",
    "name": "--wa-gunjo",
    "tier": "foundation",
    "value": "#4c6cb3"
  },
  {
    "description": "瑠璃 lapis",
    "name": "--wa-ruri",
    "tier": "foundation",
    "value": "#1e50a2"
  },
  {
    "description": "紺 navy",
    "name": "--wa-kon",
    "tier": "foundation",
    "value": "#223a70"
  },
  {
    "description": "若竹 young bamboo",
    "name": "--wa-wakatake",
    "tier": "foundation",
    "value": "#68be8d"
  },
  {
    "description": "萌葱 spring green",
    "name": "--wa-moegi",
    "tier": "foundation",
    "value": "#006e54"
  },
  {
    "description": "山吹 mountain yellow",
    "name": "--wa-yamabuki",
    "tier": "foundation",
    "value": "#f8b500"
  },
  {
    "description": "朱 vermilion",
    "name": "--wa-shu",
    "tier": "foundation",
    "value": "#eb6101"
  },
  {
    "description": "茜 madder",
    "name": "--wa-akane",
    "tier": "foundation",
    "value": "#b7282e"
  },
  {
    "description": "臙脂 cochineal",
    "name": "--wa-enji",
    "tier": "foundation",
    "value": "#b94047"
  },
  {
    "description": "桜 cherry (soft bg)",
    "name": "--wa-sakura",
    "tier": "foundation",
    "value": "#fef4f4"
  },
  {
    "description": "墨 warm ink",
    "name": "--wa-sumi",
    "tier": "foundation",
    "value": "#595857"
  },
  {
    "description": "鼠 mouse-grey",
    "name": "--wa-nezu",
    "tier": "foundation",
    "value": "#949495"
  },
  {
    "description": "Chart accents are neutral decorative primitives, not business semantics. gh#873 — `--chart-3` (山吹 yamabuki) measured 1.78:1 as a rendered 2px LINE stroke on --card (rgb(253,253,252)): 59% of the WCAG 2.2 SC 1.4.11 non-text floor (3:1). It is not stroke-only: `chartColor()` (chart-frame.tsx) hands the same raw hex to Bar's `fill` and Pie's `Cell fill` at FULL opacity, so \"keep it out of the stroke rotation\" would still leave two chart types failing — a bar or a slice IS the graphical object, same floor as a line. The one place the palette is genuinely a fill with a different argument is Area's *band* (chart-cartesian.tsx), which composites at `--chart-area-fill-alpha` (0.2) UNDER the line that carries the value (chart-layout.css's own comment) — that pixel is not this token's raw hex and is not what this fix is measured against. Same hue (43.79°) and saturation (100%) held, lightness alone dropped 48.63% → 34.35% — light 1.78:1 → 3.50:1, dark 9.01:1 → 4.58:1 (was already comfortable; stays comfortable). Measured on the RENDERED stroke/fill in Chromium, not the token value — a token-value probe on this exact palette silently returns 15.46:1 for every member by failing to resolve the custom property, which is how the prior pass on gh#865 got a plausible-looking number that meant nothing. `--chart-2` and `--chart-4` clear 3:1 here (6.14:1 / 6.15:1) but NOT against the dark `--card` (2.61:1 / 2.61:1 — a different ground, not the same measurement re-run); their fix is a dark-theme-only override below, so the light values — and their tie to --wa-moegi / the --destructive hex — are untouched. `--chart-1` (3.47:1), `--chart-5` (3.19:1) and `--chart-6` (3.31/4.85:1) clear the floor in both themes and are left alone (surgical: fix what measured under, not what merely has a thin margin). See src/components/charts/__tests__/ chart-palette-contrast-873.test.tsx for the regression test derived from this stylesheet.",
    "name": "--chart-1",
    "tier": "foundation",
    "value": "#0077c7"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-2",
    "tier": "foundation",
    "value": "#006e54"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-3",
    "tier": "foundation",
    "value": "#af8000"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-4",
    "tier": "foundation",
    "value": "#b7282e"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-5",
    "tier": "foundation",
    "value": "#4c6cb3"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-6",
    "tier": "foundation",
    "value": "#eb6101"
  },
  {
    "description": "Sequential heat ramp — HeatmapChart (gh#1330). ONE hue (the --chart-1 blue, 204°) stepped by lightness alone, so the order of the steps survives every colour-vision deficiency: CVD shifts hue, and a single-hue ramp carries its meaning in luminance, which protan/deutan/tritan vision all keep. Relative luminance falls monotonically 0.805 → 0.541 → 0.330 → 0.173 → 0.064; against the light --card that is 1.21 / 1.74 / 2.72 / 4.62 / 9.03:1, each step ≥1.45:1 from the last. Step 1 is deliberately quiet (it is \"low\", not \"absent\"): an EMPTY cell is told apart by its dashed outline and its text, never by this fill. A service retunes the whole ramp here.",
    "name": "--chart-heat-1",
    "tier": "foundation",
    "value": "#d6ebf8"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-heat-2",
    "tier": "foundation",
    "value": "#94c9ec"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-heat-3",
    "tier": "foundation",
    "value": "#4ea3dc"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-heat-4",
    "tier": "foundation",
    "value": "#0077c7"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--chart-heat-5",
    "tier": "foundation",
    "value": "#004a7f"
  },
  {
    "description": "Disabled affordance opacity — single knob (was referenced but undefined → silent failure).",
    "name": "--disabled-opacity",
    "tier": "foundation",
    "value": "0.5"
  },
  {
    "description": "6px base × scaling; override to retheme every radius step",
    "name": "--radius",
    "tier": "foundation",
    "value": "calc(0.375rem * var(--scaling))"
  },
  {
    "description": "φ — radii scale by the golden ratio (steps derive in @theme)",
    "name": "--radius-ratio",
    "tier": "foundation",
    "value": "1.618"
  },
  {
    "description": "fully-round: switch / radio / slider / pill badges (NOT --radius-derived)",
    "name": "--radius-pill",
    "tier": "foundation",
    "value": "9999px"
  },
  {
    "description": "squared corners: table cells, flush inputs",
    "name": "--radius-sharp",
    "tier": "foundation",
    "value": "0"
  },
  {
    "description": "Elevation ramp. `--shadow-color` is the single brand-tint hook (space-separated RGB channels): a service can set e.g. `--shadow-color: 12 26 49` (navy) to tint the WHOLE ramp at once. These own `--shadow-md` too, so dropdown/popover/nav no longer borrow Tailwind's foreign gray-black.",
    "name": "--shadow-color",
    "tier": "foundation",
    "value": "0 0 0"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--shadow-xs",
    "tier": "foundation",
    "value": "0 1px 1px 0 rgb(var(--shadow-color) / 0.04)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--shadow-sm",
    "tier": "foundation",
    "value": "0 1px 2px 0 rgb(var(--shadow-color) / 0.05)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--shadow-md",
    "tier": "foundation",
    "value": "0 6px 16px -4px rgb(var(--shadow-color) / 0.08), 0 1px 3px 0 rgb(var(--shadow-color) / 0.08)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--shadow-lg",
    "tier": "foundation",
    "value": "0 12px 28px -6px rgb(var(--shadow-color) / 0.1), 0 2px 6px -2px rgb(var(--shadow-color) / 0.08)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--shadow-xl",
    "tier": "foundation",
    "value": "0 20px 25px -5px rgb(var(--shadow-color) / 0.1), 0 8px 10px -6px rgb(var(--shadow-color) / 0.1)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--shadow-2xl",
    "tier": "foundation",
    "value": "0 25px 50px -12px rgb(var(--shadow-color) / 0.25)"
  },
  {
    "description": "Brand GLOW — an opt-in coloured halo for the primary CTA (and any surface that opts in). Quiet by default (cardinal rule #44): a zero-size transparent shadow, which is invalid as a bare `none` inside a comma shadow list but valid as `0 0 0 0 transparent`. A service turns it on by overriding the whole value once, e.g. `--shadow-glow: 0 8px 20px hsl(var(--primary) / .32)` — the CTA then carries a brand glow with no component change.",
    "name": "--shadow-glow",
    "tier": "foundation",
    "value": "0 0 0 0 transparent"
  },
  {
    "description": "The colour and the composed gradient default at the call site (.ui-brand-glow): composed here they froze on the root's primary, so a nested [data-tenant] glow stayed the root hue. default = var(--primary)",
    "name": "--brand-glow-color",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--brand-glow-alpha",
    "tier": "foundation",
    "value": "0.18"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--brand-glow-size",
    "tier": "foundation",
    "value": "60% 50%"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--brand-glow-position",
    "tier": "foundation",
    "value": "50% 0%"
  },
  {
    "description": "default = the radial halo composed in layout.css",
    "name": "--brand-glow",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "── THE SWITCH ─────────────────────────────────────────────────────────────────────────── `--focus-outline` is ONE 0/1 flag, and every painted focus length below multiplies by it: --focus-ring-width: calc(var(--focus-ring-weight) * var(--focus-outline)) — so setting it to 0 zeroes the whole indicator at once. There is deliberately no parallel mechanism: one multiplier is the only shape in which a kill switch cannot be routed around by a per-component rebind. IT SHIPS ON, as of gh#544 — it used to ship off, and that reversal is the point of this note. The old default was a real product decision: the indicator had been reported as intrusive and the owner accepted the cost, which was that this library did not satisfy WCAG 2.2 SC 2.4.7 Focus Visible (AA) and so could carry no JIS X 8341-3:2016 AA statement. What changed is not the principle but two measurements. FIRST, what the default actually produced. Counting `data-focus-outline` across the four real consumers of this package: `ql` sets it (3 files); `godx-task`, `godx-chat` and the platform app set it NOWHERE. Three of four products shipped with no keyboard-focus indicator at all — not chosen, because the switch is only discoverable by reading this file. SECOND, what the ON state now costs. It is the HAIRLINE field indicator described below, not the 3px outline the original complaint was about. The thing being turned on is no longer the thing that was turned off. The escape hatch is the same shape it always was, one attribute, now pointing the other way: <html data-focus-outline=\"off\"> (or AppProvider's equivalent) `data-focus-outline=\"on\"` still works and still means on, so every consumer that already set it is untouched. Every painted length below multiplies by `--focus-outline`, so with the switch off the outline resolves to `0px`, the halo's spread resolves to `0px`, and `--focus-field-shadow` is `none`. The `:focus-visible` selectors themselves stay exactly where they are: only the paint goes. ── THE ON WEIGHT ────────────────────────────────────────────────────── The modern default is a 2px mark with 2px offset. Hue remains --ring for at least 3:1 contrast on supported surfaces; navigation keeps its inset. Consumers can retune the two thickness knobs or use the existing opt-out. 1 = on, 0 = off",
    "name": "--focus-outline",
    "tier": "foundation",
    "value": "1"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--focus-outline-weight",
    "tier": "foundation",
    "value": "var(--stroke-md)"
  },
  {
    "description": "default = var(--focus-ring-color, var(--ring)), resolved at the focused element — a `:root` binding froze on the root's --ring, so a nested tenant scope never re-tinted the outline (gh#687; docs/TOKENS.md, the freeze rule)",
    "name": "--focus-outline-color",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "the field halo spread",
    "name": "--control-outline-width",
    "tier": "foundation",
    "value": "calc(var(--stroke-md) * var(--focus-outline))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--focus-outline-offset",
    "tier": "foundation",
    "value": "2px"
  },
  {
    "description": "FOCUS RING — the two global knobs for the keyboard-focus affordance (WCAG 2.4.7 / 2.4.11). `--focus-ring-color` is the themeable hue (HSL components, defaults to --ring) and `--focus-ring-width` the standard thickness; override either ONCE — even scoped under a `[data-tenant]` — to retint or resize EVERY focus ring. `--focus-ring-color` is declared `initial` (NOT `var(--ring)`): a :root binding to a role var would freeze at the :root --ring and a scoped [data-tenant] override of --ring alone would never reach it. Every :focus-visible rule reads it with the live-role fallback `hsl(var(--focus-ring-color, var(--ring)))`, so the default re-resolves at the element that paints the ring while an explicit override still wins. default = the live --ring role",
    "name": "--focus-ring-color",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "The painted thickness, and the point every path passes through. `--focus-ring-weight` is the public knob a component or a service retunes; multiplying by the switch is what guarantees that a rebind cannot bring the mark back while the switch is off.",
    "name": "--focus-ring-weight",
    "tier": "foundation",
    "value": "var(--focus-outline-weight, var(--stroke-hairline))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--focus-ring-width",
    "tier": "foundation",
    "value": "calc(var(--focus-ring-weight) * var(--focus-outline))"
  },
  {
    "description": "Alpha of the ring fill. Exists so a component that needs a SOFTER ring (a filled toggle, tinted shell chrome) tunes one knob instead of writing its own `hsl(... / 0.35)` — which is how four incompatible ring shapes appeared before the single-source rule in styles/focus-ring.css.",
    "name": "--focus-ring-opacity",
    "tier": "foundation",
    "value": "1"
  },
  {
    "description": "THE FIELD HALO — `--control-outline`, split into the parts this repo composes with. All three READ the derived tier rather than declaring a number of their own: the width is `--control-outline-width`, and the colour and the alpha are the two halves of one rgba(). They stay named `--focus-ring-glow-*` because that is the public knob a service already themes through; what changed is where their DEFAULTS come from. This block once hard-coded 0.12 light / 0.3 dark, eyeballed — close to, but not, the values the tier now commits to: 0.11 and 0.29 for the seeds this library actually ships, with the halo hue rgb(109,0,228) rather than the primary itself. The halo is DECORATION and must never be asked to carry the a11y contract: measured against this palette, a primary tint over the page reads 1.23:1 at the shipped 0.11 and does not reach WCAG 2.2 SC 1.4.11's 3:1 until alpha 0.53 light / 0.85 dark — past the point where it is a halo at all. What carries the state on a field is the recoloured 1px border, and that only once `data-focus-outline=\"on\"` is set — see the switch above and docs/DESIGN-AUTHORITY.md.",
    "name": "--focus-ring-glow-width",
    "tier": "foundation",
    "value": "var(--control-outline-width)"
  },
  {
    "description": "`initial`, NOT `var(--control-outline)`: the halo colour derives from `--primary` (gh#678), and a `:root` binding would freeze on the root's primary — a tenant scope below `<html>` would keep the package violet halo. Default = the live `--control-outline`, resolved in styles/focus-ring.css.",
    "name": "--focus-ring-glow-color",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--focus-ring-glow-alpha",
    "tier": "foundation",
    "value": "var(--control-outline-alpha)"
  },
  {
    "description": "THE WHOLE FIELD HALO AS ONE TOKEN — the field's focus shadow, and the single seam the switch moves. Composing the shadow LIST here rather than in the rule is what keeps the two positions of the switch from becoming two focus languages: styles/focus-ring.css reads `box-shadow: var(--focus-field-shadow)` once and knows nothing about which position is active. `none` is the OFF value, and it is `none` rather than a zero-spread shadow on purpose: a literal `0 0 0 0 transparent` would still REPLACE the control's resting `--control-shadow`, so a switched-off focus would quietly flatten every input on the page. The PAINTING value is `initial` here and composed in styles/focus-ring.css, at the focused element: the list carries a colour, and a colour composed on `:root` is the root's colour forever — a scoped `--primary` never reached the halo, and neither did the `[aria-invalid]` rebind of `--focus-ring-glow-color` (gh#678; docs/TOKENS.md, the freeze rule). Default = `0 0 0 var(--focus-ring-glow-width) hsl(var(--focus-ring-glow-color, <live --control-outline>) / var(--focus-ring-glow-alpha))`. `none` (the OFF position) still wins over it.",
    "name": "--focus-field-shadow",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Gap between element and ring, for the OUTLINE form only (a star, a dot, a heading anchor — marks where a radius-hugging shadow would touch the glyph). The shadow form ignores it by construction.",
    "name": "--focus-ring-offset",
    "tier": "foundation",
    "value": "var(--focus-outline-offset)"
  },
  {
    "description": "Opt-in for individual clipped focus carriers, never inherited from containers.",
    "name": "--focus-ring-inset-offset",
    "tier": "foundation",
    "value": "calc(-1 * (var(--focus-ring-width) + var(--focus-outline-offset)))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--focus-ring-contained-offset",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Ring headroom for clipped chrome (`overflow-clip-margin` on the topbar family, gh#291). MUST stay a plain length consumed via a bare var(): Chromium rejects any calc() in overflow-clip-margin at parse time (even calc(2 * 2px)), silently dropping the declaration to 0. Value = max ring paint (3px open/focus) + rounding immunity: at 4px a flush-edge ring had only 1px of slack, which device-pixel rounding on non-retina (dpr 1) displays or fractional browser zoom could consume, shaving the ring's outer edge. 8px keeps ≥5px of slack under any rounding regime.",
    "name": "--focus-ring-clip-margin",
    "tier": "foundation",
    "value": "8px"
  },
  {
    "description": "Keyboard-scroll regions use an inset brand mark by default. Both the region weight and the global focus switch remain configurable.",
    "name": "--region-focus-ring-width",
    "tier": "foundation",
    "value": "var(--focus-ring-weight)"
  },
  {
    "description": "default = hsl(var(--focus-ring-color, var(--ring)))",
    "name": "--region-focus-ring-color",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "GRADIENTS — opt-in decorative fills exposed at the token layer so a service can paint a hero banner, a brand wash, or a radial brand glow purely by configuring tokens (cardinal rule #45). All default to a transparent no-op so nothing renders until a theme opts in; a surface that supports a gradient reads one of these as its background-image. Examples a service might set: --gradient-brand: linear-gradient(135deg, hsl(var(--primary)), hsl(var(--accent))); --gradient-hero: linear-gradient(180deg, hsl(var(--secondary)), hsl(var(--background))); --gradient-glow: radial-gradient(60% 80% at 50% 0%, hsl(var(--primary) / .25), transparent);",
    "name": "--gradient-brand",
    "tier": "foundation",
    "value": "none"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--gradient-hero",
    "tier": "foundation",
    "value": "none"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--gradient-glow",
    "tier": "foundation",
    "value": "none"
  },
  {
    "description": "Sans stack — FONT-AGNOSTIC by default. The library ships NO hardcoded brand face here: `--font-sans-base` is a pure system stack so godx renders cleanly with zero font setup. Consumers supply their own faces (next/font, @fontsource, self-host) and set the tokens — never edit the library. Two ways to theme fonts, both token-only (no [lang] selectors to write): 1. One face everywhere → override `--font-sans-base`. 2. Per-language faces → set the per-lang SLOT tokens; styles/base.css wires each `[lang]` to read its slot with `--font-sans-base` as the fallback: --font-sans-ja (lang=\"ja\") --font-sans-ko (lang=\"ko\") --font-sans-vi (lang=\"vi\") --font-sans-zh-hans (lang=\"zh\" | \"zh-Hans\" | \"zh-CN\") --font-sans-zh-hant (lang=\"zh-Hant\" | \"zh-TW\") e.g. `--font-sans-ja: \"Noto Sans JP\", var(--font-sans-base);` The opt-in bundle `@godxjp/ui/styles/fonts` overwrites `--font-sans-base` (and `--font-sans-vi`) with the DXS bundle — \"Noto Sans JP\" primary, \"M PLUS 2\" as its fallback — so the all-in-one entry is zero-config. That fill also lands on `:root` at THIS specificity, so `styles/fonts` MUST be imported AFTER `styles/base`, or the system stack below silently wins (issue #210).",
    "name": "--font-sans-base",
    "tier": "foundation",
    "value": "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, system-ui, sans-serif"
  },
  {
    "description": "The five per-language SLOTS, DECLARED — `initial`, which is the guaranteed-invalid value, so `var(--font-sans-ja, var(--font-sans-base))` in styles/base.css falls back exactly as it did when they were undeclared. Nothing about the cascade changes; what changes is that they are now VISIBLE. Declared nowhere, they existed only as prose in the comment above and in docs/CUSTOMER-THEMING.md, so every tool that reads this tier — the agent catalog, the MCP token list, any audit that enumerates the theme surface — reported a public theming knob as not existing (gh#862). A token nobody can look up is a token nobody has.",
    "name": "--font-sans-ja",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-sans-ko",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-sans-vi",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-sans-zh-hans",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-sans-zh-hant",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-family-sans",
    "tier": "foundation",
    "value": "var(--font-sans-base)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-family-mono",
    "tier": "foundation",
    "value": "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"
  },
  {
    "description": "Dual-font split (opt-in) — many brand designs pair a DISPLAY face for headings with a separate BODY face (e.g. Source Sans 3 display + Inter body). Both default to --font-family-sans, so a single-font system is unchanged; a service overrides one or both. Headings read --font-family-display, body reads --font-family-body (wired in styles/index.css @layer base).",
    "name": "--font-family-display",
    "tier": "foundation",
    "value": "var(--font-family-sans)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-family-body",
    "tier": "foundation",
    "value": "var(--font-family-sans)"
  },
  {
    "description": "── Type scale — GOLDEN-RATIO modular scale (Ant/Tailwind model). ONE base + ONE ratio; every step is base × ratioⁿ, so the whole scale stays in golden proportion. `--font-size-ratio` is φ^¼ (the golden ratio's quarter-step ≈ 1.1227) — a TRUE golden ratio yet dense enough that headings stay small (h1≈20, h2≈18; pure φ=1.618 would be marketing-size). Internal apps get the 14px DEFAULT with ZERO config; a customer overrides `--font-size-base` (and optionally `--font-size-ratio`) and the entire scale rescales in golden proportion. 14px — THE base (= <body>). The single knob; override to retheme.",
    "name": "--font-size-base",
    "tier": "foundation",
    "value": "0.875rem"
  },
  {
    "description": "φ^¼ — golden-ratio step (φ=1.618, φ^¼ keeps the dense scale small)",
    "name": "--font-size-ratio",
    "tier": "foundation",
    "value": "1.1227"
  },
  {
    "description": "── EVERY DERIVED STEP IS AN `initial` KNOB, NOT A VALUE (gh#834) ────────────────────────── A custom property substitutes its `var()`s AT THE ELEMENT THAT DECLARES IT. Written here as `--font-size-5xl: var(--font-size-display)`, the step computed ONCE, on `<html>`, and a scope below it that re-declared the seed only inherited the answer root had already given. Measured in Chromium before this change, with `[data-tenant] { --font-size-base: 24px; --font-size-display: 80px }`: `text-base` moved 14 → 24px and EVERY OTHER STEP DID NOT MOVE AT ALL — text-2xs 11.11, xs 12.47, sm 14, lg 17.65, xl 19.81, 2xl 22.24, 3xl 32.96, 4xl 42.19, 5xl 54, h1 19.81, h2 17.65, h3 14, h4 12.47. `docs/showcase/futurelastic-web.tsx` carried a comment reading \"80px hero via text-5xl\"; it painted 54. That is not a display-ramp bug, it is the tier's shape, and `docs/CUSTOMER-THEMING.md` sells the opposite in two places at once: level 1 calls `--font-size-base` a seed, and level 3 says the same token may be set \"under `[data-tenant]` / `.dark` / any subtree\". So the ramp takes the shape docs/TOKENS.md already prescribes for role-mirror knobs — the knob is `initial` (a real, catalogued, guaranteed-invalid declaration: there is no value to freeze) and THE FORMULA MOVES TO THE CALL SITE as the `var()` fallback, where it re-resolves at the painting element under any scope. An explicit override of a step still wins, because a set knob is not invalid and the fallback never fires. CONSEQUENCE, AND IT IS NOT OPTIONAL: every reader must carry the fallback. A bare `var(--font-size-xs)` now resolves to NOTHING — silent and total, the same failure gh#664's call-site test was written for. `check:frame-token-scope` (REACH) is the gate that measures it on a real element; the formulas below are the canonical text every reader repeats. Each formula reads ONLY the un-derived knobs (`--font-size-base`, `--font-size-ratio`, `--font-size-display`, `--font-size-display-ratio`). `xl` and `2xl` used to chain through `lg` and `xl`; an `initial` knob cannot be chained through, so they are flattened to `base × ratioⁿ`. Left-associative and therefore bit-identical to the nested form — re-measured at 19.8116px and 22.2425px, unchanged. = calc(base / ratio / ratio) — ratio⁻² ≈ 11px",
    "name": "--font-size-2xs",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= calc(base / ratio) — ratio⁻¹ ≈ 12.5px",
    "name": "--font-size-xs",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= var(--font-size-base) — 14px body (alias of base)",
    "name": "--font-size-sm",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= calc(base * ratio * ratio) — ratio² ≈ 17.6px",
    "name": "--font-size-lg",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= calc(base * ratio * ratio * ratio) — ratio³ ≈ 19.8px",
    "name": "--font-size-xl",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= calc(base * ratio * ratio * ratio * ratio) — ratio⁴ ≈ 22.3px",
    "name": "--font-size-2xl",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "FLUID, and that is a deliberate change to what a display step MEANS (gh#836). The ramp shipped as a fixed 54px, so `text-5xl` was 54px at 1440 AND at 320. Measured with a 99-character headline: 6 lines at 1280, 10 at 375, **12 at 320** — a phone hero five screens tall. Both website showcases had already written their own `clamp()` for exactly this, and the package itself knows the answer for exactly one caller, privately, in `--centered-shell-landing-heading-size-compact`. gh#836 offered two roads. Widening `size` to the responsive object `Flex direction` takes is the larger API and leaves every consumer to restate the same three breakpoints; making the ramp fluid is the smaller diff and the larger commitment, because it changes what an existing size means. This takes the second, and the reason it is safe to take HERE is that the display steps were unreachable from any public API until 28.8.0 — there is no admin screen whose headline moves, because nothing could reach these tokens to use them. 2rem (32px) at the 320px floor to 3.375rem (54px) at 1280 and above, on viewport width. The upper bound is exactly the previous fixed value, so a desktop hero is unchanged to the pixel; only the small end moves. The derived 3xl/4xl steps divide this, so they narrow with it and the ratio between the three is preserved at every width. A `clamp()` on `vw` is the one place this library accepts a viewport unit: it is the axis the defect lives on, and the alternative is the page-local `clamp()` both showcases wrote — which, written a third time, would have become folklore. `--font-size-display` remains the single knob: a service that wants a fixed display size sets it to a length and the clamp is gone. 32px → 54px — the display knob",
    "name": "--font-size-display",
    "tier": "foundation",
    "value": "clamp(2rem, 1.5rem + 2.5vw, 3.375rem)"
  },
  {
    "description": "bolder step than the body φ^¼ — marketing wants more contrast",
    "name": "--font-size-display-ratio",
    "tier": "foundation",
    "value": "1.28"
  },
  {
    "description": "`initial` knobs, formula at the call site — see the block above for why. = calc(display / dratio / dratio) — ≈ 33px feature heading",
    "name": "--font-size-3xl",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= calc(display / dratio) — ≈ 42px section",
    "name": "--font-size-4xl",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= var(--font-size-display) — 54px hero",
    "name": "--font-size-5xl",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "Headings — also golden-derived, and `initial` for the same reason. h1=ratio³, h2=ratio²; h3/h4/h5 reuse body steps (single source), so their call-site default CHAINS through the body step rather than re-spelling it: `var(--heading-h4, var(--font-size-xs, <xs formula>))` keeps \"h4 IS the xs step\" true through a scoped `--font-size-xs` as well as a scoped base. = calc(base * ratio * ratio * ratio) — ≈ 20px",
    "name": "--heading-h1",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= calc(base * ratio * ratio) — ≈ 18px",
    "name": "--heading-h2",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= var(--font-size-base) — 14px",
    "name": "--heading-h3",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "= the --font-size-xs step — ≈ 12.5px",
    "name": "--heading-h4",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "h5 exists for antd's `Typography.Title level={5}`; `Heading` still stops at 4. It takes the next step DOWN the same scale rather than a new number — see TitleLevelProp.",
    "name": "--font-weight-normal",
    "tier": "foundation",
    "value": "400"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-weight-medium",
    "tier": "foundation",
    "value": "500"
  },
  {
    "description": "the reference design uses three weights only: 400 body · 500 heading/label · 700 emphasis. 600 is forbidden (ambiguous between 500 and 700) — the legacy \"semibold\" token collapses to medium so any remaining reference renders at 500. `bold` is the 700 emphasis weight.",
    "name": "--font-weight-semibold",
    "tier": "foundation",
    "value": "500"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--font-weight-bold",
    "tier": "foundation",
    "value": "700"
  },
  {
    "description": "Display/black weight — OPT-IN for marketing display type (hero/CTA). The enterprise system caps at 700 (簡素 restraint); this is only reached via the .font-display-weight utility / a service setting it on a display surface, so admin text is unchanged.",
    "name": "--font-weight-black",
    "tier": "foundation",
    "value": "800"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--line-height-tight",
    "tier": "foundation",
    "value": "1.25"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--line-height-normal",
    "tier": "foundation",
    "value": "1.5"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--line-height-body",
    "tier": "foundation",
    "value": "1.7"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--letter-spacing-tight",
    "tier": "foundation",
    "value": "0"
  },
  {
    "description": "── SCALING — the one global density knob (Radix Themes model). A single dimensionless multiplier on every SIZE token (spacing grid, control / table / checkbox / switch heights, radius), so the whole UI rescales in proportion from one place. `1` = the design baseline. The `density` axis sets named presets (compact .92 · default 1 · comfortable 1.08); AppProvider's `scaling` prop sets any value continuously. Type has its OWN base+ratio (--font-size-base) and is NOT scaled here — fontSize stays an orthogonal axis. Touch targets (--touch-target-min) are also exempt (a11y minimum).",
    "name": "--scaling",
    "tier": "foundation",
    "value": "1"
  },
  {
    "description": "Minimum interactive target on the block axis — WCAG 2.2 SC 2.5.8 (24x24 AA). The --scaling comment above already named this token as the one size that must NOT ride the multiplier, but nothing ever defined it, so the exemption described a token that did not exist. It is a legal floor, not a design measure: shrinking it with a compact density would make the UI fail the success criterion at exactly the density where targets are already hardest to hit. Literal on purpose — scale-exempt, like the note says. scale-exempt: WCAG 2.2 SC 2.5.8 AA floor, must not ride --scaling",
    "name": "--touch-target-min",
    "tier": "foundation",
    "value": "1.5rem"
  },
  {
    "description": "Raw spacing scale — the 4px grid, scaled. Everything that derives from --space-* (padding, gaps, --phi-unit, semantic spacing, chrome) inherits the scaling automatically; this is the single highest-leverage scaling point.",
    "name": "--space-0",
    "tier": "foundation",
    "value": "0"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-1",
    "tier": "foundation",
    "value": "calc(0.25rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-2",
    "tier": "foundation",
    "value": "calc(0.5rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-3",
    "tier": "foundation",
    "value": "calc(0.75rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-4",
    "tier": "foundation",
    "value": "calc(1rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-5",
    "tier": "foundation",
    "value": "calc(1.25rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-6",
    "tier": "foundation",
    "value": "calc(1.5rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-8",
    "tier": "foundation",
    "value": "calc(2rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-10",
    "tier": "foundation",
    "value": "calc(2.5rem * var(--scaling))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--space-12",
    "tier": "foundation",
    "value": "calc(3rem * var(--scaling))"
  },
  {
    "description": "THE DISPLAY END OF THE SCALE (gh#831). The grid used to stop at 48px, which is the ceiling of an admin screen and the floor of a marketing section — so two unrelated website showcases each typed `padding-block: 5rem` because there was no step to reach for. These two are Carbon `$spacing-11` and `$spacing-12` exactly (docs/DESIGN-AUTHORITY.md names Carbon as the authority for spacing, and carbon-scale-alignment.test.ts enforces it), so the scale grows TOWARD its authority rather than away from it, and both stay on the 4px grid. Named `n = px / 4` like every step above them. Re-declared in `.ui-scale-fixed` below and in styles/density.css — a --scaling-derived step that is not re-declared in both FREEZES at :root (docs/TOKENS.md). 80px — Carbon spacing-11",
    "name": "--space-20",
    "tier": "foundation",
    "value": "calc(5rem * var(--scaling))"
  },
  {
    "description": "96px — Carbon spacing-12",
    "name": "--space-24",
    "tier": "foundation",
    "value": "calc(6rem * var(--scaling))"
  },
  {
    "description": "── ICON SIZE — the geometric axis that had a vocabulary but no name (gh#326). 28 component tokens were declaring raw numbers, and between them they only ever used NINE values. The scale was already there; nobody had written it down. These nine names ARE that list — naming an existing vocabulary, not inventing a new one. A FIXED LIST, NOT A RATIO. Unlike --font-size-* there is no `base * ratio^n` here, and that is deliberate: 14/16 = 0.875 but 20/16 = 1.25, so no single ratio generates these steps. Type can sit between pixels because hinting and antialiasing carry it; a 1px-stroke glyph cannot — half a pixel of icon is a blurred icon. So every step is a whole pixel at the 16px root, and a service retunes a STEP rather than a ratio. NOT SCALED HERE. --scaling is applied by the tokens that opt IN (`calc(var(--icon-size-md) * var(--scaling))`, as --control-icon-size does), so the scale itself stays the crisp whole-pixel list. Density is a per-token decision, not a property of the vocabulary. TIER 1 / TIER 2 — where the boundary sits. These nine steps are tier 1: the value appears in more than one place, so it earns a name and a service retunes it once. A value that appears in exactly ONE place (the 6px status dot) is tier 2 and does NOT belong on the scale — set that component's own `--*-icon-size` / `--*-glyph-size` token at the call site instead (`style={{ \"--menu-icon-size\": \"6px\" }}` or a `[data-…]`-scoped rule in the app theme). An inline custom property wins by inheritance proximity, so tier 2 needs no `!important`, no `:root` override and no fork. Every icon rule in src/styles reads its token through `var()` with no literal fallback, which is what keeps that route open — see docs/TOKENS.md. 10px",
    "name": "--icon-size-2xs",
    "tier": "foundation",
    "value": "0.625rem"
  },
  {
    "description": "12px",
    "name": "--icon-size-xs",
    "tier": "foundation",
    "value": "0.75rem"
  },
  {
    "description": "14px",
    "name": "--icon-size-sm",
    "tier": "foundation",
    "value": "0.875rem"
  },
  {
    "description": "16px — the default icon step",
    "name": "--icon-size-md",
    "tier": "foundation",
    "value": "1rem"
  },
  {
    "description": "20px",
    "name": "--icon-size-lg",
    "tier": "foundation",
    "value": "1.25rem"
  },
  {
    "description": "24px",
    "name": "--icon-size-xl",
    "tier": "foundation",
    "value": "1.5rem"
  },
  {
    "description": "36px",
    "name": "--icon-size-2xl",
    "tier": "foundation",
    "value": "2.25rem"
  },
  {
    "description": "40px",
    "name": "--icon-size-3xl",
    "tier": "foundation",
    "value": "2.5rem"
  },
  {
    "description": "48px",
    "name": "--icon-size-4xl",
    "tier": "foundation",
    "value": "3rem"
  },
  {
    "description": "── STROKE — the thickness of a painted LINE (gh#324, the second axis to be named). gh#324 measured `width` at 91% raw and called it the worst axis in the system. It is not one axis. Three unrelated concerns wear the `-width` suffix: the thickness of a drawn line, the measure of a container (a dialog, a reading column, a sidebar), and the content width of a field (how wide a locale picker must be to hold its longest label). Only the FIRST is a vocabulary — see the verdict recorded in `scripts/token-scale-bypass-rules.mjs`. The vocabulary was already there and repeats hard: SIX values across ~20 tokens spanning borders, focus rings, accent rails, selected-state markers and presence strokes. Naming it is what lets a service retune line weight once — a hi-dpi theme that wants 1.5px hairlines, or a high-contrast theme that wants every emphasis stroke at 3px — instead of hunting 20 tokens. PIXELS, NOT REM, AND DELIBERATELY SO. A stroke is a DEVICE line: its job is to read as one crisp rule at any type size, so it must not grow when the root font-size does. Every token that moves onto this scale was already `px` for that reason; a `rem` thickness (`--slider-track-height: 0.375rem`) is a different decision and stays where it is. NOT SCALED. `--scaling` is a DENSITY knob — it tightens the spacing rhythm, and a 1px divider that became 0.92px under compact density would blur, not tighten. No token on this axis multiplies by it today and none should. `--stroke-hairline` sits BELOW `--stroke-sm` rather than being called `xs`, because 1px is not really a step: it is the device hairline, the one thickness a service retunes the EXISTENCE of rather than the value (cardinal rule #44). The scale-bypass guard exempts a bare `1px` for the same reason. Naming it anyway gives the retune-the-value route to the themes that want it. TIER 2 — a thickness that appears in exactly one place does not belong here. Set that component's own `--*-border-width` / `--*-ring-width` token at the call site or in the app theme; every stroke rule in src/styles reads its token through `var()`. every resting border, divider and rule",
    "name": "--stroke-hairline",
    "tier": "foundation",
    "value": "1px"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--stroke-sm",
    "tier": "foundation",
    "value": "1.5px"
  },
  {
    "description": "the emphasis stroke — focus rings, selected markers",
    "name": "--stroke-md",
    "tier": "foundation",
    "value": "2px"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--stroke-lg",
    "tier": "foundation",
    "value": "3px"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--stroke-xl",
    "tier": "foundation",
    "value": "4px"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--stroke-2xl",
    "tier": "foundation",
    "value": "6px"
  },
  {
    "description": "── BACKDROP BLUR — the optical depth of a translucent surface (gh#837). The fourth axis to be named, and it was named because a token shipped with nothing legal to feed it. `--topbar-backdrop-blur-size` arrived in 28.8.0 so the glass bar two showcases had hand-written became a framework knob — and then the marketing page found that the only values available were a raw literal, another component's private knob (`--app-launcher-launchpad-backdrop-blur-size`), or a token from the WRONG AXIS. It borrowed `--space-2` and said so at the call site, which is honest and is not a solution. Borrowing spacing here is the same category error `check:token-scale-bypass` and the icon tier (gh#328) already police: `--space-*` is `calc(<n> * var(--scaling))`, so a blur taken from it moves whenever density is retuned, along an axis nobody chose. NOT `--scaling`-MULTIPLIED, unlike spacing and unlike the control tier. A backdrop blur is an OPTICAL effect — how far the material scatters what is behind it — not a measurement of layout. Compact density means more information per screen; it does not mean thinner glass. Tailwind's own `blur-*` scale is fixed for the same reason, as are Material 3's scrim treatments and Apple HIG's materials, none of which scale with content density. Three steps, from the two real call sites: 8px is the bar (measured on the marketing page), 16px is the launchpad's full-page scrim, and 4px is the step below for a surface that wants to separate without obscuring. TIER 2 applies as everywhere else: a blur used in exactly one place sets that component's own `--*-backdrop-blur-size` at the call site.",
    "name": "--blur-sm",
    "tier": "foundation",
    "value": "4px"
  },
  {
    "description": "the glass bar — translucent chrome over scrolling content",
    "name": "--blur-md",
    "tier": "foundation",
    "value": "8px"
  },
  {
    "description": "a full-page scrim, where the content behind must stop competing",
    "name": "--blur-lg",
    "tier": "foundation",
    "value": "16px"
  },
  {
    "description": "THE SATURATE COMPANION — ONE knob for every frosted surface in the system, not one per surface, and it is deliberate (gh#880). `blur()` averages what is behind it, and the mean of any real screen is a mid grey. That is not a stylistic observation: it is why the first glassmorphism attempt produced \"grey mush\" on every pane. Pushing chroma back up after the blur is what a physical frosted pane does — it scatters direction, not colour — and the published recipe is one number, `blur(12px) saturate(160%)` (docs/GLASSMORPHISM-STANDARD.md §1). WHY ONE AND NOT TEN. Saturation is a property of the MATERIAL, not a per-component design decision. The standard's per-surface differences are the fill ALPHA (a dropdown needs the most opaque fill, a drawer the next) and the blur SIZE — both of which stay per-surface here. Ten saturate knobs would be ten ways for the panes to drift out of step, and \"the card is glass and the thing inside it is not\" is the exact defect gh#880 was opened about. `--app-launcher-launchpad-backdrop-color-saturate` stays as the ONE documented exception: a full-viewport scrim is a different quantity of material from a 7-line menu, and it is the only surface for which that has been measured. IT IS READ WITH A CALL-SITE DEFAULT OF 160%, NOT AS A BARE `var()`. Every `backdrop-filter` below is written `blur(var(--x-backdrop-blur-size)) saturate(var(--surface-backdrop-saturate, 160%))`, so a theme that sets only a blur size still gets the saturate — asking for glass can never accidentally ask for fog. With NO blur size set the whole declaration is invalid-at-computed-value-time and `backdrop-filter` keeps its own initial `none`, which is what keeps every surface byte-identical by default. default = 160%, resolved at every call site",
    "name": "--surface-backdrop-saturate",
    "tier": "foundation",
    "value": "initial"
  },
  {
    "description": "── BAND HEIGHT — the vertical extent of a horizontal band that content is centred in (gh#324, the third axis to be named). Same split as `width`: `height` is TWO concerns wearing one suffix. A control, a table row, a menu item, a sidebar nav row and the app-shell top bar are all the same decision — how tall is the band this content sits in — and they share ONE vocabulary of seven values, each of which is declared by two to five tokens. A chart plot's height, a transfer pane's min-height and a select popover's max-height are the OTHER concern: container measures, chosen per surface, with almost no repeated value between them. Those are tier 2 and stay literal. gh#324's fourth case is the whole argument: `PageContainer`'s chrome band had no height token while `AppShell`'s bar did, so nothing could be aligned to it. The two were never conceived as members of one axis, because the axis had no name. WHY THIS IS NOT `--control-height-*`. The control tier is a RUNTIME LADDER: `--control-height` multiplies by `--scaling`, `-sm`/`-lg`/`-xs` step off it, and `@media (pointer: coarse)` lifts the whole ladder to the 44px tap floor. This scale is the STATIC vocabulary that the ladder is anchored on — `--control-height-default: var(--band-height-md)` — exactly as `--font-size-base` anchors the type scale. Do NOT point a band token at `--control-height-*` to \"reuse a step\": that silently enrols it in density AND in the coarse-pointer growth, which is a geometry change, not a rename. `--table-row-height-default` is `var(--band-height-md)` and NOT `var(--control-height-default)` for precisely that reason. NOT SCALED HERE, for the gh#328 reason: whether a band breathes with density is a per-token decision made long ago. `--control-height` opts in (`calc(… * var(--scaling))`); `--app-shell-bar-height` deliberately does not. Baking `--scaling` into the scale would flip every one of them at once. 24px",
    "name": "--band-height-xs",
    "tier": "foundation",
    "value": "1.5rem"
  },
  {
    "description": "28px",
    "name": "--band-height-sm",
    "tier": "foundation",
    "value": "1.75rem"
  },
  {
    "description": "32px — the default control/row band",
    "name": "--band-height-md",
    "tier": "foundation",
    "value": "2rem"
  },
  {
    "description": "36px",
    "name": "--band-height-lg",
    "tier": "foundation",
    "value": "2.25rem"
  },
  {
    "description": "44px — the WCAG 2.2 AA touch floor (rule #24)",
    "name": "--band-height-xl",
    "tier": "foundation",
    "value": "2.75rem"
  },
  {
    "description": "48px",
    "name": "--band-height-2xl",
    "tier": "foundation",
    "value": "3rem"
  },
  {
    "description": "56px",
    "name": "--band-height-3xl",
    "tier": "foundation",
    "value": "3.5rem"
  },
  {
    "description": "Golden ratio scale",
    "name": "--ratio-phi",
    "tier": "foundation",
    "value": "1.6180339887"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--phi-unit",
    "tier": "foundation",
    "value": "var(--space-4)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--phi-n2",
    "tier": "foundation",
    "value": "calc(var(--phi-unit) / var(--ratio-phi) / var(--ratio-phi))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--phi-n1",
    "tier": "foundation",
    "value": "calc(var(--phi-unit) / var(--ratio-phi))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--phi-0",
    "tier": "foundation",
    "value": "var(--phi-unit)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--phi-p1",
    "tier": "foundation",
    "value": "calc(var(--phi-unit) * var(--ratio-phi))"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--phi-p2",
    "tier": "foundation",
    "value": "calc(var(--phi-p1) * var(--ratio-phi))"
  },
  {
    "description": "Motion — the primitive tier for animation, so enter/transition timing reads a token instead of a literal 0.5s / cubic-bezier(...) / translateY(10px) (cardinal rule #2). the reference design keeps motion LOW: short durations, a calm decelerate curve, a small reveal shift. Consumers honour prefers-reduced-motion at the call site.",
    "name": "--duration-fast",
    "tier": "foundation",
    "value": "120ms"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--duration-base",
    "tier": "foundation",
    "value": "180ms"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--duration-slow",
    "tier": "foundation",
    "value": "320ms"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--ease-standard",
    "tier": "foundation",
    "value": "cubic-bezier(0.2, 0, 0, 1)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--ease-emphasized",
    "tier": "foundation",
    "value": "cubic-bezier(0.32, 0.72, 0, 1)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--ease-decelerate",
    "tier": "foundation",
    "value": "cubic-bezier(0, 0, 0, 1)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--ease-accelerate",
    "tier": "foundation",
    "value": "cubic-bezier(0.3, 0, 1, 1)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--reveal-distance",
    "tier": "foundation",
    "value": "10px"
  },
  {
    "description": "One step of the Reveal stagger ladder — `<Reveal delay={n}>` waits n × this before entering, so a column of reveals cascades. Read instead of a literal `.04s`/`.09s` per-item delay.",
    "name": "--reveal-stagger-step",
    "tier": "foundation",
    "value": "60ms"
  },
  {
    "description": "AMBIENT/LOOPING motion (gh#313) — the cycle member of the motion tier. `--duration-fast|base| slow` time a TRANSITION (something moves from A to B and stops); a loop needs an INTERVAL, so every ambient affordance in the product breathes at one rate. `Activity` reads these; the remaining Activity knobs (geometry / colour) live in tokens/components/activity.css. NOTE these two are Activity-scoped but live HERE, beside `--reveal-*`, because the motion tier is where timing belongs and because component-token names must carry a geometry/colour property word (`check-token-tiers`) — there is none for a duration.",
    "name": "--duration-loop",
    "tier": "foundation",
    "value": "1400ms"
  },
  {
    "description": "Per-component override (#45): a service tunes its typing rhythm without moving every loop.",
    "name": "--activity-interval",
    "tier": "foundation",
    "value": "var(--duration-loop)"
  },
  {
    "description": "Offset between the three `dots` marks — the loop counterpart to `--reveal-stagger-step`, named to match. In RTL the dots reverse with the row, so the cascade follows the reading direction with no extra rule.",
    "name": "--activity-stagger-step",
    "tier": "foundation",
    "value": "160ms"
  },
  {
    "description": "How long a toast stays before it dismisses itself (gh#1253). In the MOTION tier, like `--activity-interval`: a component-token name has no property word for a duration. Sonner takes `duration` as a JS number, so `Toaster` reads this ONCE on mount with getComputedStyle — from its ThemeScope host when it has one, else `<html>` — and accepts `ms` or `s`. A theme override applies to toasts raised after the Toaster mounts; a per-call `duration` or the Toaster's own `duration` prop still wins. 4000ms is Sonner's own default.",
    "name": "--toast-duration",
    "tier": "foundation",
    "value": "4000ms"
  },
  {
    "description": "MARQUEE — the TRAVERSAL member of the loop family, and deliberately NOT `--duration-loop`. `--duration-loop` is 1400ms because it times a BREATH: a dot rising and falling, a bar sweeping a small box. A marquee's cycle is a distance being crossed, two orders of magnitude longer, and the two are not the same knob — binding them would mean a service that calms its typing indicator to 2s also whips its logo wall across the screen twice a second. Same tier, same naming, separate value. It is a duration PER SCREENFUL, not per cycle: the component measures one copy of the content and sets `--marquee-cycle-scale` to (copy width ÷ viewport width), so the duration of one lap is `interval × scale` and the PACE is the same whether the track carries one item or forty. A per-cycle duration would make forty logos forty times faster than one, which is how every pure-CSS marquee behaves and why none of them survive real content. 20s per screenful ≈ 60px/s at 1200px — the resting pace a logo wall reads at. The two ordinals are the `speed` prop's `slow` and `fast`; they are tokens rather than multipliers in the stylesheet so a theme can retune the ladder, not just its middle rung.",
    "name": "--marquee-interval",
    "tier": "foundation",
    "value": "20s"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--marquee-interval-slow",
    "tier": "foundation",
    "value": "calc(var(--marquee-interval) * 2)"
  },
  {
    "description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
    "name": "--marquee-interval-fast",
    "tier": "foundation",
    "value": "calc(var(--marquee-interval) / 2)"
  },
  {
    "description": "── THE PRIMARY FAMILY — knobs, `initial`; defaults resolve at the call site (see above). ──",
    "name": "--primary-hover",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--primary-active",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--primary-border",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--control-outline",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "AT THE ENDS OF THE RAMP THE STEP TURNS AROUND (v32, gh#1220). A seed darker than 12% L has no room below it: the neutral ink (240 6% 10%) stepped to 1.6% for hover and 0% for pressed, 1.16:1 from rest, which reads as no hover at all. Below 12% L hover goes UP 9.6 and pressed UP 4.8 (ink: 19.6% / 14.8%). The bound is 12, not 20, and the up-steps are small, because a light label must stay AA: the worst hue (green, highest luminance per L) peaks at 21.6% L, still ≥ 6:1 under white — at 20 / +15.5 the dense sweep measured #004400 pressed at 4.06:1. The mirror case: above 94% L (the dark theme's near-white ink, 98%) hover ran into 100% (1.04:1), so both lighten steps turn DOWN (92.2% / 86.4% for the ink). Mid-ramp seeds (the GoDX violet, 50% and 86.9%) take exactly the old steps. Brand INKS (`--text-*`) keep their own formula below: an ink sits on a light surface and must step away from it, whatever the fill does.",
    "name": "--primary-hover-darken-channels",
    "tier": "semantic",
    "value": "h s calc(l - 8.4 + 18 * clamp(0, (12 - l) * 1000, 1))"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--primary-active-darken-channels",
    "tier": "semantic",
    "value": "h s calc(l - 15.5 + 20.3 * clamp(0, (12 - l) * 1000, 1))"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--primary-hover-lighten-channels",
    "tier": "semantic",
    "value": "h s calc(l + 5.8 - 11.6 * clamp(0, (l - 94) * 1000, 1))"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--primary-active-lighten-channels",
    "tier": "semantic",
    "value": "h s calc(l + 11.6 - 17.4 * clamp(0, (l - 83.4) * 1000, 1) - 5.8 * clamp(0, (l - 94) * 1000, 1))"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--primary-hover-channels",
    "tier": "semantic",
    "value": "var(--primary-hover-darken-channels)"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--primary-active-channels",
    "tier": "semantic",
    "value": "var(--primary-active-darken-channels)"
  },
  {
    "description": "the hue a focus outline paints on a control that has no boundary of its own (#a66de3 on our seed)",
    "name": "--primary-border-channels",
    "tier": "semantic",
    "value": "h calc(s * 0.68) calc(l + 16)"
  },
  {
    "description": "the focus halo on a field (rgb(109,0,228) on our seed)",
    "name": "--control-outline-channels",
    "tier": "semantic",
    "value": "h s calc(l - 5.3)"
  },
  {
    "description": "the alpha half of that halo",
    "name": "--control-outline-alpha",
    "tier": "semantic",
    "value": "0.11"
  },
  {
    "description": "── THE BRAND TEXT FAMILY — the same shape, for the same reason (gh#664). ── `--text-link` and `--text-brand` are RAMP STEPS off the action colour, not independent inks: identity v2.3 puts the link one step below the action bg (#6400D4), which is exactly where `--primary-hover` lands. They were authored as literals, and that is how `--text-link` spent a release on the pre-v2.3 BLUE after the seed moved to violet — the miss gh#648 found in this tier, one tier up, and invisible to that issue's hue lock because the lock only guards `--primary-*`. Declared as knobs, the step follows the seed and cannot be left behind. `--text-primary` is the PRESSED step of the same ramp, and the MARK tier hangs off it. It was held back once on the belief that `--mark-primary` could not follow, because that token is contracted to a RAW `H S% L%` triple washed at an alpha and CSS relative colour yields a colour only inside `hsl()`. Measured in Chrome, that reasoning was wrong: the alpha goes after the slash INSIDE the same `hsl()`, so a call site writes `hsl(var(--mark-primary, var(--text-primary, from hsl(var(--primary)) …)) / .2)` and every level still overrides. The mark tier follows with it.",
    "name": "--text-link",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--text-brand",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--text-primary",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "Light: one step DOWN the ramp from the action colour — the same step `--primary-hover` takes, so the link sits where identity v2.3 puts it and moves when the seed does.",
    "name": "--text-link-channels",
    "tier": "semantic",
    "value": "h s calc(l - 8.4)"
  },
  {
    "description": "DERIVED COLOUR — the interaction states that hang off the authored seeds.",
    "name": "--text-brand-channels",
    "tier": "semantic",
    "value": "h s calc(l - 8.4)"
  },
  {
    "description": "The pressed ink is two steps down — identity v2.3 action.primary.pressed (#5200B0).",
    "name": "--text-primary-channels",
    "tier": "semantic",
    "value": "h s calc(l - 15.5)"
  },
  {
    "description": "#c44b4d",
    "name": "--destructive-hover",
    "tier": "semantic",
    "value": "359 50.6% 53.1%"
  },
  {
    "description": "#911923",
    "name": "--destructive-active",
    "tier": "semantic",
    "value": "355 70.6% 33.3%"
  },
  {
    "description": "the same halo on an invalid field rgba(166,22,11,0.09)",
    "name": "--control-outline-error",
    "tier": "semantic",
    "value": "4.3 87.6% 34.7%"
  },
  {
    "description": "the alpha half of that halo",
    "name": "--control-outline-error-alpha",
    "tier": "semantic",
    "value": "0.09"
  },
  {
    "description": "There is no separate focus COLOUR: a focused field's border simply becomes the primary. Declared as a REFERENCE rather than a copied triple, so retinting the seed retints the focus mark with it — which is the entire point of a derived tier. Declared in BOTH blocks, not inherited from `:root`: a var() binding made once at `:root` would freeze on the light `--primary` if `.dark` ever lands on an element below `<html>` (docs/TOKENS.md, the freeze rule). The same rule means a `--primary` scoped BELOW `<html>` does not reach `--ring`: `--ring` is a public role read as `hsl(var(--ring))` all over consumer CSS, so it cannot become an `initial` knob — a nested scope sets `--ring` itself (docs/CUSTOMER-THEMING.md §Multi-tenant).",
    "name": "--ring",
    "tier": "semantic",
    "value": "var(--primary)"
  },
  {
    "description": "Semantic spacing — ONE coherent 4px grid (Tailwind/Material/Ant standard). All steps reference the linear `--space-*` scale (NOT the golden φ scale — golden ratio is for modular SIZE scales like type/radius, not the spacing grid; mixing the two left an incoherent density rhythm). The φ tokens remain available as an optional golden-layout utility, just not the spacing baseline. 32px — page gutter",
    "name": "--space-page-x",
    "tier": "semantic",
    "value": "var(--space-8)"
  },
  {
    "description": "32px",
    "name": "--space-page-y",
    "tier": "semantic",
    "value": "var(--space-8)"
  },
  {
    "description": "16px",
    "name": "--space-section",
    "tier": "semantic",
    "value": "var(--space-4)"
  },
  {
    "description": "THE MARKETING BAND RHYTHM (gh#831). `--space-section` is the gap BETWEEN the blocks of one admin page; these two are the block-axis padding of a full-bleed marketing BAND and of the hero band that opens the page. Named `--space-section-*` and not `--space-band-*` on purpose: `band` already means \"the vertical extent of a control/row\" in this repo (`--band-height-*`, rule #24) and a second meaning for the same word is the drift check:prop-vocabulary exists to stop. They read the linear `--space-*` grid for the reason stated four lines above — the φ ladder is not the spacing generator here, and 80/96px are Carbon `$spacing-11`/`$spacing-12` (docs/DESIGN-AUTHORITY.md). Re-declared in styles/density.css: both alias a --scaling-derived step, so a descendant density scope that did not re-derive them would FREEZE at :root. 80px — band padding-block",
    "name": "--space-section-band",
    "tier": "semantic",
    "value": "var(--space-20)"
  },
  {
    "description": "96px — hero band padding-block",
    "name": "--space-section-hero",
    "tier": "semantic",
    "value": "var(--space-24)"
  },
  {
    "description": "4px",
    "name": "--space-stack-xs",
    "tier": "semantic",
    "value": "var(--space-1)"
  },
  {
    "description": "8px",
    "name": "--space-stack-sm",
    "tier": "semantic",
    "value": "var(--space-2)"
  },
  {
    "description": "16px",
    "name": "--space-stack-md",
    "tier": "semantic",
    "value": "var(--space-4)"
  },
  {
    "description": "24px",
    "name": "--space-stack-lg",
    "tier": "semantic",
    "value": "var(--space-6)"
  },
  {
    "description": "40px",
    "name": "--space-stack-xl",
    "tier": "semantic",
    "value": "var(--space-10)"
  },
  {
    "description": "4px",
    "name": "--space-inline-xs",
    "tier": "semantic",
    "value": "var(--space-1)"
  },
  {
    "description": "8px",
    "name": "--space-inline-sm",
    "tier": "semantic",
    "value": "var(--space-2)"
  },
  {
    "description": "12px",
    "name": "--space-inline-md",
    "tier": "semantic",
    "value": "var(--space-3)"
  },
  {
    "description": "16px",
    "name": "--space-inline-lg",
    "tier": "semantic",
    "value": "var(--space-4)"
  },
  {
    "description": "THE INLINE AXIS OWES AN `xl` TOO (gh#835). It had one — at `foundation.css` inside `.ui-scale-fixed`, and NOWHERE else — so `--space-inline-xl` computed to EMPTY on `<html>` and on every ancestor of an ordinary component. `Flex direction=\"row\" gap=\"xl\"` therefore painted `gap: normal` outside the chrome bands that happen to carry that class: a documented member of the controlled `GapProp` vocabulary handing back the browser's initial value. Measured in Chromium before this line: row xs/sm/md/lg = 4/8/12/16px and xl = `normal`. `--space-6` (24px) and not `--space-10` (40px), the block axis's xl: the inline scale is tighter than the block scale at every other step (4 · 8 · 12 · 16 against 4 · 8 · 16 · 24), because a wide gap across a row cuts the reading line while a wide gap down a column separates blocks. Same value as the `.ui-scale-fixed` declaration, which keeps its own copy for the same reason every other step there does — that band does not scale with density. 24px",
    "name": "--space-inline-xl",
    "tier": "semantic",
    "value": "var(--space-6)"
  },
  {
    "description": "OVERLAY STACKING — one system-level layer for every portaled surface (rule #44/#45). Tooltip, Popover, Select, DropdownMenu and Sheet all hard-coded `z-50` independently, so a host app that mounts @godxjp/ui under its own stacking context (a sticky masthead, a third-party chat widget) had to fight five separate literals. Stacking is a SYSTEM decision, not a per-primitive one: a service raises every overlay together by setting this once.",
    "name": "--overlay-z-index",
    "tier": "semantic",
    "value": "50"
  },
  {
    "description": "PINNED-IN-FLOW STACKING — the layer an element takes while it is stuck to the scrollport but still part of the document: `Affix`, the sticky `Anchor` rail, a sticky table header, a sticky form footer. It is the same argument as `--overlay-z-index` one layer down, and it is here for the same reason: `table-layout.css`, `data-display-layout.css` and `control.css` each reached for a bare `z-index: 20` independently, so a host app that mounts this package under its own stacking context had to fight each of them separately. Between page content and every portaled surface, on purpose: a pinned bar must cover the rows scrolling under it, and must never cover the dialog, the dropdown or the toast.",
    "name": "--sticky-z-index",
    "tier": "semantic",
    "value": "20"
  },
  {
    "description": "Master-detail geometry. Consumers choose a semantic rail preset; they never author grid tracks. 300px",
    "name": "--master-detail-rail-compact",
    "tier": "semantic",
    "value": "18.75rem"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--master-detail-rail-narrow",
    "tier": "semantic",
    "value": "12rem"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--master-detail-rail-wide",
    "tier": "semantic",
    "value": "24rem"
  },
  {
    "description": "320px",
    "name": "--master-detail-rail-standard",
    "tier": "semantic",
    "value": "20rem"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--master-detail-gap",
    "tier": "semantic",
    "value": "var(--space-stack-md)"
  },
  {
    "description": "The collapse threshold: MasterDetail keeps its two-track split while the composition's OWN inline size is at least this wide, and stacks (master then detail) below it. A service theme retunes it once globally; the `collapseBelow` prop overrides it per instance (rule #45). This is a real knob — the layout reads it through the flex-basis threshold, NOT a media query, precisely so a `var()` can drive it (see src/styles/layout.css · .ui-master-detail). 640px — the `sm` step",
    "name": "--master-detail-collapse-below",
    "tier": "semantic",
    "value": "40rem"
  },
  {
    "description": "SplitPane main ↔ aside gap (gh#1310, rule #45), split and stacked. Default = --space-stack-md, resolved at the call site so a density scope that re-derives the step still reaches it; a service sets the column step it reads between panes, e.g. var(--space-inline-xl).",
    "name": "--split-pane-gap",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "Bounded master viewport (gh#231). OPT-IN, chosen by the semantic `masterViewport` prop — `auto` (the default) applies NO bound, so every existing composition is unchanged. A real collection can be thousands of pixels tall; when the layout stacks, that pushes the detail far below the fold. The presets cap the collection's BLOCK size and scroll it inside the region instead. Sized as a whole number of nominal collection rows (2.5rem ≈ a compact list row) so a service theme retunes them in the same semantic unit the design grid uses. 320px — about 8 nominal rows",
    "name": "--master-detail-master-viewport-compact",
    "tier": "semantic",
    "value": "20rem"
  },
  {
    "description": "448px — about 11 nominal rows",
    "name": "--master-detail-master-viewport-standard",
    "tier": "semantic",
    "value": "28rem"
  },
  {
    "description": "Focus-ring room INSIDE the bounded region: an overflow container clips both axes, so without an inset the ring of a row at the edge would be cut off (WCAG 2.4.11/2.4.13). Doubles as the scroll-padding so a row scrolled into view never sits flush against the clip edge. 4px",
    "name": "--master-detail-master-viewport-inset",
    "tier": "semantic",
    "value": "var(--space-1)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--space-page-active-x",
    "tier": "semantic",
    "value": "var(--space-page-x)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--space-page-active-y",
    "tier": "semantic",
    "value": "var(--space-page-y)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--space-section-active",
    "tier": "semantic",
    "value": "var(--space-section)"
  },
  {
    "description": "16px mobile page gutter",
    "name": "--space-page-compact-x",
    "tier": "semantic",
    "value": "var(--space-4)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--space-page-compact-y",
    "tier": "semantic",
    "value": "var(--space-4)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--space-section-compact",
    "tier": "semantic",
    "value": "var(--space-4)"
  },
  {
    "description": "Modal scrim — the single backdrop colour shared by EVERY overlay (Dialog, AlertDialog, Sheet, Drawer, AppShell mobile nav). Themeable (rule #44) so a service tints the wash to its brand once, e.g. a navy `--overlay-background: rgb(12 26 49 / .55)`, instead of forking each overlay. HOW IT REACHES AN OVERLAY (gh#215 — it previously reached NOTHING): each surface declares its own knob `initial` and resolves a SHARE of this colour at the call site, `var(--dialog-overlay-background, color-mix(in srgb, var(--overlay-background) var(--dialog-overlay-alpha), transparent))`. That keeps the calibrated per-surface depth — a slide-in Sheet washes the page more lightly (40%) than a modal Dialog (60%) — while ONE override here retints every backdrop. Per docs/TOKENS.md the knobs must stay `initial`: a `:root` binding would freeze and a scoped `[data-tenant]`/`.dark` override of this token would never reach the overlay. Overlays are portaled, so a tenant scope must also sit on the portal container (see docs/CUSTOMER-THEMING.md).",
    "name": "--overlay-background",
    "tier": "semantic",
    "value": "rgb(0 0 0 / 0.4)"
  },
  {
    "description": "RECESSED SURFACE role (gh#399) — \"the ground a card sits on\", one step BEHIND `--card`. It is a ROLE, not a derivation: the two themes order their surfaces differently, so no single expression is correct on both. Light puts `--muted` (95%) behind `--card` (99%); dark puts it (18%) in FRONT of `--card` (12%), so the shipped `hsl(var(--muted) / 0.4)` composited to rgb(35,33,30) against a rgb(33,32,28) card — the page read 1.015:1 LIGHTER than the cards on it, i.e. the elevation inverted. No alpha fixes that: the mix runs from `--background` (correct) toward `--muted` (wrong), so anything above ~0.33 crosses the card. Each theme therefore states its own ground below. Light keeps the exact shipped composite (1.036:1 behind the card); dark takes the page `--background`, which measures 1.089:1 — matching the light theme's separation instead of inverting it.",
    "name": "--surface-recessed",
    "tier": "semantic",
    "value": "hsl(var(--muted) / 0.4)"
  },
  {
    "description": "Block-end inset of the page footer band; symmetric with its block-start rhythm.",
    "name": "--page-footer-pad-block-end",
    "tier": "semantic",
    "value": "var(--space-stack-md)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-header-divider",
    "tier": "semantic",
    "value": "none"
  },
  {
    "description": "The widest share of the header row the actions (`extra`) keep on ONE row before they wrap (gh#1025); the title keeps the rest. `initial` — default 60% at the call site.",
    "name": "--page-header-extra-max-measure",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "PageContainer `toolbar` — the fixed chrome band between the header and the (scrolling) body. ALL THREE knobs are quiet by default (rule #44): background — `transparent`, i.e. the band shows the page ground exactly as it did before the knob existed. It is bound at `:root` and NOT `initial`, unlike the divider below, because the default is a plain CSS keyword rather than another role token: there is nothing for a scoped [data-tenant]/.dark override to re-resolve, so the `initial` + call-site-fallback dance would buy nothing and only hide the default from anyone reading this file. A service that wants the band to read as its own surface — the design that asked for this knob puts a chat channel's workflow rail on the card ground — sets `--page-toolbar-background: hsl(var(--card));` ONCE in its theme. Never `className=\"bg-card\"` at the call site: that is hand-laid page chrome, it paints only under `variant=\"flush\"` gutters correctly by accident, and it cannot be re-themed per tenant. pad-block — `initial`; the call site falls back to the container's `--page-band-gap` (`var(--page-toolbar-pad-block, var(--page-band-gap))`), which is scoped on `.ui-page-container` and so cannot be bound here. The band's BOX sits FLUSH against the header above and the body below (src/styles/layout.css cancels the container's gap from the band itself — a painted, ruled band floating in a void divides nothing), and this inset gives the band's CONTENT the page's band rhythm back: a plain filter strip sits one band gap from the header and from the body, the same as any other band. At the old `0px` default a transparent strip touched both surfaces, 0px (gh#1323). A service that paints or rules the band sets a tighter inset HERE (`--page-toolbar-pad-block: var(--space-2)`) instead of padding the strip at the call site; `0px` restores the flush strip. divider — declared `initial` so the CALL SITE can fall back to --page-header-divider (`var(--page-toolbar-divider, var(--page-header-divider))`). One theme declaration therefore rules the whole page chrome consistently, and a scoped [data-tenant]/.dark override of the header divider still reaches the band — a `:root` binding would freeze it at the :root value (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Set `--page-toolbar-divider: none` to silence just this band.",
    "name": "--page-toolbar-background",
    "tier": "semantic",
    "value": "transparent"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-toolbar-pad-block",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-toolbar-divider",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "Top rule of the PageContainer `footer` — the third page chrome band, brought onto the same contract as the header and the toolbar (its rule used to be a hard literal in layout.css, so a page could not turn it off at all). Declared `initial` like the toolbar's, so the CALL SITE resolves it as `var(--page-footer-divider, 1px solid hsl(var(--border)))` and a scoped [data-tenant]/.dark override still reaches it (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). It is the ONE chrome knob whose default is a RULE rather than silence, and deliberately so: `footer` is the shared slot a form's Save/Cancel bar lands in, where the line separating the actions from the page content is the behaviour every existing page already depends on. The old literal is the fallback verbatim, so unset is byte-identical. A page whose footer content already carries its own frame — a chat composer is a bordered Card — silences the duplicate with `--page-footer-divider: none`.",
    "name": "--page-footer-divider",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "Bottom inset of the page header, sized so title→body distance (this pad + the --space-section-active container gap) EQUALS the page's top padding — the title band reads vertically balanced (24 above / 24 below by default), instead of the old fixed 16px pad that left 24 above vs 32 below. A page that passes a `toolbar` measures title→BAND instead (this pad alone, the gap being cancelled): the band is chrome attached to the header, not the next section down.",
    "name": "--page-header-pad-bottom",
    "tier": "semantic",
    "value": "calc(var(--space-page-active-y) - var(--space-section-active))"
  },
  {
    "description": "Inline measure of the header `extra` region while the page header is in `responsive-inline` arrangement (gh#231). Below the 640px step the default arrangement drops `extra` onto its own full-width line under the subtitle; `headerLayout=\"responsive-inline\"` keeps it beside the title band at this measure instead, so a single compact control (a search field, one primary action) stays on the title row at 390px. Unused by the default arrangement, so no existing page moves. 11rem = 176px, i.e. the control ends flush with the compact page gutter. 176px",
    "name": "--page-header-extra-measure",
    "tier": "semantic",
    "value": "11rem"
  },
  {
    "description": "Gap between the page title and its status/meta band (PageContainer `status`, godxjp-ui#255), and between the band's own items. One knob aligns the badge row to a service's grid; a page that never passes `status` reads neither the token nor the wrapping row.",
    "name": "--page-header-status-gap",
    "tier": "semantic",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "PageContainer `headerLoading` placeholders (gh#255). The title/subtitle elements wear the shared `.ui-skeleton-block` skin, so they need only a MEASURE and a block size — a service retunes the pending band's proportions here instead of per page. 224px",
    "name": "--page-title-placeholder-measure",
    "tier": "semantic",
    "value": "14rem"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-title-placeholder-block-size",
    "tier": "semantic",
    "value": "1.5em"
  },
  {
    "description": "352px",
    "name": "--page-subtitle-placeholder-measure",
    "tier": "semantic",
    "value": "22rem"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-subtitle-placeholder-block-size",
    "tier": "semantic",
    "value": "1.25em"
  },
  {
    "description": "Bounded page MEASURE (gh#245 / gh#247) — the shared inline cap applied to the page HEADER and BODY together, so the header `extra` action ends on the same edge as the body surface (the `variant=\"narrow\"` complaint: it caps only `.ui-page-body`, leaving the header action out at the page edge). Selected by the semantic `measure` prop; `measure=\"default\"` reads NEITHER token, so an existing page is untouched. These are OUTER measures: the page gutters (--space-page-active-x, 24px each side by default) live INSIDE the cap, so the VISIBLE surface is the measure minus both gutters: narrow 42rem = 672px → 624px visible surface (the historical variant=\"narrow\" body width) medium 48rem = 768px → 720px visible surface (the canonical readable/feed measure) Below the cap nothing binds, so a 390px viewport stays fluid at the 16px compact gutter (358px surface). A service theme retunes both in ONE place; never a page-local max-width. 672px outer → 624px surface",
    "name": "--page-measure-narrow",
    "tier": "semantic",
    "value": "42rem"
  },
  {
    "description": "768px outer → 720px surface",
    "name": "--page-measure-medium",
    "tier": "semantic",
    "value": "48rem"
  },
  {
    "description": "THE MARKETING MEASURE (gh#831). A landing page is not a reading column: two unrelated website showcases each hand-wrote a shell cap (1200px and 1140px) because the widest name here was `medium` at 768px. 72rem sits between the two measured values and is a step the industry already ships (Tailwind `--container-6xl`); the wide-container cluster runs 1136–1320px (Radix Container 4 = 1136, Primer/Tailwind = 1280, Bootstrap = 1320). No `PageContainer` branch reads it yet (the website-components roadmap, §5.9), so today this is the VOCABULARY a marketing composition caps its own shell with, as `--gradient-hero` is. 1152px outer → 1104px surface",
    "name": "--page-measure-wide",
    "tier": "semantic",
    "value": "72rem"
  },
  {
    "description": "Responsive page typography is independent from density. Density changes information spacing; these tokens change only page chrome so mobile keeps readable body text and touch targets.",
    "name": "--page-title-font-size",
    "tier": "semantic",
    "value": "var( --heading-h1, calc( var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio) ) )"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-title-font-size-compact",
    "tier": "semantic",
    "value": "var( --heading-h2, calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)) )"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-subtitle-font-size",
    "tier": "semantic",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-subtitle-font-size-compact",
    "tier": "semantic",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "PageContainer `headerScale=\"chrome\"` — the title step for a page whose top row IS CHROME rather than a document title: a chat channel name, a mail subject line, an IDE tab. It is a SEPARATE knob from the two above on purpose: those are ONE document title at two viewport sizes (a responsive step), while this is a different KIND of page and holds at every width. `--heading-h3` (= --font-size-base, 14px) is the body step, which is the point — the row reads as a label ON the surface, not as the page's headline, and the header band collapses from the measured 61px to ~40px once it stops carrying a 20px h1. Quiet by default: a page that never passes `headerScale` never reads this token (rule #44).",
    "name": "--page-title-font-size-chrome",
    "tier": "semantic",
    "value": "var(--heading-h3, var(--font-size-base))"
  },
  {
    "description": "PageContainer `headerScale=\"display\"` (gh#1160) — an ARTICLE's headline (a Notion / note.com page). The 4xl display step, which already scales with the viewport through `--font-size-display`'s clamp (≈25px on a phone → 42px wide), so one knob covers phone and desktop and the compact step below does not apply. CJK titles need more leading than Latin ones at this size: 1.4, not the tight 1.25 a short Latin headline gets. `initial` with the formula at the call site: it reads `--font-size-display`, a seed a consumer may re-scope, and a :root formula would compute once on <html> (docs/TOKENS.md · \"Role-mirror knobs MUST be initial\"). = the 4xl display step, resolved at the call site",
    "name": "--page-title-font-size-display",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-title-line-height-display",
    "tier": "semantic",
    "value": "1.4"
  },
  {
    "description": "The page icon above the title (gh#1160): emoji or glyph, and how far it rides up over a banner cover's bottom edge.",
    "name": "--page-icon-size",
    "tier": "semantic",
    "value": "var(--icon-size-4xl)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-icon-cover-overlap",
    "tier": "semantic",
    "value": "calc(var(--page-icon-size) * 0.6)"
  },
  {
    "description": "PageCover (gh#1160). A banner's height scales with the viewport between a phone floor and a desktop ceiling — one knob per step, no media query; an eyecatch keeps note.com's ~1.91:1.",
    "name": "--page-cover-block-size-md",
    "tier": "semantic",
    "value": "clamp(8rem, 24vw, 15rem)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-cover-block-size-lg",
    "tier": "semantic",
    "value": "clamp(10rem, 32vw, 20rem)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--page-cover-eyecatch-aspect-ratio",
    "tier": "semantic",
    "value": "1.91"
  },
  {
    "description": "default = var(--card-radius) at the call site (gh#888)",
    "name": "--page-cover-radius",
    "tier": "semantic",
    "value": "initial"
  },
  {
    "description": "The SUBTITLE step of the same fact. Measured against the reference chat screen, the chrome title and the chrome subtitle were rendering at the SAME step (both --font-size-base), which is not a hierarchy — a channel name and the channel's purpose line read as one undifferentiated block. The design puts the purpose line two steps down (`Text size=\"2xs\"`), and the size is what carries the LINE BOX: at 14px/1.7 the subtitle line is 23.8px tall, at 11px/1.7 it is 18.9px, so the whole header band loses ~5px it was spending on a caption. `--font-size-2xs` (ratio⁻², ≈11px) is that step, and it is the same golden scale the title step reads — never a literal. Quiet by default: a page that never passes `headerScale` never resolves it (#44).",
    "name": "--page-subtitle-font-size-chrome",
    "tier": "semantic",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "The page's TOP inset under `headerScale=\"chrome\"`, the second half of the same fact: chrome sits on the frame's edge. A document page opens with --space-page-active-y (24px, 16px below the 720px step) because a title needs air above it; a chat channel head, a mail subject bar or an IDE tab strip is the frame itself, and 24px of margin above it reads as a page floating inside its own shell — measured on a consumer chat screen as 24px lost off the top of the transcript viewport, against a design whose channel head starts at y=0. 0 is therefore the quiet default (rule #44), and it is a knob rather than a literal so a service whose grid wants its chrome inset (`--page-pad-block-start-chrome: var(--space-2)`) retunes it once instead of forking the page shell. Read ONLY when the prop is passed, so no document page resolves it.",
    "name": "--page-pad-block-start-chrome",
    "tier": "semantic",
    "value": "0px"
  },
  {
    "description": "The BAND HEIGHT of the same fact (gh#331). A document header is content-height by definition — a title is as tall as the title is. A chrome band is the opposite: it is furniture, and furniture has a height that things centre INTO. `AppShell` has had `--app-shell-bar-height` for exactly that since it shipped; `PageContainer` had no equivalent, so a `headerScale=\"chrome\"` band's vertical centre drifted with its own copy — measured in Chromium on /isolate/layout-page-container, 42.02px with an `extra` control and 40.38px without, i.e. the centre moves 0.8px for a change of content and there is no value a service can aim at. WHO OWNS THE BAND-HEIGHT AXIS (the question gh#331 defers to gh#330). `--app-shell-bar-height` does: it is the system's one declared chrome-band height, and `--centered-shell-bar-height` already reads it. A service that wants its page chrome to sit on the shell bar's band writes ONE line — `--page-header-min-block-size-chrome: var(--app-shell-bar-height)` — and the two bands are on one axis for good. It is NOT that value by DEFAULT, and the reason is not timidity: a `PageContainer` with a chrome header is not necessarily inside an `AppShell` (the canonical chat composition renders one inside a bordered region, a SplitPane pane, a Card), and a band that is not trying to line up with a bar has no business inheriting that bar's height. `auto` is the quiet state (rule #44): no floor, content-height, byte-identical to every page rendered before this token existed — document AND chrome. A MIN, never a fixed height: a taller `extra` (an `lg` control, a wrapped JA/VI channel name) must still fit rather than overflow its own band. The header centres its content in whatever band it ends up with — see `justify-content` in styles/layout.css — so raising this knob centres, it does not top-pack. The header's own `--page-header-pad-bottom` lives INSIDE the band (border-box); under the canonical chrome composition (`variant=\"ghost\"`) that pad is 0 and the centring is exact.",
    "name": "--page-header-min-block-size-chrome",
    "tier": "semantic",
    "value": "auto"
  },
  {
    "description": "Section \"chrome\" padding — the SHARED inset for header / body / footer of every overlay-ish surface (Dialog · Sheet · Drawer · Card). One global knob: a service sets these once instead of per-component. Vertical is tightened (16 vs the old 24) and density-aware (see density.css); horizontal stays 24 (Ant standard). Per-component tokens (--sheet-pad-*, --dialog-space-inset…) default to these and only override when a surface genuinely needs to differ. 24px — horizontal inset",
    "name": "--space-chrome-x",
    "tier": "semantic",
    "value": "var(--space-6)"
  },
  {
    "description": "16px — vertical inset (header/footer/body)",
    "name": "--space-chrome-y",
    "tier": "semantic",
    "value": "var(--space-4)"
  },
  {
    "description": "gap between header ↔ body ↔ footer",
    "name": "--space-chrome-gap",
    "tier": "semantic",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "The ONE vertical gap between a field's LABEL and its CONTENT — same everywhere a label sits above a control or a value (FormField, Descriptions, Form, any label-above stack). Single source so the whole system stays in sync (gh feedback: Descriptions was ~0px while FormField was 8px). 8px",
    "name": "--field-label-gap",
    "tier": "semantic",
    "value": "var(--space-2)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--admin-collection-control-height",
    "tier": "semantic",
    "value": "var(--control-height-default)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--admin-collection-section-gap",
    "tier": "semantic",
    "value": "var(--space-stack-md)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--admin-collection-toolbar-padding-y",
    "tier": "semantic",
    "value": "0px"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--admin-collection-search-measure",
    "tier": "semantic",
    "value": "20rem"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--admin-collection-table-row-height",
    "tier": "semantic",
    "value": "var(--table-row-height-default)"
  },
  {
    "description": "Layout primitive tokens: page, section, stack, inline.",
    "name": "--admin-collection-table-cell-padding-y",
    "tier": "semantic",
    "value": "var(--space-1)"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--color-card",
    "tier": "semantic",
    "value": "hsl(var(--card) / var(--card-alpha, 100%))"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--color-popover",
    "tier": "semantic",
    "value": "hsl(var(--popover) / var(--popover-alpha, 100%))"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--color-input",
    "tier": "semantic",
    "value": "hsl(var(--input) / var(--input-alpha, 100%))"
  },
  {
    "description": "Golden-ratio radius scale — every step derives from --radius × (--radius-ratio = φ)ⁿ, so overriding --radius alone rescales the whole scale proportionally (≈ 1.4/2.3/3.7/6/9.7/15.7px).",
    "name": "--radius-xs",
    "tier": "semantic",
    "value": "calc( var(--radius) / var(--radius-ratio) / var(--radius-ratio) / var(--radius-ratio) )"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--radius-sm",
    "tier": "semantic",
    "value": "calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--radius-md",
    "tier": "semantic",
    "value": "calc(var(--radius) / var(--radius-ratio))"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--radius-lg",
    "tier": "semantic",
    "value": "var(--radius)"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--radius-xl",
    "tier": "semantic",
    "value": "calc(var(--radius) * var(--radius-ratio))"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--radius-2xl",
    "tier": "semantic",
    "value": "calc(var(--radius) * var(--radius-ratio) * var(--radius-ratio))"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--color-secondary-hover",
    "tier": "semantic",
    "value": "hsl(var(--secondary-hover) / var(--secondary-hover-alpha, 100%))"
  },
  {
    "description": "───────────────────────────────────────────────────────────────────────── FOUNDATION — Tailwind entry, design tokens, density, theme mapping, base element styles.",
    "name": "--color-secondary-active",
    "tier": "semantic",
    "value": "hsl(var(--secondary-active) / var(--secondary-active-alpha, 100%))"
  },
  {
    "description": "Gap between actions. Tight on purpose — the strip is a cluster, not a row of page buttons.",
    "name": "--actions-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Inset of the `filled` / `outlined` forms. `borderless` drops both to zero.",
    "name": "--actions-padding-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Actions component tokens — the strip of actions under an assistant message (Ant Design X `Actions`). Every action is a `Button`, so NOTHING here sets a control height: that comes from the `--control-height` tier through Button's own `size=\"icon-sm\"` step, and restating it would re-derive a tier that drifts from the buttons beside it (`pnpm check:control-sizing`).",
    "name": "--actions-padding-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--actions-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Chrome of the two bounded variants. Role-mirror knobs (docs/TOKENS.md): `initial` so each documented default resolves at the CALL SITE. Default filled ground = hsl(var(--muted)) Default outlined stroke = var(--stroke-hairline) solid hsl(var(--border))",
    "name": "--actions-filled-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Actions component tokens — the strip of actions under an assistant message (Ant Design X `Actions`). Every action is a `Button`, so NOTHING here sets a control height: that comes from the `--control-height` tier through Button's own `size=\"icon-sm\"` step, and restating it would re-derive a tier that drifts from the buttons beside it (`pnpm check:control-sizing`).",
    "name": "--actions-outlined-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`fadeIn` / `fadeInLeft` — the distance the strip travels along the inline axis. The DURATION is deliberately not a knob here. Timing belongs to the motion tier, for the same reason `src/tokens/components/activity.css` records: `check-token-tiers`' component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration, and a service retunes arrival motion once through `--duration-base` rather than per component. The animation reads that token directly, and drops to nothing under `prefers-reduced-motion`.",
    "name": "--actions-fade-offset-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Mark geometry. `em`-based so the whole mark tracks `--activity-font-size-*` (and therefore `--font-size-base` and the density axis) instead of pinning a px diameter per size step.",
    "name": "--activity-mark-size",
    "tier": "component",
    "value": "0.25em"
  },
  {
    "description": "Travel of one `dots` step — the loop counterpart to `--reveal-distance`, named to match. It is ALSO the height the mark row reserves, so the indicator appearing under a composer never shifts the row.",
    "name": "--activity-mark-offset",
    "tier": "component",
    "value": "0.25em"
  },
  {
    "description": "Resting opacity of a dot at the bottom of its cycle. Never 0: a dot that vanishes reads as a rendering bug at the trough, and the reduced-motion resting state must stay fully legible.",
    "name": "--activity-mark-rest-alpha",
    "tier": "component",
    "value": "0.35"
  },
  {
    "description": "The single `pulse` mark — a breathing dot (live / recording), bigger than one `dots` dot because it carries the whole affordance alone.",
    "name": "--activity-pulse-mark-size",
    "tier": "component",
    "value": "0.5em"
  },
  {
    "description": "Mark-to-mark and mark-to-label gap.",
    "name": "--activity-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Root size ladder — the mark is `em`-based, so this ONE value scales the whole indicator. Steps mirror the `Text` size the label is rendered at, so mark and label stay optically paired (`--font-size-sm` IS `--font-size-base`; the ladder skips the alias).",
    "name": "--activity-font-size-xs",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "ACTIVITY — the ambient/looping motion primitive (gh#313). The loop counterpart to `Reveal`: `Reveal` runs ONCE on mount, `Activity` runs FOREVER while something is happening elsewhere (someone typing, a sync in flight, a response streaming, a recording running). Every value the loop reads is a knob (cardinal rule #45) so a service theme retunes the whole ambient feel in one place instead of forking a `@keyframes`. TIMING LIVES IN THE MOTION TIER, NOT HERE. `--duration-loop`, `--activity-interval` and `--activity-stagger-step` are declared in `src/tokens/foundation.css` beside `--duration-slow` and `--reveal-stagger-step`: they are the cycle members of the motion tier, they must sit next to their one-shot siblings to stay comparable, and `check-token-tiers`' component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration. Geometry, colour and alpha — everything the shape rule DOES cover — live here. Defaults are the QUIETEST ambient state (cardinal rule #44): muted ink, a small mark, low travel.",
    "name": "--activity-font-size-sm",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "ACTIVITY — the ambient/looping motion primitive (gh#313). The loop counterpart to `Reveal`: `Reveal` runs ONCE on mount, `Activity` runs FOREVER while something is happening elsewhere (someone typing, a sync in flight, a response streaming, a recording running). Every value the loop reads is a knob (cardinal rule #45) so a service theme retunes the whole ambient feel in one place instead of forking a `@keyframes`. TIMING LIVES IN THE MOTION TIER, NOT HERE. `--duration-loop`, `--activity-interval` and `--activity-stagger-step` are declared in `src/tokens/foundation.css` beside `--duration-slow` and `--reveal-stagger-step`: they are the cycle members of the motion tier, they must sit next to their one-shot siblings to stay comparable, and `check-token-tiers`' component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration. Geometry, colour and alpha — everything the shape rule DOES cover — live here. Defaults are the QUIETEST ambient state (cardinal rule #44): muted ink, a small mark, low travel.",
    "name": "--activity-font-size-md",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "ACTIVITY — the ambient/looping motion primitive (gh#313). The loop counterpart to `Reveal`: `Reveal` runs ONCE on mount, `Activity` runs FOREVER while something is happening elsewhere (someone typing, a sync in flight, a response streaming, a recording running). Every value the loop reads is a knob (cardinal rule #45) so a service theme retunes the whole ambient feel in one place instead of forking a `@keyframes`. TIMING LIVES IN THE MOTION TIER, NOT HERE. `--duration-loop`, `--activity-interval` and `--activity-stagger-step` are declared in `src/tokens/foundation.css` beside `--duration-slow` and `--reveal-stagger-step`: they are the cycle members of the motion tier, they must sit next to their one-shot siblings to stay comparable, and `check-token-tiers`' component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration. Geometry, colour and alpha — everything the shape rule DOES cover — live here. Defaults are the QUIETEST ambient state (cardinal rule #44): muted ink, a small mark, low travel.",
    "name": "--activity-font-size-lg",
    "tier": "component",
    "value": "var( --font-size-lg, calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)) )"
  },
  {
    "description": "Indeterminate `bar` (syncing). Width is an inline measure, not a fill: the bar sits beside a label in a row, so `100%` would eat the label's space.",
    "name": "--activity-bar-width",
    "tier": "component",
    "value": "4rem"
  },
  {
    "description": "ACTIVITY — the ambient/looping motion primitive (gh#313). The loop counterpart to `Reveal`: `Reveal` runs ONCE on mount, `Activity` runs FOREVER while something is happening elsewhere (someone typing, a sync in flight, a response streaming, a recording running). Every value the loop reads is a knob (cardinal rule #45) so a service theme retunes the whole ambient feel in one place instead of forking a `@keyframes`. TIMING LIVES IN THE MOTION TIER, NOT HERE. `--duration-loop`, `--activity-interval` and `--activity-stagger-step` are declared in `src/tokens/foundation.css` beside `--duration-slow` and `--reveal-stagger-step`: they are the cycle members of the motion tier, they must sit next to their one-shot siblings to stay comparable, and `check-token-tiers`' component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration. Geometry, colour and alpha — everything the shape rule DOES cover — live here. Defaults are the QUIETEST ambient state (cardinal rule #44): muted ink, a small mark, low travel.",
    "name": "--activity-bar-radius",
    "tier": "component",
    "value": "var(--radius-pill)"
  },
  {
    "description": "ACTIVITY — the ambient/looping motion primitive (gh#313). The loop counterpart to `Reveal`: `Reveal` runs ONCE on mount, `Activity` runs FOREVER while something is happening elsewhere (someone typing, a sync in flight, a response streaming, a recording running). Every value the loop reads is a knob (cardinal rule #45) so a service theme retunes the whole ambient feel in one place instead of forking a `@keyframes`. TIMING LIVES IN THE MOTION TIER, NOT HERE. `--duration-loop`, `--activity-interval` and `--activity-stagger-step` are declared in `src/tokens/foundation.css` beside `--duration-slow` and `--reveal-stagger-step`: they are the cycle members of the motion tier, they must sit next to their one-shot siblings to stay comparable, and `check-token-tiers`' component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration. Geometry, colour and alpha — everything the shape rule DOES cover — live here. Defaults are the QUIETEST ambient state (cardinal rule #44): muted ink, a small mark, low travel.",
    "name": "--activity-bar-segment-width",
    "tier": "component",
    "value": "40%"
  },
  {
    "description": "ACTIVITY — the ambient/looping motion primitive (gh#313). The loop counterpart to `Reveal`: `Reveal` runs ONCE on mount, `Activity` runs FOREVER while something is happening elsewhere (someone typing, a sync in flight, a response streaming, a recording running). Every value the loop reads is a knob (cardinal rule #45) so a service theme retunes the whole ambient feel in one place instead of forking a `@keyframes`. TIMING LIVES IN THE MOTION TIER, NOT HERE. `--duration-loop`, `--activity-interval` and `--activity-stagger-step` are declared in `src/tokens/foundation.css` beside `--duration-slow` and `--reveal-stagger-step`: they are the cycle members of the motion tier, they must sit next to their one-shot siblings to stay comparable, and `check-token-tiers`' component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration. Geometry, colour and alpha — everything the shape rule DOES cover — live here. Defaults are the QUIETEST ambient state (cardinal rule #44): muted ink, a small mark, low travel.",
    "name": "--activity-bar-track-alpha",
    "tier": "component",
    "value": "0.2"
  },
  {
    "description": "scale-exempt: an em thickness that must track the label beside it, not a fixed band step",
    "name": "--activity-bar-height",
    "tier": "component",
    "value": "0.25em"
  },
  {
    "description": "Mark colour. ROLE-MIRROR KNOB ⇒ declared `initial` here with the role default at the CALL SITE (`hsl(var(--activity-color, var(--muted-foreground)))` in styles/motion.css). Written as `--activity-color: var(--muted-foreground)` it would freeze at the `:root` role value and a scoped `[data-tenant]` / `.dark` override of `--muted-foreground` would never reach it. @see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\". Documented default: --activity-color = var(--muted-foreground) (tone=\"muted\").",
    "name": "--activity-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Distance from the scrollport's BLOCK-START edge at which an Affix pins, and the distance it sits at once pinned. Ant Design `offsetTop`, whose default is `0`; ported as that default.",
    "name": "--affix-inset-block-start",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "The same, from the BLOCK-END edge — the sticky form footer rather than the sticky header. Ant Design `offsetBottom` has no default at all, because in antd the PRESENCE of the prop is what selects bottom pinning. That selection is still the prop's here; this is only the length it pins at.",
    "name": "--affix-inset-block-end",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Thickness of the ink rail — its inline size in a vertical anchor, its block size in a horizontal one. A hairline by default, matching the list's own leading rule.",
    "name": "--anchor-ink-width",
    "tier": "component",
    "value": "2px"
  },
  {
    "description": "Paint of the ink rail, and of the active row's label. `initial` + a call-site fallback, NOT `var(--primary)` here, because `--primary` is exactly the role a tenant re-scopes: a `[data-tenant] { --primary: … }` would override the role and never reach a knob that had already frozen against `:root`'s copy of it, so the rail would keep the default brand's colour under the tenant's. docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\", and src/tokens/__tests__/tenant-scope-freeze-687.test.ts is the guard. Documented default: `hsl(var(--primary))`.",
    "name": "--anchor-ink-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Paint of the rail's TRACK — the full-length rule the ink slides along. Same freeze rule, same shape. Documented default: `hsl(var(--border))`.",
    "name": "--anchor-track-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Vertical rhythm of one row: the block padding above and below a label. The row's HEIGHT is this plus the label's own line box, deliberately — an anchor row is a line of running text, not a control, so it must not be pinned to the `--control-height` tier (which is also re-scoped by AuthShell, and would freeze if mirrored).",
    "name": "--anchor-item-padding-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Inline distance from the rail to the label.",
    "name": "--anchor-item-padding-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Extra inline indent applied to a NESTED row — antd's one level of `items[].children`.",
    "name": "--anchor-nested-padding-inline",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Gap between rows on the HORIZONTAL axis. The vertical axis has none: its rows sit flush so the ink rail reads as one continuous rule.",
    "name": "--anchor-gap",
    "tier": "component",
    "value": "var(--space-inline-lg)"
  },
  {
    "description": "Gap between cards in the list. Ant X: `marginXS` = 8px.",
    "name": "--attachments-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "THE CARD BOX. Ant X's file card is a fixed 268x68 chip: wide enough for a name plus one line of description, short enough that a row of them reads as a tray and not as a list. Both axes are fixed there and fixed here — the block size is what the `+` tile and the `scrollY` one-row viewport are measured against, so it has three readers, not one. Ant X `width: 268`",
    "name": "--attachments-card-size",
    "tier": "component",
    "value": "16.75rem"
  },
  {
    "description": "Ant X `cardHeight` = 14 * 1.5714 * 2 + 12 + 12 = 68",
    "name": "--attachments-card-block-size",
    "tier": "component",
    "value": "4.25rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; `initial`, default = var(--radius). Ant X `token.borderRadius` = 6 ≡ --radius",
    "name": "--attachments-card-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Ant X `marginSM` — glyph to name",
    "name": "--attachments-card-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "THE PLACEHOLDER — the whole control while the list is empty, and the drop target. Ant X `token.padding` = 16",
    "name": "--attachments-placeholder-space-inset",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; `initial`, default = var(--radius). Ant X `token.borderRadius` = 6 ≡ --radius",
    "name": "--attachments-placeholder-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Ant X's placeholder mark is `fontSizeHeading2` = 30px, which is not a step of this repo's nine-value icon scale (gh#326) and whose neighbours are 24 and 36. It stays on the step the frozen table in `src/tokens/__tests__/icon-size-scale.test.ts` already records for it — the same mark Upload's dropzone draws, which is the surface a reader meets this one beside.",
    "name": "--attachments-placeholder-icon-size",
    "tier": "component",
    "value": "var(--icon-size-3xl)"
  },
  {
    "description": "Attachments — Ant Design X chat-surface file collection. Ant X retunes this through `styles={{ list, placeholder, upload, … }}`. Here every length and tint is a named knob (rules #44/#45) so a service sets the rail once in theme.css. EVERY KNOB BELOW IS READ BY A RULE IN `src/styles/data-entry-layout.css` (gh#855). It was not always so: all twelve of these resolved, were generated into the MCP catalog, were described to every consumer — and nothing anywhere read one of them, because the component had no stylesheet at all. The defaults are Ant X's own numbers, taken from `@ant-design/x@2.9.0` (`es/attachments/style/index.js` + `es/file-card/style/index.js`) rather than invented, and mapped onto this repo's scales; `docs/DESIGN-AUTHORITY.md` carries the divergences.",
    "name": "--attachments-placeholder-title-font-size",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Attachments — Ant Design X chat-surface file collection. Ant X retunes this through `styles={{ list, placeholder, upload, … }}`. Here every length and tint is a named knob (rules #44/#45) so a service sets the rail once in theme.css. EVERY KNOB BELOW IS READ BY A RULE IN `src/styles/data-entry-layout.css` (gh#855). It was not always so: all twelve of these resolved, were generated into the MCP catalog, were described to every consumer — and nothing anywhere read one of them, because the component had no stylesheet at all. The defaults are Ant X's own numbers, taken from `@ant-design/x@2.9.0` (`es/attachments/style/index.js` + `es/file-card/style/index.js`) rather than invented, and mapped onto this repo's scales; `docs/DESIGN-AUTHORITY.md` carries the divergences.",
    "name": "--attachments-placeholder-description-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Attachments — Ant Design X chat-surface file collection. Ant X retunes this through `styles={{ list, placeholder, upload, … }}`. Here every length and tint is a named knob (rules #44/#45) so a service sets the rail once in theme.css. EVERY KNOB BELOW IS READ BY A RULE IN `src/styles/data-entry-layout.css` (gh#855). It was not always so: all twelve of these resolved, were generated into the MCP catalog, were described to every consumer — and nothing anywhere read one of them, because the component had no stylesheet at all. The defaults are Ant X's own numbers, taken from `@ant-design/x@2.9.0` (`es/attachments/style/index.js` + `es/file-card/style/index.js`) rather than invented, and mapped onto this repo's scales; `docs/DESIGN-AUTHORITY.md` carries the divergences.",
    "name": "--attachments-placeholder-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The scrim the drop layer paints over the whole control while a file is dragged across it. Role-mirror knob, so `initial` and the role resolved at the CALL SITE (docs/TOKENS.md) — a `[data-tenant]`/`.dark` scope that re-seeds `--background` must reach this. Documented default = `color-mix(in srgb, hsl(var(--background)) 85%, transparent)`, which is Ant X's `colorBgPlaceholderHover` (`colorBgContainer` at alpha .85).",
    "name": "--attachments-drop-overlay-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The ✕ at the end of a card's row. Ant X draws it at `fontSizeLG` = 16; it stays at the 14px step the frozen icon table records, which is also `--upload-remove-icon-size`. Two remove affordances in one group drawing two different sizes is the defect, not the saving.",
    "name": "--attachments-remove-icon-size",
    "tier": "component",
    "value": "var(--upload-remove-icon-size)"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-space-gap",
    "tier": "component",
    "value": "var(--space-inline-xs)"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-space-x",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-space-y",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Corner of the chip (gh#404). Default = the historical literal `--radius-md`, so nothing moves; it exists so a NESTING context can restate it through the cascade (a Badge inside a bordered Button squares down to --radius-sm) and a call site can restate it back. gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--badge-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Companion to --badge-font-size (gh#260). The cva's old `text-xs` utility also set line-height via Tailwind's default `--text-xs--line-height: calc(1 / 0.75)` (the theme remaps --text-xs but never that companion). Same unitless ratio here keeps the default badge pixel-identical now that badge-layout.css owns the type metrics.",
    "name": "--badge-line-height",
    "tier": "component",
    "value": "calc(1 / 0.75)"
  },
  {
    "description": "Leading/trailing glyph inside the pill. It was a bare `0.75rem` in badge-layout.css with no token at all, so a service could only resize it with `!important` or a forked stylesheet — the two routes the icon axis's tier 2 exists to abolish (gh#326). Same step, so nothing moves. Matches --badge-font-size's step by design: the glyph reads as a character in the label's run, so the two retune together. Deliberately NOT --scaling-multiplied — the literal it replaces did not track density.",
    "name": "--badge-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xs)"
  },
  {
    "description": "Removable chip (antd Tag closable) — × affix inside the pill.",
    "name": "--badge-space-x-removable",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-remove-offset-inline-end",
    "tier": "component",
    "value": "calc(-1 * var(--space-1))"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-remove-icon-size",
    "tier": "component",
    "value": "var(--badge-icon-size)"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-remove-rest-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-remove-hover-alpha",
    "tier": "component",
    "value": "1"
  },
  {
    "description": "DATA COLOUR (`color` prop) — the entity's own colour, not a semantic tone. A caller colour is DATA: a project administrator picks it for a status, an issue type, a tag, a label. Solid, no foreground clears WCAG AA for every colour they can pick — near-black and white measure equal at luminance 0.2029, where both land on 4.15:1, under the 4.5 that badge-sized text needs, and a real picker can produce that. So the GROUND moves instead: the colour is washed into the surface and the label stays the surface's own foreground, which makes the ratio a function of these two knobs rather than of the colour somebody chose. The fill is where the label sits, so it is quiet; the edge carries no text, so it is free to be four times as saturated — it is what keeps a pale tint from dissolving into the surface, and where the colour still says WHICH status at a glance. At these defaults the worst case across the sRGB cube measures 8.52:1 (both themes), against 4.15 for a solid chip.",
    "name": "--badge-tint-fill",
    "tier": "component",
    "value": "18%"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-tint-edge",
    "tier": "component",
    "value": "45%"
  },
  {
    "description": "`initial`, NOT `hsl(var(--card))` — the :root freeze rule (docs/TOKEN-RESOLUTION.md §3). Bound here, `var(--card)` substitutes against the ROOT's card once, so a `.dark` REGION below root moved `--card` and the chip kept the light one. Measured: in a `.dark` region the scope reported `--card: 48 8% 12%` while the chip still painted `color(srgb 0.9933 0.9933 0.9867)` — a white chip in a dark panel. `.dark` on `<html>` was always right, which is why it survived: the freeze only shows where the scope sits BELOW the binding. Same shape as gh#848 and gh#866; found by `scripts/explain-token.mjs`. The formula now lives at the call site in badge-layout.css, where the scope is in effect.",
    "name": "--badge-tint-surface",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Badge component tokens.",
    "name": "--badge-tint-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`initial` FOR THE SAME REASON, and getting this wrong once is how I learned to measure twice: the first fix moved `--badge-tint-surface` to the call site but left this one bound here as `var(--badge-tint-surface, hsl(var(--card)))`. That still substitutes at :root, so in a `.dark` region the chip mixed the LIGHT card into the dark surface and painted `color(srgb 0.285…)` where `.dark` on `<html>` painted `0.1296` — a fix that moved the defect instead of removing it, and one a screenshot would have called correct. The whole chain is now resolved at the call site. The old warning still holds — an UNSET custom property makes color-mix() invalid at computed-value time and drops the background AND the border — which is exactly why every read below carries the full fallback rather than relying on this declaration.",
    "name": "--badge-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Square corners — a strip spans its container edge-to-edge, so it carries no radius.",
    "name": "--banner-radius",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "The strip keeps a single hairline block-end rule (tone-coloured via the alert border rules); inline/block-start edges are open so it reads as part of the frame. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--banner-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Strip inset. Block is denser than the inline Alert card; inline defaults to the page gutter so banner text aligns with page content under AppShell/PageContainer.",
    "name": "--banner-space-inset-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Banner — the full-bleed attention strip (<Banner> = Alert variant=\"banner\"). Colour stays with the alert tone rules; these tokens own ONLY the strip geometry, so a service retunes the banner once here instead of forking alert-layout.css (rule #45 — every service-tunable constant gets a knob).",
    "name": "--banner-space-inset-inline",
    "tier": "component",
    "value": "var(--space-page-active-x, var(--space-6))"
  },
  {
    "description": "A leading RAIL, not a frame: an aside inside prose reads as an annotation of the column it sits in, and four borders make it a card that interrupts the column.",
    "name": "--callout-rail-width",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Squared off against the rail; the trailing corners still follow the alert radius. `initial`, not `var(--alert-radius)` — a :root binding freezes (gh#888); default resolves at the call site. Default = var(--alert-radius).",
    "name": "--callout-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Prose insets. Block matches the paragraph rhythm around it rather than the denser banner strip; inline leaves room for the rail without shifting the text.",
    "name": "--callout-space-inset-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Callout — the in-prose aside (<Callout> = Alert variant=\"callout\"). Colour stays with the alert tone rules; these tokens own ONLY the aside geometry, so a service retunes every callout once here instead of forking alert-layout.css (rule #45 — every service-tunable constant gets a knob).",
    "name": "--callout-space-inset-inline",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Block margin — a callout separates from the paragraphs it sits between.",
    "name": "--callout-space-stack",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Horizontal inset of every slot (header / content / footer) + the resting top/bottom shell padding. This is the column the title, body and footer all align to.",
    "name": "--card-space-inset",
    "tier": "component",
    "value": "var(--space-section-active)"
  },
  {
    "description": "BLOCK-axis (top/bottom) shell padding of the slotted card rhythm — a plain header's top, a `solo` body's top, and the terminal slot's bottom (gh#232). Split off --card-space-inset so a shell (AuthShell compact) can retune the card's height WITHOUT moving the inline column. Declared `initial` — NOT `var(--card-space-inset)` — so the default resolves at the CALL SITE: a :root binding would freeze at the :root inset and `[data-density=\"tight\"|\"cozy\"]` (which override --card-space-inset on the card element) would stop reaching it. See docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — the same call-site rule applies to derived knobs. default = var(--card-space-inset)",
    "name": "--card-space-shell-y",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Vertical padding of a BANDED header band (top = bottom). Drives --card-space-divided-y.",
    "name": "--card-space-header-y",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "Gap between the header and the body, and the body's own top padding — the breathing room under a title before content begins.",
    "name": "--card-space-body-y",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Symmetric block padding for a SOLO content slot, so a composed shell can tune block and inline spacing independently without targeting CardContent. Declared `initial` for the SAME reason as --card-space-shell-y above: written as `var(--card-space-inset)` here it would freeze at the :root inset, and a card carrying [data-density=\"tight\"|\"cozy\"] (which override --card-space-inset ON THE CARD) would keep the :root value. The default now resolves at the call site through the chain solo-y → shell-y → inset, so a solo body follows the general block knob when only that is set, and an explicit solo-y still wins. default = var(--card-space-shell-y, var(--card-space-inset))",
    "name": "--card-space-solo-y",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Vertical padding of a SEPARATED footer band (top = bottom). Drives --card-space-divided-y.",
    "name": "--card-space-footer-y",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "DIVIDED-section vertical padding (rule #44/#45). A header/footer that carries a divider border (banded header, separated footer) reads as its own band, so it pads SYMMETRICALLY top+bottom — distinct from a plain header that flows into the body (top inset, no bottom). One themeable knob keeps the header- and footer-band rhythm in sync; a service theme tunes the band density here instead of forking per-slot CSS.",
    "name": "--card-space-divided-y",
    "tier": "component",
    "value": "var(--card-space-header-y)"
  },
  {
    "description": "Vertical gap between stacked items WITHIN a slot (e.g. title ↕ description in the header).",
    "name": "--card-space-gap",
    "tier": "component",
    "value": "var(--space-stack-xs)"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-title-font-size",
    "tier": "component",
    "value": "calc(var(--font-size-base) * var(--font-size-ratio))"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-title-line-height",
    "tier": "component",
    "value": "var(--line-height-tight)"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-title-font-weight",
    "tier": "component",
    "value": "var(--font-weight-semibold)"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-description-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-description-line-height",
    "tier": "component",
    "value": "var(--line-height-normal)"
  },
  {
    "description": "Card fill + edge — opt-in knobs that DEFAULT to the live --card / --border roles. Declared `initial` (not `var(--card)`) so the default re-resolves at the call site under a scoped theme: a :root binding to a role var freezes at the :root value and a scoped `[data-tenant]` override of the role never reaches it (see docs/STANDARDS-vocabulary-tokens.md · \"role-mirror knobs\"). A service still overrides the knob directly (--card-background: …) to win over the role default. default = hsl(var(--card))",
    "name": "--card-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--border))",
    "name": "--card-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Banded-header fill — role-tintable (rule #45): a service points this at any role, e.g. --card-header-background: var(--primary), and tunes --card-header-background-alpha for the wash strength. Default = the live --muted role (resolved at the call site). default = hsl(var(--muted))",
    "name": "--card-header-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-header-background-alpha",
    "tier": "component",
    "value": "0.55"
  },
  {
    "description": "Banded-header divider — tokenised (rule #44) so a service theme can make it dashed / heavier / none without forking CSS. Pair with --card-header-background-alpha: 0 for a quiet borderless-band header. Default = 1px solid hsl(var(--card-border)) (resolved at the call site).",
    "name": "--card-header-border-bottom",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) * var(--radius-ratio))",
    "name": "--card-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Flat resting cards: the hairline defines the surface; elevation is reserved for overlays. Set --card-shadow to a shadow value for opt-in elevation, or to initial to restore the live --shadow-sm fallback at the call site (including scoped shadow ramps).",
    "name": "--card-shadow",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Brand glow layer — invisible no-op at rest (rule #44). Paired AFTER --card-shadow in the surface box-shadow so a service can wash every card with the global glow, e.g. --card-glow: var(--shadow-glow), with no markup change.",
    "name": "--card-glow",
    "tier": "component",
    "value": "0 0 0 0 transparent"
  },
  {
    "description": "`hoverable` (antd `hoverable`) — the elevation a pointer-interactive card steps UP to on hover. One step above the resting `--card-shadow` on the same ramp, so a service that has already flattened or lifted every card keeps a proportional lift instead of a fixed one.",
    "name": "--card-hover-shadow",
    "tier": "component",
    "value": "var(--shadow-md)"
  },
  {
    "description": "Fill tint — subtle role wash over the card background (default transparent = invisible). Painted as an overlay so a service sets --card-tint: hsl(var(--primary) / 0.04) once.",
    "name": "--card-tint",
    "tier": "component",
    "value": "transparent"
  },
  {
    "description": "THE OTHER END OF THE TINT, AND ITS DIRECTION (gh#880 item 6). The wash used to be painted `linear-gradient(var(--card-tint), var(--card-tint))` — the same variable twice — which is a flat overlay wearing a gradient's clothes. A service that wanted a genuine two-colour wash had one value slot for two colours, so `--card-tint: A, B` expanded to `linear-gradient(A, B, A, B)`: a hard split, not a ramp. A glass card's rim highlight is a diagonal two-stop ramp (docs/GLASSMORPHISM-STANDARD.md §1), so this is the difference between \"a card can be glass\" and \"a card can be tinted\". BOTH ARE `initial` WITH THEIR DEFAULT AT THE CALL SITE, so the default value is the live `--card-tint` of whatever scope the card is in, not the one frozen at `<html>`, and the resting card paints `linear-gradient(to bottom, transparent, transparent)` exactly as before. default = var(--card-tint) — a single-colour wash stays flat",
    "name": "--card-tint-end",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = `to bottom`, the direction the two-stop form already had",
    "name": "--card-tint-angle",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "GLASS (gh#880 item 1) — `initial`, i.e. OFF, and the default must stay `initial` rather than `0px`. An element with a `backdrop-filter` becomes the containing block for its fixed descendants (the trap `src/styles/shell-layout.css` documents on the app-launcher scrim and `src/components/layout/affix.tsx` documents for Affix), and `blur(0px)` still promotes the box to a backdrop root. Unset, the whole declaration at `.ui-card` is invalid-at-computed-value-time and `backdrop-filter` keeps its own initial `none`, so no backdrop root is created and an `Affix` inside a Card still positions against the viewport. The saturate companion is shared: `--surface-backdrop-saturate` (tokens/foundation.css). default = none — a card blurs nothing",
    "name": "--card-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Accent edge — width of the semantic leading-edge stripe (data-accent). Tokenised (rule #44) so a service theme can re-tune it without forking CSS. The slot padding compensation in card-layout.css subtracts the same token, so content stays aligned on the shell whatever the rail width. default = var(--stroke-2xl), resolved at the call site (gh#906)",
    "name": "--card-accent-rail-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Accent placement `perimeter` (gh#12) — the FULL attention border. Two knobs so a service can tune the edge weight and the outer ring independently; the defaults reproduce the optical weight of `variant=\"featured\"` (1px border + 1px ring) in the card's own semantic accent tone instead of --primary. Structural strokes, like the base card hairline: both read the hairline step at their call sites since gh#906, so a theme restating the stroke scale moves them with everything else. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--card-accent-perimeter-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--card-accent-perimeter-ring-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`variant=\"featured\"` edge — role-mirror knob (docs/TOKENS.md). `initial` so the --primary default resolves at the CALL SITE and a scoped [data-tenant]/.dark override of --primary reaches it; a service points it anywhere (e.g. var(--attention)) to retint every featured card at once. Default = hsl(var(--primary)).",
    "name": "--card-featured-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--card-featured-ring-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-label-font-weight",
    "tier": "component",
    "value": "var(--font-weight-medium)"
  },
  {
    "description": "gh#1305 (ADR C12): sentence case, no tracking by default; a theme opts into small caps.",
    "name": "--stat-card-label-letter-spacing",
    "tier": "component",
    "value": "normal"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-label-letter-case",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-value-font-size",
    "tier": "component",
    "value": "var( --font-size-2xl, calc( var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio) ) )"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-value-line-height",
    "tier": "component",
    "value": "1.1"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-value-font-weight",
    "tier": "component",
    "value": "var(--font-weight-semibold)"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-hint-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-gap",
    "tier": "component",
    "value": "var(--space-stack-xs)"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-icon-size",
    "tier": "component",
    "value": "var(--icon-size-2xl)"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-icon-glyph-size",
    "tier": "component",
    "value": "var(--icon-size-lg)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--stat-card-icon-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Medallion tint — soft brand wash + brand glyph by default; a service retints by overriding --primary or these tokens directly (rule #44/#45). `initial` so the --primary default re-resolves at the call site under a scoped theme (no :root freeze). Defaults = hsl(var(--primary) / 0.1) fill · hsl(var(--primary)) glyph.",
    "name": "--stat-card-icon-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-icon-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--stat-card-delta-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "── ServiceLauncherCard (gh#219) ─────────────────────────────────────────────────── Internal rhythm of a launcher tile: one gap knob drives the vertical stack AND the icon↔title↔status row, so a service theme retunes the whole tile density once.",
    "name": "--card-service-launcher-space-gap",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "Semantic icon surface — 36px, the `--icon-size-2xl` step, multiplied by --scaling so the medallion still breathes with its sibling controls (the gh#328 rule: an icon that wants density says so itself). It read `var(--control-height-lg)` until gh#324: a CONTROL tier is the wrong axis for an icon box, and the bug was visible — `@media (pointer: coarse)` lifts the control ladder to the 44px tap floor, so on every touch device the medallion silently inflated to 48px while the glyph inside it stayed 20px.",
    "name": "--card-service-launcher-icon-size",
    "tier": "component",
    "value": "calc(var(--icon-size-2xl) * var(--scaling))"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-service-launcher-icon-glyph-size",
    "tier": "component",
    "value": "calc(var(--icon-size-lg) * var(--scaling))"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--card-service-launcher-icon-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Available-service medallion tint. `initial` (role-mirror rule, docs/TOKENS.md) so the role defaults resolve at the CALL SITE and a scoped [data-tenant]/.dark override reaches them. Defaults = hsl(var(--accent)) fill · hsl(var(--primary)) glyph.",
    "name": "--card-service-launcher-icon-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-service-launcher-icon-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Unavailable medallion tint — applied when the consumer supplies `disabledReason`, so an un-launchable service never reads as brand-live. `initial` for the same role-mirror reason. Defaults = hsl(var(--muted)) fill · hsl(var(--muted-foreground)) glyph.",
    "name": "--card-service-launcher-unavailable-icon-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-service-launcher-unavailable-icon-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Description prose — also drives the disabled-reason line and the catalog-CTA caption.",
    "name": "--card-service-launcher-description-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-service-launcher-description-line-height",
    "tier": "component",
    "value": "var(--line-height-body)"
  },
  {
    "description": "Mono metadata line (hostname · plan) — tighter leading than prose by design.",
    "name": "--card-service-launcher-metadata-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-service-launcher-metadata-line-height",
    "tier": "component",
    "value": "var(--line-height-normal)"
  },
  {
    "description": "Dashed catalog/add companion tile: kept tall enough to sit level with a populated launcher tile in the same grid row. Four control tiers ≈ medallion + title + description + action.",
    "name": "--card-service-launcher-cta-min-height",
    "tier": "component",
    "value": "calc(var(--control-height-lg) * 4)"
  },
  {
    "description": "Skeleton bar widths — shape-matched placeholders for the title and status badge.",
    "name": "--card-service-launcher-skeleton-title-width",
    "tier": "component",
    "value": "var(--space-12)"
  },
  {
    "description": "Card component tokens: card chrome derives from semantic layout tokens.",
    "name": "--card-service-launcher-skeleton-status-width",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "── Plot height tiers (size = xs|sm|md|lg) ─────────────────────────────────────────── `xs` is the canonical dashboard-summary-card density: a seven-day trend that sits under a KPI headline without stealing its vertical rhythm. A service retunes the whole scale here; a screen picks a step with the `size` prop.",
    "name": "--chart-trend-plot-height-xs",
    "tier": "component",
    "value": "3.5rem"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-trend-plot-height-sm",
    "tier": "component",
    "value": "5rem"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-trend-plot-height-md",
    "tier": "component",
    "value": "7.5rem"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-trend-plot-height-lg",
    "tier": "component",
    "value": "10rem"
  },
  {
    "description": "Active tier — chart-layout.css re-points this per `data-size`; overriding it directly pins one height for every trend regardless of `size`.",
    "name": "--chart-trend-plot-height",
    "tier": "component",
    "value": "var(--chart-trend-plot-height-xs)"
  },
  {
    "description": "── Bar marks ──────────────────────────────────────────────────────────────────────── Thin marks, a surface gap between neighbours and a rounded data-end anchored to the baseline (the data-visualization mark spec).",
    "name": "--chart-trend-bar-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--chart-trend-bar-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Ceiling on a single mark so a 3-point trend does not render slabs.",
    "name": "--chart-trend-bar-max-width",
    "tier": "component",
    "value": "1.5rem"
  },
  {
    "description": "Floor so a zero/absent value still reads as a plotted category rather than a hole. default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--chart-trend-bar-min-height",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Muted mark fill — role-mirror knob, declared `initial` so the role default re-resolves at the CALL SITE under `.dark` / `[data-tenant]` (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Default = hsl(var(--muted-foreground) / 0.75), which clears the 3:1 non-text contrast floor (WCAG 1.4.11) against the card surface.",
    "name": "--chart-trend-bar-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Opacity applied to the muted-fill role default.",
    "name": "--chart-trend-bar-background-alpha",
    "tier": "component",
    "value": "0.75"
  },
  {
    "description": "Emphasized (\"current\") mark fill — role-mirror knob. Default = hsl(var(--primary)).",
    "name": "--chart-trend-bar-emphasis-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── Baseline + category ticks ──────────────────────────────────────────────────────── Chrome defaults QUIET (rule #44): no baseline rule at rest. A service opts in with `--chart-trend-baseline-border: var(--stroke-hairline) solid hsl(var(--border));`.",
    "name": "--chart-trend-baseline-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-trend-tick-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-trend-tick-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Gap between the plot block and the optional activity footer slot.",
    "name": "--chart-trend-footer-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "── Category axis (horizontal BarChart) ──────────────────────────────────────────────── The category axis of a horizontal bar chart holds free text, and in Japanese that text is a company name of 8–10 full-width glyphs (100–125px at the tick size). recharts reserves a flat 60px whatever the ticks say, which painted those names OUTSIDE the plot box where the SVG clip cut them from the START — losing exactly the identifying `株式会社` (gh#409 · 1). The chart now measures its widest tick and sizes the axis from it. These two knobs own the limits of that: how much air sits between the tick and the plot, and how much of the canvas a category axis may take before labels are truncated at their END instead. A service that runs longer names raises the fraction; one that wants the bars to dominate lowers it.",
    "name": "--chart-category-axis-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Share of the canvas the category axis may occupy, 0..1. At the 1102px dashboard column this is ~440px — four times a 10-glyph 全角 name — so truncation is the exception, not the rule, while a pathological label still cannot squeeze the bars out of their own chart.",
    "name": "--chart-category-axis-max-fraction",
    "tier": "component",
    "value": "0.4"
  },
  {
    "description": "Stroke weight of the line, and of an area's top edge.",
    "name": "--chart-series-stroke-width",
    "tier": "component",
    "value": "2"
  },
  {
    "description": "Opacity of an area's filled band. Low by design: an area overlaps its neighbours, and the line above it is what carries the value.",
    "name": "--chart-area-fill-alpha",
    "tier": "component",
    "value": "0.2"
  },
  {
    "description": "Dash pattern of the cartesian background grid (any `stroke-dasharray` value; `none` = solid).",
    "name": "--chart-grid-line-dash",
    "tier": "component",
    "value": "3 3"
  },
  {
    "description": "Minimum cell edge per tier. `xs` is still 24px — a cell is a hover/focus target (WCAG 2.5.8).",
    "name": "--chart-heatmap-cell-size-xs",
    "tier": "component",
    "value": "1.5rem"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-heatmap-cell-size-sm",
    "tier": "component",
    "value": "1.75rem"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-heatmap-cell-size-md",
    "tier": "component",
    "value": "2rem"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-heatmap-cell-size-lg",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "Active tier — chart-layout.css re-points this per `data-size`.",
    "name": "--chart-heatmap-cell-size",
    "tier": "component",
    "value": "var(--chart-heatmap-cell-size-md)"
  },
  {
    "description": "Surface gap between neighbouring cells (the table's border-spacing).",
    "name": "--chart-heatmap-cell-gap",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio)), resolved at the call site",
    "name": "--chart-heatmap-cell-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "EMPTY cell outline — the non-colour cue that tells \"no data\" from a zero (WCAG 1.4.1). Role-mirror knob, `initial` at :root; default at the call site = `var(--stroke-hairline) dashed hsl(var(--muted-foreground))`.",
    "name": "--chart-heatmap-empty-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Top-N emphasis ring — a SHAPE cue, never colour alone. Colour is a role-mirror knob (default `hsl(var(--foreground))` at the call site); width is a plain constant.",
    "name": "--chart-heatmap-emphasis-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-heatmap-emphasis-width",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "The pinned row-header column paints over cells scrolled beneath it, so it needs a ground. Role-mirror knob; default = `hsl(var(--card))` at the call site.",
    "name": "--chart-heatmap-row-header-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-heatmap-tick-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Legend rhythm: the swatch edge and the gap between legend items / plot ↔ legend.",
    "name": "--chart-heatmap-legend-swatch-size",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
    "name": "--chart-heatmap-legend-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Bubble fill. `initial` so the --muted default re-resolves at the CALL SITE under a scoped theme; a :root binding to a role var freezes at :root (docs/TOKENS.md — the :root freeze rule). Documented default = hsl(var(--muted)).",
    "name": "--chat-bubble-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Ink on that fill — role-mirror knob, documented default = hsl(var(--foreground)).",
    "name": "--chat-bubble-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The 1px edge of an `outlined` bubble. Decorative chrome, so it mirrors --border, not --input (docs/TOKENS.md — `--border` vs `--input`). Documented default = hsl(var(--border)).",
    "name": "--chat-bubble-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--chat-bubble-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Gap between the avatar column and the message column.",
    "name": "--chat-bubble-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "The measure a bubble never exceeds. Long-form assistant prose past ~70 characters per line stops being readable, and a chat pane is as wide as the window (#45 — a service retunes the measure to its own column).",
    "name": "--chat-bubble-max-inline-size",
    "tier": "component",
    "value": "34rem"
  },
  {
    "description": "Avatar box. Role-mirror of a RE-SCOPED tier (--control-height is re-declared per density and by the auth shell), so it is `initial` + a call-site fallback for the same reason a colour knob is. Documented default = var(--control-height).",
    "name": "--chat-bubble-avatar-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Inner inset of the bubble body, at the default `md` step. The xs/sm/lg steps re-declare these two on the element itself (styles/data-display-layout.css).",
    "name": "--chat-bubble-padding-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "ChatBubble / ChatBubbleList component tokens (@godxjp/chat since v32) — one message in a conversation, and the feed it lives in. NAMING NOTE: the roadmap spelled the surface knob `--chat-bubble-surface`. `surface` is not one of the property words `check:token-tiers` accepts for the `--{component}-{part}-{property}` shape, so the knob ships as `--chat-bubble-background` — the same word every other component tier uses for the same role (`--card-background`, `--list-row-unread-background`).",
    "name": "--chat-bubble-padding-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Vertical rhythm BETWEEN messages in a ChatBubbleList.",
    "name": "--chat-bubble-list-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Inset the \"jump to latest\" affordance keeps from the block-end edge of the feed.",
    "name": "--chat-bubble-list-jump-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "The typed-so-far caret drawn while `typing` animates. Role-mirror knob, documented default = hsl(var(--muted-foreground)). Never the only signal: the article also carries `aria-busy` and a localized sr-only \"typing\" string.",
    "name": "--chat-bubble-typing-caret-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--chat-bubble-typing-caret-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "One line box tall, so the caret matches whatever type ramp the bubble is rendering at rather than a fixed pixel height a service theme could not move.",
    "name": "--chat-bubble-typing-caret-height",
    "tier": "component",
    "value": "1em"
  },
  {
    "description": "The short line of the two-line loading Skeleton — a ragged second line is what makes the placeholder read as prose rather than as a bar chart. A theme can retune the raggedness.",
    "name": "--chat-bubble-skeleton-short-inline-size",
    "tier": "component",
    "value": "60%"
  },
  {
    "description": "Status-tinted bubbles (`tone`) wash the role colour exactly like Alert does, so an error bubble and an error banner agree. Never colour alone — the bubble also renders a localized sr-only tone word.",
    "name": "--chat-bubble-tone-background-alpha",
    "tier": "component",
    "value": "0.08"
  },
  {
    "description": "ChatBubble / ChatBubbleList component tokens (@godxjp/chat since v32) — one message in a conversation, and the feed it lives in. NAMING NOTE: the roadmap spelled the surface knob `--chat-bubble-surface`. `surface` is not one of the property words `check:token-tiers` accepts for the `--{component}-{part}-{property}` shape, so the knob ships as `--chat-bubble-background` — the same word every other component tier uses for the same role (`--card-background`, `--list-row-unread-background`).",
    "name": "--chat-bubble-tone-border-alpha",
    "tier": "component",
    "value": "0.35"
  },
  {
    "description": "The message column of an `end`-placed (own) bubble. Role-mirror knobs so a service can tint \"my\" messages without touching the assistant's. Documented defaults = hsl(var(--primary) / 0.1) and hsl(var(--foreground)).",
    "name": "--chat-bubble-end-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ChatBubble / ChatBubbleList component tokens (@godxjp/chat since v32) — one message in a conversation, and the feed it lives in. NAMING NOTE: the roadmap spelled the surface knob `--chat-bubble-surface`. `surface` is not one of the property words `check:token-tiers` accepts for the `--{component}-{part}-{property}` shape, so the knob ships as `--chat-bubble-background` — the same word every other component tier uses for the same role (`--card-background`, `--list-row-unread-background`).",
    "name": "--chat-bubble-end-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Floor and ceiling of the draft box, both `initial` — and that is load-bearing, not tidiness. Their defaults READ `--control-height`, which is re-declared per size step on the composer itself (`.ui-control-surface[data-size=\"sm\"]` and friends). Bound here at `:root`, each one would resolve ONCE against the root tier and freeze: measured in Chromium, all four of `size=\"xs|sm|md|lg\"` rendered at an identical 55px box. `initial` sends the fallback chain in `data-entry-layout.css` back to the CALL SITE, where the step's own `--control-height` is in scope. Same rule as ListRow's dividers and the compact-row knobs (docs/TOKENS.md — the :root freeze rule). Default floor = var(--control-height) — exactly one control row. Default ceiling = calc(var(--control-height) * 5) — past it the draft scrolls itself instead of pushing the page. A MULTIPLIER, never `calc(var(--control-height) ± …)`, which silently re-derives a tier (check:control-sizing).",
    "name": "--chat-composer-min-height",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ChatComposer component tokens — the message input of a conversation (Ant Design X `Sender`). The composer is a CONTROL, so its box height is not its own decision: both bounds below are expressed in the `--control-height` tier, which is density-aware. A resting one-line composer therefore lines up with the Button beside it, and every size step (`data-size`) moves both bounds together. Never restate either as a literal length — see docs/TOKENS.md and `pnpm check:control-sizing`.",
    "name": "--chat-composer-max-height",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Gap between the header / draft row / footer bands.",
    "name": "--chat-composer-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Inset of the composer frame. The draft box itself is borderless — the frame IS the boundary, so two nested rounded borders never appear.",
    "name": "--chat-composer-padding-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "ChatComposer component tokens — the message input of a conversation (Ant Design X `Sender`). The composer is a CONTROL, so its box height is not its own decision: both bounds below are expressed in the `--control-height` tier, which is density-aware. A resting one-line composer therefore lines up with the Button beside it, and every size step (`data-size`) moves both bounds together. Never restate either as a literal length — see docs/TOKENS.md and `pnpm check:control-sizing`.",
    "name": "--chat-composer-padding-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Gap between the prefix slot, the draft box and the trailing actions.",
    "name": "--chat-composer-row-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Corner shape — `initial` so the control default re-resolves at the call site under a scoped theme (a :root binding to a role var freezes at :root). Default = var(--control-radius).",
    "name": "--chat-composer-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Divider under the `header` slot — `initial`, documented default = 1px solid hsl(var(--border)), so a service retunes the chrome once instead of per composer.",
    "name": "--chat-composer-header-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Type scale of the footer hint line (a token counter, a \"Shift+Enter for a new line\" hint).",
    "name": "--chat-composer-footer-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height-compact",
    "tier": "component",
    "value": "var(--band-height-sm)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height-default",
    "tier": "component",
    "value": "var(--band-height-lg)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height-comfortable",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-padding-x-compact",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-padding-x-default",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-padding-x-comfortable",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Held width for `width=\"bounded\"` controls (gh#375). `min()` so the value is a ceiling on a desktop bar and a share of the viewport on a phone, never a fixed rem that overflows it.",
    "name": "--control-bounded-width",
    "tier": "component",
    "value": "min(15rem, 48vw)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height",
    "tier": "component",
    "value": "calc(var(--control-height-default) * var(--scaling))"
  },
  {
    "description": "Adjacent control sizes, derived from the active --control-height. The ±step is scaled too so the whole control ladder stays proportional under --scaling.",
    "name": "--control-height-sm",
    "tier": "component",
    "value": "calc(var(--control-height) - calc(0.25rem * var(--scaling)))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height-lg",
    "tier": "component",
    "value": "calc(var(--control-height) + calc(0.25rem * var(--scaling)))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height-xs",
    "tier": "component",
    "value": "calc(var(--control-height) - calc(0.5rem * var(--scaling)))"
  },
  {
    "description": "THE GLOVE TIER (gh#1304) — `size=\"touch\"` on Button, Segmented, Toggle/ToggleGroup and `RadioGroup optionType=\"button\"`. 56px: wet or gloved hands at a food-production station need more than the 44px WCAG 2.2 SC 2.5.5 target, so this sits one band above `--number-input-touch-height`. A band, NOT derived from `--control-height` — not by density, not by a shell's tier — because the floor is the hand's, not the layout's.",
    "name": "--control-height-touch",
    "tier": "component",
    "value": "var(--band-height-3xl)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-padding-x",
    "tier": "component",
    "value": "var(--control-padding-x-default)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-gap-sm",
    "tier": "component",
    "value": "var(--space-inline-xs)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-radius",
    "tier": "component",
    "value": "var(--radius)"
  },
  {
    "description": "Match the default 6px field corner while retaining an independent Button knob. The utility consumes a concrete value, so this remains a root alias; scoped services override --button-radius directly. Pill and sharp shapes keep their own tokens.",
    "name": "--button-radius",
    "tier": "component",
    "value": "var(--radius)"
  },
  {
    "description": "THE BUTTON'S OWN SURFACE — one knob per painted variant (gh#880, standard §1). Every variant painted a bare role (`hsl(var(--primary))`, `hsl(var(--background))`, `hsl(var(--secondary))`, `hsl(var(--destructive))`) with no knob of its own, so the only way to retint a button was to retint the ROLE — and `--primary` is also the link ink, the focus mark and a chart series. There was no way to say \"this button is translucent\" without saying it about eight other things. WHY BUTTONS AT ALL. namethatui's source draws the line this library needed: glassmorphism is a decorative skin for ANY surface including controls, while Apple's Liquid Glass reserves glass for the floating control layer above opaque content. A glass page with a solid primary button on it is the Liquid Glass split applied backwards. FOUR FILLS, NOT SIX. `ghost` and `link` paint no resting surface, so they have nothing to knob. The HOVER fills are deliberately not knobs either: they already resolve from roles at their own call sites (`--primary-hover`, `--accent`, `--secondary`), so a theme reaches them today — the documented consequence being that a glass RESTING fill with an untouched hover gives a button that turns opaque under the pointer, and a theme that wants glass on both moves the role too. ONE BLUR FOR THE WHOLE COMPONENT, because the material is one decision per component and the variants are one component. `initial`, so unset there is no blur and no backdrop root. default = hsl(var(--primary)) at the call site",
    "name": "--button-default-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--destructive)) at the call site",
    "name": "--button-destructive-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--background)) at the call site",
    "name": "--button-outline-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--button-outline-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--input)) at the call site",
    "name": "--button-outline-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--secondary)) at the call site",
    "name": "--button-secondary-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--button-secondary-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE ONE BUTTON KNOB THAT IS INK, NOT A FILL (gh#884) — the `link` variant's text colour. The others above are backgrounds, so their contrast is owned by the label token that rides on them; this one IS the label, over a surface the library does not control. `--primary` is only ever guaranteed against `--primary-foreground`, so a light seed or a translucent panel makes the default illegible (measured 1.43:1 at `#FFD400`, 1.10:1 on glass) and the service sets this. default = hsl(var(--primary)) at the call site",
    "name": "--button-link-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = none — a button blurs nothing",
    "name": "--button-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control surface knobs — font-size, border width and resting shadow of every `.ui-control` (input / picker trigger). Tokenised so a service theme tunes them once instead of each component hard-coding Tailwind utilities. Defaults preserve the historical look (font-size-base, 1px border, shadow-xs).",
    "name": "--control-font-size",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--control-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-shadow",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-icon-size",
    "tier": "component",
    "value": "calc(var(--icon-size-md) * var(--scaling))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-icon-size-sm",
    "tier": "component",
    "value": "calc(var(--icon-size-sm) * var(--scaling))"
  },
  {
    "description": "VALIDATION STATUS — antd's `status` axis (docs/DESIGN-AUTHORITY.md names Ant Design the taxonomy authority). Only the FOCUS half is a knob: the boundary itself has to be painted from a Tailwind utility, because `border-input` sits in a later cascade layer than this file's component rules and would win over any of them (measured in Chromium — see components/data-entry/control-appearance.ts). The error boundary therefore reuses the role `aria-invalid:border-destructive` already paints, and cannot drift into a second red. The warning halo borrows the ERROR halo's alpha rather than inventing a second opacity: antd derives both from one `colorXxxOutline` recipe, and only the error one is defined in this tier.",
    "name": "--control-status-warning-border-color",
    "tier": "component",
    "value": "var(--warning)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-status-warning-glow-color",
    "tier": "component",
    "value": "var(--warning)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-status-warning-glow-alpha",
    "tier": "component",
    "value": "var(--control-outline-error-alpha)"
  },
  {
    "description": "THE BAND A NumberInput TAKES ON A COARSE POINTER, and the one control in this package that needs a taller one than rule #24's 44px floor. Its two steppers are STACKED inside the field, so each can only ever be half the band. Measured in Chromium (Playwright touch emulation, `(pointer: coarse)` matching) before this token: the default NumberInput was 44px and each stepper **24×19px**, with their centres 20px apart. WCAG 2.2 SC 2.5.8 wants 24×24, and the Spacing exception does not rescue it either — that needs 24px-diameter circles centred on each box NOT to intersect, and at 20px apart they do. 44px cannot be made to work: half of it is 22px whatever the inset and gap. 48px can, exactly — two 24px halves, no inset, no gap — so the band moves up one step for this control alone, and only where a coarse pointer says it matters. `size=\"lg\"` already lands on 48px there, so it gains the same 24×24 for free; `xs` and `sm` stay where the consumer put them (a deliberately smaller control is the consumer's trade, the same way rule #24 already treats them). A service that wants the 44px row back sets this to `var(--band-height-xl)` and takes 22px targets with it.",
    "name": "--number-input-touch-height",
    "tier": "component",
    "value": "var(--band-height-2xl)"
  },
  {
    "description": "`size=\"touch\"` (gh#1304). The SPACE between two glove targets: ToggleGroup items, Segmented segments and the buttons of a `RadioGroup optionType=\"button\"` bar stand this far apart at the touch step (8px), so a gloved press on one edge cannot land on the neighbour. Button has no siblings of its own — lay a row of touch Buttons out with a gap of at least this.",
    "name": "--control-touch-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Button's inline inset at the touch step — one rung under `lg`'s, because a touch Button is usually a short verdict (良 / 否) and its 56px min-inline-size already makes the box.",
    "name": "--button-touch-space-inline",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "CHROME VARIANT — antd's `variant` axis. `outlined` needs no token: it is what a field already draws. `filled` swaps the boundary for a tinted surface; `borderless` drops both. Kept as knobs so a service theme can retune the dense-form treatment once, globally.",
    "name": "--control-variant-filled-background",
    "tier": "component",
    "value": "var(--muted)"
  },
  {
    "description": "default = var(--accent), resolved at the call site (the freeze rule)",
    "name": "--control-variant-filled-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--control-variant-filled-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Character counter — antd `count`. Quiet by default; loud only once the ceiling is passed.",
    "name": "--control-count-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--control-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`initial`, not `var(--text-error)`: a binding here computes ONCE at `:root`, so a `[data-tenant]` re-theming the error ink would keep this counter on the root's answer (docs/TOKENS.md, the freeze rule). The default lives at the rule that paints it.",
    "name": "--control-count-exceeded-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-count-space-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--textarea-count-inset-block-end",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--textarea-count-inset-inline-end",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "antd `addonBefore` / `addonAfter` — a segment welded outside the field's own box.",
    "name": "--input-addon-background",
    "tier": "component",
    "value": "var(--muted)"
  },
  {
    "description": "default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--input-addon-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--input-addon-padding-inline",
    "tier": "component",
    "value": "var(--control-padding-x)"
  },
  {
    "description": "Switch `checkedChildren` / `unCheckedChildren` and `loading`.",
    "name": "--switch-content-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-content-space-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-spinner-size",
    "tier": "component",
    "value": "calc(var(--switch-thumb-size) - var(--space-1))"
  },
  {
    "description": "Slider marks / dots / value bubble — antd `marks`, `dots`, `tooltip`.",
    "name": "--slider-mark-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--slider-mark-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-mark-space-block-start",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-dot-size",
    "tier": "component",
    "value": "var(--slider-track-height)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-dot-background",
    "tier": "component",
    "value": "var(--background)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-dot-border-color",
    "tier": "component",
    "value": "var(--border)"
  },
  {
    "description": "default = var(--primary), resolved at the call site",
    "name": "--slider-dot-active-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-tooltip-background",
    "tier": "component",
    "value": "var(--popover)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-tooltip-color",
    "tier": "component",
    "value": "var(--popover-foreground)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-tooltip-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--slider-tooltip-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-tooltip-padding-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-tooltip-offset-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Radio `optionType=\"button\"` — antd's welded radio bar.",
    "name": "--choice-button-background",
    "tier": "component",
    "value": "var(--background)"
  },
  {
    "description": "default = var(--foreground), resolved at the call site (gh#906)",
    "name": "--choice-button-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--choice-button-border-color",
    "tier": "component",
    "value": "var(--input)"
  },
  {
    "description": "The four brand-coloured knobs default at the call site — a `:root` binding would freeze on the root's primary and ignore a scoped [data-tenant] re-theme (docs/TOKENS.md, the freeze rule). default = var(--primary)",
    "name": "--choice-button-selected-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--primary)",
    "name": "--choice-button-selected-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--choice-button-selected-border-color-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--primary)",
    "name": "--choice-button-solid-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--primary-foreground)",
    "name": "--choice-button-solid-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Ring knobs for the two controls that historically wanted a softer mark than the global default — both are filled surfaces where the ring was felt to read as a second border. THE ALPHA IS 1, AND THAT IS THE CRITERION TALKING. WCAG 2.2 SC 1.4.11 asks for ≥3:1 between the focused and unfocused states of the pixels that mark focus, and colour is the whole of that bar. Measured against this palette, the focus hue at alpha 0.35 composites to 1.64:1 against the page (0.45 → ≈1.90); nothing in that band is a compliant indicator, so \"softer\" was buying taste at the cost of the criterion. The softening now comes from the HALO (`--focus-ring-glow-*`), which sits outside the opaque stop and is free to be as quiet as it likes because it is decoration rather than the indicator. The knobs stay — a service can still trade the criterion away deliberately — but the shipped default no longer makes that trade silently. Guarded by src/tokens/__tests__/focus-ring-contrast.test.ts. default = var(--stroke-lg), resolved at the call site (gh#906)",
    "name": "--toggle-focus-ring-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--toggle-focus-ring-alpha",
    "tier": "component",
    "value": "1"
  },
  {
    "description": "Mark width for a BORDERED FIELD. This knob exists because a field is the one control that already owns a boundary, so it is the one place the mark could plausibly be dropped and the recoloured border left to carry the state — which is the established treatment for a bordered field: a primary border plus a translucent halo, nothing in between. It ships at the same step as `--focus-outline-weight`, the hairline stroke, so a field and a button carry the same weight. A gate asserts the two stay equal, because this token cannot literally READ the global one without freezing at :root (docs/TOKENS.md, the freeze rule). It feeds `--focus-ring-weight`, never `--focus-ring-width`. The width is `weight × --focus-outline`, so a field's mark is still switched off with everything else — a knob that bypassed the switch would be a hole in it. If a service sets this, note the unit: the halo's spread is summed with a length in `calc()`, and CSS refuses to add a unitless number to a length — a bare `0` makes the whole box-shadow invalid at computed-value time and it resolves to NONE. Write `0px`. modern 2px mark, matching global focus",
    "name": "--control-focus-ring-width",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "Outline-form gaps — marks where a radius-hugging ring would touch the glyph.",
    "name": "--rating-focus-ring-offset",
    "tier": "component",
    "value": "2px"
  },
  {
    "description": "Star paint (gh#694). HSL components, `initial` so the default resolves at the star — a `:root` binding would freeze on the root's role and ignore a scoped [data-tenant] theme (the freeze rule). Filled default = var(--warning); empty default = var(--muted-foreground) at the alpha.",
    "name": "--rating-star-filled-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--rating-star-empty-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--rating-star-empty-alpha",
    "tier": "component",
    "value": "0.45"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--checkbox-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--checkbox-size",
    "tier": "component",
    "value": "calc(1rem * var(--scaling))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--checkbox-size-compact",
    "tier": "component",
    "value": "0.875rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--checkbox-size-comfortable",
    "tier": "component",
    "value": "1.125rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--choice-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--choice-group-gap-x",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--choice-group-gap-y",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--choice-description-gap",
    "tier": "component",
    "value": "0.125rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--choice-control-offset",
    "tier": "component",
    "value": "0.125rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-width",
    "tier": "component",
    "value": "calc(2.25rem * var(--scaling))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-width-compact",
    "tier": "component",
    "value": "2rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-width-comfortable",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-height",
    "tier": "component",
    "value": "calc(1.25rem * var(--scaling))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-height-compact",
    "tier": "component",
    "value": "1.125rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-height-comfortable",
    "tier": "component",
    "value": "1.375rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-thumb-size",
    "tier": "component",
    "value": "calc(1rem * var(--scaling))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-thumb-size-compact",
    "tier": "component",
    "value": "0.875rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-thumb-size-comfortable",
    "tier": "component",
    "value": "1.125rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-thumb-translate",
    "tier": "component",
    "value": "calc(1rem * var(--scaling))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-thumb-translate-compact",
    "tier": "component",
    "value": "0.875rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-thumb-translate-comfortable",
    "tier": "component",
    "value": "1.125rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-track-height",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-thumb-size",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "A vertical slider fills its container's block size; this keeps one visible in a container that has none (antd leaves it at 0 and relies on the page to size it).",
    "name": "--slider-vertical-min-block-size",
    "tier": "component",
    "value": "10rem"
  },
  {
    "description": "InputOTP slot box (gh#233). Its own knob so an auth surface can widen the 6-slot challenge row to fill a wide panel WITHOUT re-scoping --control-height (which would resize every other control in the same card). Declared `initial` — the tier-mirror form of the role-mirror rule in docs/TOKENS.md: the default must resolve at the CALL SITE (`var(--otp-slot-size, var(--control-height))`), because `--otp-slot-size: var(--control-height)` here would FREEZE at the :root tier (32px) and an OTP row inside `.ui-auth-shell[data-variant=\"canonical\"]`, which re-scopes --control-height to 36px, would silently shrink. Verified in Chromium: 36px before and after. A service opts in with a NAMED tier (`var(--control-height-lg)`), never a calc. default = var(--control-height) at the call site",
    "name": "--otp-slot-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Per-AXIS overrides of the slot box (gh#12). --otp-slot-size stays the square shorthand; these two win over it when set, so a code field can be WIDER-than-tall or TALLER-than-wide without abandoning the token. A canonical device-grant code field is 27.5x52 per slot (a 4-slot `appearance=\"grouped\"` box of 112x54 with its 1px group border) — not expressible with one square knob, which is why grouped OTP measured 146x38 against that artboard. `initial` for the same tier-mirror reason as --otp-slot-size: the whole fallback chain (axis → square → --control-height) must resolve at the CALL SITE so a shell that re-scopes --control-height still reaches an OTP row that sets neither axis. default = var(--otp-slot-size, var(--control-height))",
    "name": "--otp-slot-inline-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--otp-slot-size, var(--control-height))",
    "name": "--otp-slot-block-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Main-axis alignment of the whole OTP row (rule #44/#45 — chrome is a token, default quiet). `flex-start` is the historical behaviour, so an existing field is byte-identical; a centred code field is `align=\"center\"` on InputOTP (which wins over this knob) or this token set once in a service theme. It exists because EVERY consumer was wrapping .ui-otp-container in a flex-centring div to get a centred challenge.",
    "name": "--otp-container-align",
    "tier": "component",
    "value": "flex-start"
  },
  {
    "description": "Checked/on/active fills — `initial` so the --primary default re-resolves at the call site under a scoped theme (a :root binding to var(--primary) freezes at the :root value and a scoped [data-tenant] override of --primary never reaches it). A service retints the \"selected\" state by overriding these directly. Defaults = hsl(var(--primary)) · slider track 0.2α.",
    "name": "--checkbox-checked-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--switch-checked-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--toggle-on-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Pressed Toggle LABEL colour — the pair to --toggle-on-background, `initial` like it (default hsl(var(--primary-foreground)) at the call site). Without it a service that quietened the pressed fill to a pale tint was left with white text on it.",
    "name": "--toggle-on-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`Toggle variant=\"quiet\"` pressed state (gh#1257) — role-mirror knobs, `initial`; defaults at the call site: fill hsl(var(--secondary)), label hsl(var(--foreground)), counter hsl(var(--background)) / hsl(var(--foreground)).",
    "name": "--toggle-quiet-on-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--toggle-quiet-on-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--toggle-quiet-on-count-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--toggle-quiet-on-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-track-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--slider-range-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Switch OFF track fill (gh#315) — `initial`, default hsl(var(--input)). Its own knob so a service can quieten the off-track without dragging the --input control-boundary role back below the WCAG SC 1.4.11 floor (rule #45); whatever you set still owes 3:1 against the page and against the thumb (--background), or \"off\" stops being a visible state.",
    "name": "--switch-unchecked-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--switch-unchecked-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "A labelled OFF track defaults to muted-foreground rather than the input boundary role: text needs 4.5:1, not the 3:1 required of an empty track. Pair custom track fills with this foreground; the default background role contrasts in both light and dark themes.",
    "name": "--switch-content-unchecked-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ColorPicker — width of the hex text field beside the swatch.",
    "name": "--color-picker-input-width",
    "tier": "component",
    "value": "6.5rem"
  },
  {
    "description": "ColorPicker `presets` (gh#1055). The swatch box IS the radio's pointer target, so it sits on the WCAG 2.2 SC 2.5.8 floor (antd's own preset block is 24px too) and never rides --scaling below it. The gap leaves room for the checked ring, which is drawn outside the box.",
    "name": "--color-picker-preset-size",
    "tier": "component",
    "value": "var(--touch-target-min)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--color-picker-preset-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--color-picker-presets-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Command / CommandPalette — list height, inner paddings and the palette's own box.",
    "name": "--command-list-max-height",
    "tier": "component",
    "value": "min(300px, 50vh)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-input-padding-x",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-group-padding",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-item-padding-y",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-item-padding-x",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "The gap between a row's leading mark and its label. `.ui-command-item` is a flex row and had NO gap at all, so every command/palette/picker row with an icon rendered its glyph flush against the text — measured at 0px between an organization mark and its name. It reads --control-gap because a command row is a control row: the same distance the trigger it opened from already puts between its own icon and label.",
    "name": "--command-item-gap",
    "tier": "component",
    "value": "var(--control-gap)"
  },
  {
    "description": "`Command split` (antd List `split`, gh#699) — a list drawn as ONE ruled box. --command-list-split-padding the group/list padding under split: 0, so no inner frame separates the rows from the panel edge. --command-list-split-inset the inline inset the SURFACE puts between the panel edge and the list, which a split row cancels (negative margin) and pays back as padding so its fill and rule still meet both edges. 0 for a bare Command; OrgSwitcher sets its column inset. --command-item-divider-width the hairline between rows. --command-item-divider-color ROLE-MIRROR KNOB — `initial` here, default resolved at the call site = var(--border) (HSL channels; docs/TOKENS.md).",
    "name": "--command-list-split-padding",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-list-split-inset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--command-item-divider-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-item-divider-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-palette-width",
    "tier": "component",
    "value": "35rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-palette-inset-top",
    "tier": "component",
    "value": "calc(var(--space-6) * 4)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-palette-viewport-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-palette-hint-padding-y",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-palette-hint-padding-x",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-palette-hint-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "SearchInput — the inset the leading/trailing icons sit at, and the field padding derived from it so the text never runs under an icon.",
    "name": "--search-input-edge-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-input-start-padding",
    "tier": "component",
    "value": "calc( var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-input-end-padding",
    "tier": "component",
    "value": "calc( var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap) )"
  },
  {
    "description": "The --font-size-xs tier, spelled once per control that reads it, so a service can retune a single one of them without moving the whole scale.",
    "name": "--choice-description-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--color-picker-hex-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--color-picker-presets-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--command-group-heading-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-input-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tag-input-chip-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--toggle-sm-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--toggle-xs-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-sm-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "TRAILING AFFIX — the clear ✕ / chevron overlay a select-family trigger parks at its inline end. Select, SearchSelect and TagInput each hard-coded the same `end-2 size-6 rounded-sm opacity-50` stack independently (#319), so a service retuning affix weight had to chase the literal through several components. One shared set of knobs instead — this is a CONTROL-level concern, not a per-component one.",
    "name": "--control-affix-inset-inline-end",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-affix-action-size",
    "tier": "component",
    "value": "1.5rem"
  },
  {
    "description": "Shared coarse-pointer floor; independent of density and the desktop glyph size.",
    "name": "--control-affix-touch-target-size",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--control-affix-action-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-affix-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Resting weight of an affix glyph — it must read as secondary until hovered/focused.",
    "name": "--control-affix-rest-alpha",
    "tier": "component",
    "value": "0.5"
  },
  {
    "description": "2.25rem — the room a single trailing affix needs. Written as a raw rem because the literal it replaced (`pe-9`) is a flat Tailwind step, not a density-scaled one.",
    "name": "--control-trigger-space-inline-end",
    "tier": "component",
    "value": "2.25rem"
  },
  {
    "description": "INSIDE-FIELD AFFIX — the leading/trailing controls Input and TimePicker render WITHIN the field box, as opposed to the overlay affix (--control-affix-*) that Select and SearchSelect park on top of a trigger. Both carried the identical literal stack (#319). Because these sit on the field's own surface rather than over it, they rest a touch heavier than the overlay pair — that difference is the reason the two sets stay separate.",
    "name": "--control-inline-affix-size",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-inline-affix-icon-size",
    "tier": "component",
    "value": "var(--control-affix-icon-size)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-inline-affix-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-inline-affix-inset-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-inline-affix-rest-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "Inline room the field reserves so its text never runs under a single affix.",
    "name": "--control-inline-affix-space-inline-end",
    "tier": "component",
    "value": "2.25rem"
  },
  {
    "description": "Input centres its affix on the field's single line; a textarea has no single line to centre on, so its clear control parks at the top-end corner instead.",
    "name": "--textarea-clear-inset-block-start",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "MULTILINE BOX — the block padding of `.ui-control-multiline` (Textarea). It was a bare `--space-2` inside the padding shorthand, which made it unreachable for a service that runs a denser composer, AND it is the constant the auto-grow row maths has to add back, so the two had to read the same knob or drift (#45).",
    "name": "--control-multiline-padding-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "The unit a \"row\" is measured in. `initial` on purpose: the call site reads `var(--textarea-autogrow-line-height, var(--line-height-normal))`, so a service that retunes the multiline line-height for CJK legibility retunes the ceiling with it (#46). Unitless — it is multiplied by `--control-font-size`.",
    "name": "--textarea-autogrow-line-height",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Floor of the grown box, in text rows. The `minRows` prop overrides per instance — the same theme-global / prop-local priority as `--form-label-width` vs `labelWidth`. The floor is additionally clamped up to `--control-height` so a resting one-row composer still lines up with the Input / Button beside it instead of undercutting the control tier.",
    "name": "--textarea-autogrow-min-height-rows",
    "tier": "component",
    "value": "1"
  },
  {
    "description": "Ceiling of the grown box, in text rows; past it the control scrolls internally instead of pushing the page. `maxRows={0}` sets this to `infinity` for an unbounded box.",
    "name": "--textarea-autogrow-max-height-rows",
    "tier": "component",
    "value": "8"
  },
  {
    "description": "The non-text part of the box the row maths must add back: block padding + border, both edges. `.ui-textarea-autogrow--ghost` re-declares it without the border, because the ghost variant drops its own chrome.",
    "name": "--textarea-autogrow-box-inset",
    "tier": "component",
    "value": "calc( (var(--control-multiline-padding-block) + var(--control-border-width, var(--stroke-hairline))) * 2 )"
  },
  {
    "description": "COMPOSITE FIELD — the bordered box that wraps two inputs plus a separator (date/month range pickers) or one input plus affixes. Shared so the four range/picker fields cannot drift into four slightly different boxes.",
    "name": "--control-composite-field-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "The <input type=file> button is a browser-owned box we restyle; it sits one tier below the field so it reads as a control INSIDE the control.",
    "name": "--input-file-button-height",
    "tier": "component",
    "value": "var(--band-height-sm)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--input-file-button-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "SEARCH-SELECT — the Popover+Command combobox. Its panel geometry was baked onto the component as arbitrary values (`max-w-[min(32rem,calc(100vw-1.5rem))]`), so a service could not widen the panel or change the viewport gutter without forking.",
    "name": "--search-select-panel-max-width",
    "tier": "component",
    "value": "32rem"
  },
  {
    "description": "Seat for a NUMERIC `popupMatchSelectWidth`. `auto` is the inert default — the knob only does anything once a call site sets it, and then the value is that consumer's own measurement.",
    "name": "--search-select-panel-inline-size",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-panel-viewport-inset",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-list-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "antd `listHeight` writes this per instance; `none` lets the panel's own available height win. antd listHeight 256px; the list scrolls inside",
    "name": "--search-select-list-max-height",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-footer-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-option-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Picker rows read compact (~34px), like Linear / GitHub label pickers, not body-text rows.",
    "name": "--search-select-option-line-height",
    "tier": "component",
    "value": "var(--line-height-tight)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-option-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-option-sublabel-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-status-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-status-space-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Empty/error states sit alone in the panel, so they get a taller, centred block.",
    "name": "--search-select-placeholder-space-block",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-status-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--search-select-spinner-size",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "CASCADER — column browser + flat search list. Its option rows, column widths and panel paddings were literals on the component (#319), so a service could not widen a column to fit longer JA labels or tighten the row rhythm without forking.",
    "name": "--cascader-column-min-width",
    "tier": "component",
    "value": "9rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-columns-max-height",
    "tier": "component",
    "value": "min(280px, 50vh)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-list-max-height",
    "tier": "component",
    "value": "min(300px, 50vh)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-panel-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-option-space-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-option-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-option-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-option-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-option-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "The flat search result row is denser than a column row — it has no chevron to balance.",
    "name": "--cascader-result-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-result-space-block",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--cascader-result-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-result-icon-space-inline-end",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--cascader-empty-space-block",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "SELECT — the Radix listbox surface. Its popup shares the menu row rhythm (--menu-item-*), so only what is genuinely its own lives here (#319).",
    "name": "--select-content-max-height",
    "tier": "component",
    "value": "24rem"
  },
  {
    "description": "Seat for a NUMERIC `popupMatchSelectWidth` on the plain listbox. `auto` is the inert default.",
    "name": "--select-content-inline-size",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "THE LISTBOX SURFACE — and it is deliberately NOT the trigger's (gh#880, docs/GLASSMORPHISM-STANDARD.md §4b). Select is two problems: the TRIGGER is a form field and takes `--control-surface-background` with every other field, while the LISTBOX is an overlay that opens over arbitrary page content and needs the most opaque fill in the system — a 7-line menu over a photograph is unreadable at a card's alpha. One knob for both would make the correct answer for one the wrong answer for the other. `initial` with the role default at the call site, the same shape `--popover-surface-background` uses; the listbox painted a bare `hsl(var(--popover))` with no knob at all until now. default = hsl(var(--popover)) at the call site",
    "name": "--select-content-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = none — the listbox blurs nothing",
    "name": "--select-content-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Vertical room around the `notFoundContent` row — the same breathing space the SearchSelect panel gives its own empty state, so the two empties read as one affordance.",
    "name": "--select-empty-space-block",
    "tier": "component",
    "value": "var(--search-select-placeholder-space-block)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--select-scroll-button-space-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Select rows sit slightly wider than a menu row: a listbox has no leading icon column to absorb the optical inset, so 2.5 reads level with a menu's 2 + icon.",
    "name": "--select-item-space-inline",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "TIME PICKER — scroll columns of hour/minute/second plus an inline affix pair. All of its geometry was literal on the component (#319): a service could not shorten the column, widen the panel for a 12-hour layout, or retune the row rhythm without forking.",
    "name": "--time-picker-column-height",
    "tier": "component",
    "value": "13rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-panel-width",
    "tier": "component",
    "value": "9rem"
  },
  {
    "description": "12-hour mode adds an AM/PM column, so the panel is wider.",
    "name": "--time-picker-panel-width-12h",
    "tier": "component",
    "value": "13rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-heading-space-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-heading-space-block",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-heading-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-column-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-option-space-block",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--time-picker-option-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-option-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-footer-space-inset",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-footer-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--time-picker-affix-space-gap",
    "tier": "component",
    "value": "var(--control-inline-affix-space-gap)"
  },
  {
    "description": "TREE SELECT — a Select whose panel holds a tree. Its rows, indent and toggle were literal on the component, and the depth indent was a magic expression in JSX (`depth * 1.25 + 0.5` rem) that no theme could reach at all (#319).",
    "name": "--tree-select-list-max-height",
    "tier": "component",
    "value": "min(300px, 50vh)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-row-space-block",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-row-space-inline-end",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--tree-select-row-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-row-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Indent = base + depth × step. A denser service dials the step down without touching JSX.",
    "name": "--tree-select-depth-space-base",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-depth-space-step",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-toggle-size",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-toggle-space-inline-end",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-label-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--tree-select-empty-space-block",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "CALENDAR — the react-day-picker grid. Day/weekday cells already size from --control-height (the system control tier), but the frame around them — root inset, month gaps, nav offset, grid rhythm — was literal on the component (#319), so a service could not tighten the calendar to its own density without forking the classNames map.",
    "name": "--calendar-space-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Gap BETWEEN side-by-side months (a range picker's two panels) — not the caption→grid step. Until gh#730 `.ui-calendar-month` carried it too, and a month has exactly two children, so it stacked with --calendar-grid-space-block-start into one 32px void under 「2026年9月」 that a screenshot read as a missing week row. One gap, one token: the month column no longer sets a gap and --calendar-grid-space-block-start is the whole caption→weekday step.",
    "name": "--calendar-month-space-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-caption-space-inline",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-caption-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-nav-space-block-start",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "THE SAME INSET AS THE GRID, by construction rather than by coincidence (gh#730 item 5). `.ui-calendar-nav` is `position: absolute; inset-inline: 0`, and an absolutely positioned box resolves its insets against the PADDING box — so the nav escapes the calendar's own --calendar-space-inset and its padding is the whole inset the chevrons get. At space-1 the `‹` button's outer edge measured 4px from the popover content edge while the weekday row and every day column started at 12px: an 8px split, reported as 「lề của button và calendar ko bằng nhau」. Pointing this at --calendar-space-inset makes the two ONE value — retuning the calendar's inset moves the chevrons with the grid, in LTR and RTL alike.",
    "name": "--calendar-nav-space-inline",
    "tier": "component",
    "value": "var(--calendar-space-inset)"
  },
  {
    "description": "Nav chevrons read as secondary until hovered — they frame the month, they are not the point.",
    "name": "--calendar-nav-rest-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "THE caption→weekday-row step, the only one now (gh#730): measured 32px before, 12px after. space-3 rather than space-2 because the unruled grid's own row rhythm is --calendar-week-space-block-start (space-2, 8px) — at 8px the caption would read as one more week row, at 12px it still reads as the boundary of a group.",
    "name": "--calendar-grid-space-block-start",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-week-space-block-start",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-weekday-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--calendar-weekday-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-day-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--calendar-day-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-chevron-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-footer-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-footer-space-block-start",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--calendar-footer-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Block inset of a header cell once the grid is RULED. Unruled, the header row has no edge for its text to sit against, so it needs none; ruled, the line box started right at the 1px rule — measured 1px from the top border and 2.19px from the bottom, an inset below the smallest named step. The smallest step, not a literal, so a service retuning the spacing grid moves it too.",
    "name": "--calendar-bordered-weekday-padding-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Text inset of a `width=\"full\"` day cell (gh#1258). The full cell reads from the start edge so a number can sit above badges, and with the unruled cell's `padding: 0` the numeral touched the cell edge — 0px left, 3px top, flagged by the library's own `text-edge-inset` rule (cell: >= 8px inline, >= 4px block). `initial` so the density-scaled defaults (var(--space-2) inline, var(--space-1) block) resolve at the call site, not frozen at the :root density. A shift board that wants a tighter or roomier cell sets these.",
    "name": "--calendar-full-day-padding-inline",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--calendar-full-day-padding-block",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Colour of the day-grid ruling (`Calendar bordered`, on by default). `initial` on purpose: the role default is read at the call site as `var(--calendar-grid-border-color, hsl(var(--border)))` so it follows a scoped theme. The --border tier: L* 93.80 / 1.149:1 on the popover in light, L* 20.76 / 1.270:1 in dark — a rule exactly as heavy as a Card edge or a DataTable row rule. Asked for three times: 25.3.0 drew the grid at all, 27.6.0 lightened the full --input (3.47 / 3.88) to --input/0.5 (1.74 / 1.95, L* 78.67), and gh#730 measured that still darker than the --border every card and table uses and asked for the --border tier itself. Same tier as the RangeTimeline grid. Set any colour to retint, e.g. `hsl(var(--input) / 0.5)` for the 27.6.0 weight or `hsl(var(--input))` for the heavy line.",
    "name": "--calendar-grid-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TRANSFER — the two-pane list mover. Pane height, header rhythm and row density were literal on the component (#319), so a service could not fit the panes to its own page grid or tighten the row for a dense admin table without forking.",
    "name": "--transfer-pane-min-height",
    "tier": "component",
    "value": "14rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--transfer-pane-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-panes-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-header-space-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-header-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-header-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-header-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-search-space-inset",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-list-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-row-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-row-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-row-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--transfer-row-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-row-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "The checkbox is top-aligned against a two-line row, so it needs a hair of optical offset to sit level with the first line's cap height rather than its box.",
    "name": "--transfer-row-check-space-block-start",
    "tier": "component",
    "value": "0.125rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-row-description-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-empty-space-block",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-actions-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--transfer-action-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "PERIOD GRID — the year-nav header over a 3-column grid that DatePicker shows for a coarse `picker` (month / quarter / year), single or `range`. The `--month-picker-*` names date from when this panel lived in a separate MonthPicker; one set of knobs has always driven every copy of it, which is why merging the four pickers changed no measurement here.",
    "name": "--month-picker-panel-space-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--month-picker-grid-space-block-start",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--month-picker-grid-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--month-picker-cell-space-inline",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--month-picker-nav-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Year-nav chevrons read as secondary until hovered — same treatment as the Calendar nav, so the two panels stay visually consistent when either is retuned.",
    "name": "--month-picker-nav-rest-alpha",
    "tier": "component",
    "value": "var(--calendar-nav-rest-alpha)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--month-picker-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--month-picker-separator-icon-size",
    "tier": "component",
    "value": "var(--icon-size-sm)"
  },
  {
    "description": "`initial`, NOT `var(--control-height-xs)`: an alias of a ladder step declared here is substituted against :root's 24px and inherits frozen, so a scope that moves the ladder (a `MobileShell` scopes it to 44 / 40 / 48 / 36px) never reached it — measured, `size=\"xs\"` stayed 24px inside the shell while every other size moved. `.ui-button--xs` reads it with the live ladder step as fallback, so the default re-resolves at the button and an override still wins.",
    "name": "--button-xs-height",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Minimum TARGET of `variant=\"bare\"` (gh#404) — the pseudo-element hit area, not a box height, so it never shows up as geometry. The measure is the same xs tier the note above settled on as this package's WCAG 2.2 SC 2.5.8 floor (1.5rem = 24px), and it moves with that tier and with density. `initial`, NOT `var(--control-height-xs)`, for the reason `--button-xs-height` above carries: an alias of a ladder step written HERE is substituted against :root's value and inherits frozen, so a scope that moves the ladder never reaches it. Measured in Chromium at 393px inside `MobileShell`, which scopes `--control-height` to 2.75rem: `--control-height-xs` correctly re-resolved to 36px while the bare button's `::after` stayed **24×24** — the one touch target in a touch-first shell that did not move. `.ui-button--bare::after` reads the live step as its fallback, so the default re-resolves at the button and a service override still wins.",
    "name": "--button-bare-target-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-xs-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-xs-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-xs-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-xs-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xs)"
  },
  {
    "description": "Icon-adjacent padding: a button whose only child is an icon needs less inline room than one carrying a label, or the glyph floats in a too-wide box. One knob per size tier.",
    "name": "--button-icon-space-inline-md",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-icon-space-inline-sm",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-icon-space-inline-lg",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-icon-space-inline-xs",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "The OTP blinking caret. The ratchet catches it because the selector says \"caret\", but it is a text CURSOR, not a chevron: a 1px bar as tall as the digit's line box. Its width belongs to the stroke scale; its height belongs to neither the icon nor the band scale, so it is declared rather than forced onto one. scale-exempt: text-caret height, tracks the OTP digit's line box, not an icon or a band",
    "name": "--otp-caret-block-size",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--otp-caret-inline-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--otp-separator-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-min-width",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-space-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Count pill · COLOUR (gh#320). The pill used to tint itself translucently over whatever the button's surface happened to be (`bg-primary-foreground/15`, `bg-foreground/8`), which means its contrast was a FUNCTION of that surface — and five of those combinations measured below the 4.5:1 that WCAG 2.2 SC 1.4.3 requires of small text: default (light) 3.88 · destructive (dark) 4.29 outline family (light, at rest) 4.32 · outline family (light, hover) 3.64 outline family (dark, hover) 3.68 The hover rows are the reason a static sweep never caught this: `--accent` only appears under the cursor, so no screenshot of a resting page contains the failing state. Same shape as gh#299 and gh#315 — a value that passes on the surface someone happened to check. The fix is the one gh#312 already validated on Toggle: OPAQUE role fills, which make the pill's contrast independent of the button's variant AND of hover. Each filled variant uses its own label pair SWAPPED, so the pill is exactly as legible as the label beside it and cannot be less legible under any theme that keeps that button readable at all: default --primary on --primary-foreground 5.04 light · 7.07 dark destructive --destructive on --destructive-foreground 6.10 light · 5.53 dark secondary --secondary on --secondary-foreground 14.25 light · 12.40 dark outline family --foreground on --muted 14.25 light · 12.40 dark The outline family's `--muted` fill is 1.09:1 against the button's own ground, so at rest the counter still reads as quiet text rather than a badge (#44) — it is legibility of the DIGITS that went up, not loudness of the pill. All eight are role-mirror knobs: `initial` at :root with the role default at the CALL SITE, so a scoped [data-tenant]/.dark override of the role still reaches them (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\").",
    "name": "--button-count-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-default-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-default-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-destructive-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-destructive-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-secondary-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--button-count-secondary-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "LABEL — the Label primitive's own box and type (#319). Every one of these was a Tailwind literal baked into label.tsx (`text-sm leading-none flex items-center gap-2`), so a service whose form grid wanted a smaller/denser label had to hand-write font-size on every call site (which is exactly why --form-label-font-size had to be invented as a per-instance escape). They live under the `control` prefix because Label is a control-family primitive and src/tokens/components/ has no `label` file of its own. Defaults reproduce today's rendering exactly: font-size ← `text-sm` → --text-sm → var(--font-size-sm) line-height ← `leading-none` → 1 (leading-none beats text-sm's companion line-height)",
    "name": "--control-label-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "A LABEL WRAPS, so its line box cannot be 1. This was a literal `1`, which is right for the one case it was chosen for — a single-line label beside a checkbox, where a cap-height box aligns cleanly — and wrong for every other. The moment the text takes two lines they collide: measured on the hosted sign-up consent label at 520px, font-size 14px with line-height 14px produced a 28px box of two touching lines. Long copy, a narrow column, and ja/vi wrapping all reach that case routinely. This package has already paid for this exact mistake once: `--auth-shell-divider-label-line- height` carries the note that a hardcoded `line-height: 1` rendered an 11px row and sat the lower half of the canonical Login card 8px high (gh#263). Same literal, same failure, one token over. `--line-height-normal` (1.5), not `--line-height-tight`: 1.25 clears the collision but two wrapped lines still read as one block, and a label that has wrapped IS prose at that point. 1.5 is also what this package already decided for the same job one layer up — `--auth-shell-field-label-line-height` — so the two agree instead of drifting. Alignment is unaffected: `.ui-label` is `display: flex; align-items: center`, so the control centres against the label box whatever its height.",
    "name": "--control-label-line-height",
    "tier": "component",
    "value": "var(--line-height-normal)"
  },
  {
    "description": "Label → addon/required-marker gap. A RAW rem, deliberately NOT var(--space-2): the `gap-2` it replaces reads Tailwind's own --spacing grid, which this repo does NOT density-scale, so a --space-* default would silently resize every label row under a compact/comfortable density. A service that WANTS it to follow density points the knob at var(--space-2) itself.",
    "name": "--control-label-space-gap",
    "tier": "component",
    "value": "0.5rem"
  },
  {
    "description": "Weight of a label whose `peer` control is disabled. Deliberately its OWN knob rather than the global --disabled-opacity (0.5): a label must stay READABLE next to a disabled control — it is still the field's accessible name — so it rests one step heavier than the control it names. Default = the historical `peer-disabled:opacity-70`.",
    "name": "--control-label-disabled-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "── CONTROL SURFACE — the antd `variant` × `status` matrix (antd 6.6.2) ──────────────────── The four surfaces and the two statuses are TOKENS, not utilities, and that is the whole point of this block. The select-family trigger used to state its surface as `border-input bg-background` — two Tailwind utilities, which live in `@layer utilities` and therefore beat anything a stylesheet in `@layer components` can say. A `[data-variant=\"filled\"]` rule would have been dead on arrival, exactly the way `w-full` killed `.ui-app-setting-picker-icon` (gh#366) and `--control-bounded-width` (gh#375). So the family now withholds those two utilities and reads the surface from here instead; the DEFAULT values reproduce the previous rendering byte for byte. `--control-surface-*` is the `outlined` default; the other three name themselves. THE THREE THAT MIRROR A ROLE ARE `initial` (docs/TOKENS.md, the `:root` freeze rule), and this block is where that rule was broken. `--control-surface-background: hsl(var(--background))` SUBSTITUTES at `:root`, so it froze on the light canvas and inherited that answer into every subtree. It looks fine in product because `.dark` normally lands on `<html>`, where `:root[data-theme=\"dark\"]` re-declares `--background` on the SAME element the binding is made on. It breaks the moment a theme is scoped BELOW `<html>` — the `[data-tenant]` route docs/CUSTOMER-THEMING.md recommends at level 3, and the `.dark` wrapper the docs Theme Editor uses to show both themes at once. Measured there before this change: a `Select` trigger in a `.dark` subtree painted `rgb(253,253,252)` under `rgb(247,247,243)` text, 1.05:1, while the `Input` beside it was correctly dark. The defaults below are unchanged; they simply resolve where the element paints instead of where the knob is declared. default = hsl(var(--input)) at the call site",
    "name": "--control-surface-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--background)) at the call site",
    "name": "--control-surface-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--control-surface-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`filled` — antd's grey field: no edge, a muted fill, no resting elevation.",
    "name": "--control-filled-border-color",
    "tier": "component",
    "value": "transparent"
  },
  {
    "description": "default = hsl(var(--muted)) at the call site",
    "name": "--control-filled-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-filled-shadow",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "`borderless` — chrome removed entirely, for a control embedded in a surface that already draws the box (a toolbar cell, an inline edit).",
    "name": "--control-borderless-border-color",
    "tier": "component",
    "value": "transparent"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-borderless-background",
    "tier": "component",
    "value": "transparent"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-borderless-shadow",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "STATUS. `error` reuses the destructive role already wired to the focus halo through the `[aria-invalid=\"true\"]` rule in focus-ring.css. `warning` deliberately does NOT use `--warning` (山吹 #f8b500). Measured against `--background` (#fdfdfb) that hue is 1.85:1 — a boundary that marks a state has to clear 3:1 under WCAG 2.2 SC 1.4.11, so shipping the brand yellow as the edge would have been a colour that only looks like a warning to people who can already see it. `--text-warning` (36 100% 28%, the darkened amber this palette keeps for exactly this reason) measures 5.4:1. A service that wants antd's yellow back retunes the knob and owns that trade.",
    "name": "--control-status-error-border-color",
    "tier": "component",
    "value": "hsl(var(--destructive))"
  },
  {
    "description": "default at the call site — freeze rule",
    "name": "--control-status-warning-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE SAME AMBER, AS A TRIPLET — and it has to be a triplet, not a colour. The focus mark is composed as `hsl(var(--focus-outline-color) / var(--focus-ring-opacity))`, so a token that already resolves to `hsl(...)` nests one `hsl()` inside another: the declaration is then invalid at computed-value time and the WHOLE `outline` shorthand falls back to its initial value. Measured in Chromium on a focused `status=\"warning\"` Textarea before this line existed: `outline-style: none`, `outline-width: 3px` (`medium`, the initial) — i.e. a warned field had no focus mark at all while the switch was on. It carried `--warning` (山吹 #f8b500) before, which is the hue the note above rejects for a state edge at 1.85:1; `--text-warning` is the darkened amber that measures 5.4:1 and is what the boundary already paints, so the edge and the mark cannot drift apart. default at the call site — freeze rule",
    "name": "--control-status-warning-outline-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "EmojiPicker (gh#1164): the panel width, an emoji cell (a touch-sized square), the glyph inside it, and how tall the grid gets before it scrolls.",
    "name": "--emoji-picker-cell-size",
    "tier": "component",
    "value": "var(--control-height-default)"
  },
  {
    "description": "Eight cells plus the popover's inset — derived, so 44px touch cells (coarse pointer) still fit eight to a row (8 × 44 + insets = 376px, inside a 390px phone).",
    "name": "--emoji-picker-panel-inline-size",
    "tier": "component",
    "value": "calc( 8 * var(--emoji-picker-cell-size) + 2 * var(--popover-space-inset, var(--space-3)) )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--emoji-picker-glyph-size",
    "tier": "component",
    "value": "var(--icon-size-lg)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--emoji-picker-grid-max-block-size",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "SortableList (gh#1173): the space between items, an item's inset, its corner, and the narrowest a grid tile may get before the grid drops a column.",
    "name": "--sortable-list-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--sortable-list-item-padding",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--sortable-list-item-radius",
    "tier": "component",
    "value": "var(--control-radius)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--sortable-list-grid-item-min-inline-size",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height-compact",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--control-height-default",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "SearchInput's text stops at the clear ✕'s 44px TARGET, not at its 24px box (gh#1148): edge inset + half the box (where the glyph's centre is) + half the target.",
    "name": "--search-input-end-padding",
    "tier": "component",
    "value": "calc( var(--search-input-edge-inset) + var(--touch-target-min) / 2 + var(--control-affix-touch-target-size) / 2 )"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--textarea-padding-block-start",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--textarea-padding-block-end",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--textarea-padding-inline-start",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
    "name": "--textarea-padding-inline-end",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Gap between the creation button, each bucket, and each run of rows.",
    "name": "--conversations-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Gap between rows inside one run.",
    "name": "--conversations-list-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "ROW BOX. The row is a CONTROL, so its height is the band tier, never a literal (rule #24 and `pnpm check:control-sizing`).",
    "name": "--conversations-item-height",
    "tier": "component",
    "value": "var(--band-height-md)"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-item-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-item-padding-inline",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--conversations-item-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-item-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "ROW STATE. Role-mirror knobs (docs/TOKENS.md): `initial` so the documented default resolves at the CALL SITE and a scoped `[data-tenant]` / `.dark` override still reaches it. Bound to a value here at `:root` each one would resolve once, against the root palette, and freeze. Default resting ink = hsl(var(--muted-foreground)) Default active ground = hsl(var(--accent)) Default active ink = hsl(var(--foreground))",
    "name": "--conversations-item-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-item-active-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--conversations-item-active-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-item-active-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-item-active-font-weight",
    "tier": "component",
    "value": "var(--font-weight-medium)"
  },
  {
    "description": "Leading glyph inside a row.",
    "name": "--conversations-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Gap between a row's label and its timestamp. The TIGHTEST stack step, because the two lines are one thing being read, not two stacked items — anything larger and the row reads as two rows in a rail that is already narrow.",
    "name": "--conversations-line-gap",
    "tier": "component",
    "value": "var(--space-stack-xs)"
  },
  {
    "description": "BUCKET HEADING (\"今日\" / \"Previous 7 days\").",
    "name": "--conversations-group-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-group-padding-inline",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "Conversations component tokens — the session rail of a chat surface (Ant Design X `Conversations`). Ant X answers \"how do I retune this rail\" with `styles={{ root, group, item, creation }}` — a free-form style hole that freezes its internal slot names into public API. This file is the answer instead (rules #44/#45): every length, tint and type step the rail paints is a named knob a service sets once in its own theme.css. THE DEFAULTS ARE THE SIDEBAR'S ROW RHYTHM, taken from the same foundation steps rather than by reading `--sidebar-*` — a chat rail and a nav rail are the same object seen twice, and gh#559 is partly a complaint that the two halves of one surface were drawn by two different hands. Reading the sidebar's own knobs would have made a service's sidebar retune silently move the chat rail too, which is a coupling nobody asked for; agreeing on the STEP is the part that matters. row band --band-height-md (32px) = --sidebar-nav-item-height row type --font-size-xs = --sidebar-nav-item-font-size icon column --icon-size-md (16px) = --sidebar-nav-icon-size",
    "name": "--conversations-group-chevron-size",
    "tier": "component",
    "value": "var(--icon-size-sm)"
  },
  {
    "description": "The `{ type: \"divider\" }` rule between two runs.",
    "name": "--conversations-separator-space-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Accordion chevron and Carousel arrow. Both were bare 1rem literals in data-display-layout.css — glyphs with no tier-2 route, invisible to the icon ratchet because neither selector contains the word \"icon\".",
    "name": "--accordion-chevron-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--carousel-arrow-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "THE ARROW'S BOX, WHICH IS NOT THE SAME KNOB AS ITS GLYPH (gh#931). `--carousel-arrow-icon-size` sizes the mark INSIDE the button; the button itself was a pair of bare `2rem` literals in data-display-layout.css, so the TARGET had no tier-2 route at all. 32px clears WCAG 2.2 SC 2.5.8 (24px), which is why this is a missing knob and not a defect — but a brand whose own foundations ask for a 44px target could not reach it from a theme, and had no option left except a page-local override of a library selector. Reported from a real re-theme whose spec reads \"arrows44px\". The default is the same 2rem the literals painted, so no existing carousel moves. A theme that wants the larger target writes one line: `--carousel-arrow-size: 2.75rem`.",
    "name": "--carousel-arrow-size",
    "tier": "component",
    "value": "2rem"
  },
  {
    "description": "WHERE THE ARROWS SIT, AND THE DEFAULT IS THE MIDDLE OF THE CONTENT — NOT OF THE COMPONENT. `.ui-carousel` is the positioning context and it is as tall as the slides PLUS the dots, so a plain `50%` centres the arrows on that sum. Measured on a 98px carousel: slides 58px (middle at -3415), dots 40px, arrows landing at -3395 — exactly half the dots row too low, which is what \"tại sao lại là middle của cả khung thế\" is pointing at. The reserve below subtracts it back. default = the content's middle, at the call site",
    "name": "--carousel-arrow-inset-block-start",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--carousel-dots-block-size",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Outline-form ring gaps — a hugging ring would touch these marks (styles/focus-ring.css).",
    "name": "--accordion-focus-ring-offset",
    "tier": "component",
    "value": "2px"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--carousel-dot-focus-ring-offset",
    "tier": "component",
    "value": "2px"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--progress-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "CodeBlock — a preformatted block; Prose delegates its `pre` treatment to the same knobs.",
    "name": "--code-block-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-font-size-xs",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-line-height",
    "tier": "component",
    "value": "var(--line-height-normal)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-space-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--code-block-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-max-height-sm",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-max-height-md",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-max-height-lg",
    "tier": "component",
    "value": "32rem"
  },
  {
    "description": "SYNTAX COLOURS (gh#784). Twelve knobs, named for Shiki's `createCssVariablesTheme` output so a highlighter's own vocabulary maps onto them one-for-one with no translation layer. WHY THE PACKAGE OWNS THESE AT ALL. `CodeBlock` is a surface and does not highlight — its own prop docs tell a consumer to bring a highlighter and pass its spans. But the consumer rules then close every route those spans could take colour from: `style` and `className` are both visual overrides, and an app stylesheet may declare no custom properties. So the documented path was unbuildable, which is a contradiction in this package's docs rather than a missing feature on the consumer's side. Every one is `initial` with its role default at the CALL SITE (docs/TOKENS.md — the `:root` freeze rule), so light and dark come from the roles rather than from a second palette here, and a service that wants its own scheme overrides the knob without touching the roles.",
    "name": "--code-block-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-comment-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-keyword-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-string-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-string-expression-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-function-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-constant-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-parameter-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-punctuation-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-link-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-inserted-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--code-block-token-deleted-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`changed` is the TWELFTH name and it was missed on the first pass: gh#784's own list had eleven, I copied the list instead of the source, and shiki's theme-css-variables.ts emits twelve. It is reachable only through a CONTEXT diff (`diff -c`, `markup.changed.diff` = `^(!).*$`), which is why a unified-diff sample never produced it — a silent wrong answer rather than a missing nicety: a changed line rendered as ordinary foreground, losing the distinction the `!` marker exists to make. Reported by the consumer that tokenised all 17 grammars (gh#793).",
    "name": "--code-block-token-changed-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Prose — typography of rendered content. Heading sizes come from --heading-h1..h4, table cell measures from --table-cell-padding-*; these are the rhythm knobs.",
    "name": "--prose-font-size",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-font-size-sm",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-line-height",
    "tier": "component",
    "value": "var(--line-height-body)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-space-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-heading-space-block-start",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-list-space-inline",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-list-item-space",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--prose-quote-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-quote-space-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-code-font-size",
    "tier": "component",
    "value": "calc(1em / var(--font-size-ratio))"
  },
  {
    "description": "scale-exempt: a `pre` in prose follows the surrounding text size, so it scales with user text (gh#1320)",
    "name": "--prose-code-block-font-size",
    "tier": "component",
    "value": "1em"
  },
  {
    "description": "Prose heading steps RELATIVE to the prose text (gh#1320): ProseMirror strips per-block attributes, so editor headings only grow with user text size by inheriting — a fixed step would not. Same default sizes as the global type scale at 14px body; `--heading-h*` still overrides.",
    "name": "--prose-heading-h1-font-size",
    "tier": "component",
    "value": "calc( 1em * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio) )"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-heading-h2-font-size",
    "tier": "component",
    "value": "calc(1em * var(--font-size-ratio) * var(--font-size-ratio))"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-heading-h3-font-size",
    "tier": "component",
    "value": "calc(1em * var(--font-size-ratio))"
  },
  {
    "description": "scale-exempt: h4–h6 sit at the prose text size, relative so they scale with it (gh#1320)",
    "name": "--prose-heading-h4-font-size",
    "tier": "component",
    "value": "1em"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--prose-code-space-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "An image in a table cell is capped at a LENGTH, not at 100% (gh#1150): a percentage of an auto-width column lets the column squash the image to nothing, while a length makes the image's narrowest size min(natural width, this) — the table then scrolls in its box.",
    "name": "--prose-cell-image-max-inline-size",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "Grammar v1 blocks (gh#1156). Columns sit this far apart and stack below 40rem; a toggle's summary is the control that opens it. Callouts reuse the <Callout> geometry (--callout-*).",
    "name": "--prose-columns-gap",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "@godxjp/block-editor (gh#1156): the start gutter the ⋮⋮ / + handle sits in, and the editing surface's minimum height (an empty body is still a target you can click into).",
    "name": "--block-editor-gutter-inline-size",
    "tier": "component",
    "value": "calc(2 * var(--control-height-xs) + var(--space-2))"
  },
  {
    "description": "Below 40rem the gutter collapses to this (ADR C05: first line ≤24px from the inner edge) and the handle rises above the caret's block at its inline end instead of sitting beside it.",
    "name": "--block-editor-compact-gutter-inline-size",
    "tier": "component",
    "value": "var(--block-editor-frame-padding)"
  },
  {
    "description": "Raw-Markdown block head: one step below the editor text, relative so it scales with it (gh#1320).",
    "name": "--block-editor-raw-block-head-font-size",
    "tier": "component",
    "value": "calc(1em / var(--font-size-ratio))"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--block-editor-min-height",
    "tier": "component",
    "value": "var(--band-height-3xl)"
  },
  {
    "description": "`appearance=\"framed\"`: the inset between the frame and the text (the handle gutter is extra).",
    "name": "--block-editor-frame-padding",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--block-editor-menu-inline-size",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--block-editor-menu-max-block-size",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--prose-code-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The link ink. `initial` — not `var(--primary)` — because the default IS a tenant-scoped role: a `:root` binding computes against the root's --primary and inherits that frozen value down, so a `[data-tenant]` re-tint never reaches it (docs/TOKENS.md, the freeze rule; gh#687). The default lives at the call site in styles/data-display-layout.css and re-resolves there. Until gh#717 `a` was the ONE styled descendant family in Prose with no knob at all — headings, lists, quote, code and image each had one — which left the most common element in a wiki body un-theme-able (#45). default = hsl(var(--primary))",
    "name": "--prose-link-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Underlined at rest, same vocabulary as `--text-link-decoration-line`, and deliberately a SEPARATE knob rather than a mirror of it: `none` is legal for a link in a nav row or a card title, which is what that token governs, but Prose is running text — at the shipped inks the link differs from body copy by hue alone (1.87:1 light, 1.54:1 dark), and WCAG 1.4.1 · G183 needs 3:1 for colour to carry a link on its own (gh#664). A theme that drops the rule in chrome must not drop it here by accident.",
    "name": "--prose-link-decoration-line",
    "tier": "component",
    "value": "underline"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--prose-image-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-note-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Avatar surface — `initial` so the --muted default re-resolves at the call site under a scoped theme (a :root binding to a role var freezes at :root; a scoped role override never reaches it). A service re-tints the placeholder fill once (e.g. --avatar-background: hsl(var(--accent))). Default = hsl(var(--muted)).",
    "name": "--avatar-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--avatar-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Optional role wash over the avatar (default transparent = invisible, rule #44). Painted as an overlay so a service sets --avatar-tint: hsl(var(--primary) / 0.08).",
    "name": "--avatar-tint",
    "tier": "component",
    "value": "transparent"
  },
  {
    "description": "Avatar SIZE LADDER — `<Avatar size=\"xs|sm|md|lg\">` (gh#716). The mark is a control-row citizen: it sits inside an `icon-sm` trigger, in a 24px dense table row, beside a Button on the same line. Before this ladder the box was welded to `--control-height`, so a 32px mark inside a 28px trigger OVERFLOWED it and the only legal move left to a consumer was to raise the whole row. Each step therefore reads the SAME `--control-height-*` tier every other control reads (never a px, never a calc offset), which is what makes `size=\"sm\"` measure exactly as tall as `<Button size=\"sm\">` on the same row. `md` is the default and is byte-identical to what shipped before, so nothing moves. `shape=\"square\"` rides the same ladder: each step re-declares --avatar-square-size ON THE ELEMENT (not at :root — a calc/var over two custom properties is substituted where it is DECLARED, the trap written up in tokens/components/segmented.css), so the entity mark and the person mark are the same height at every step.",
    "name": "--avatar-size",
    "tier": "component",
    "value": "var(--control-height)"
  },
  {
    "description": "The 24px step — the mark that fits an `icon-xs` trigger and a 24px dense row.",
    "name": "--avatar-size-xs",
    "tier": "component",
    "value": "var(--control-height-xs)"
  },
  {
    "description": "The 28px step — the mark that fits an `icon-sm` trigger and a `size=\"sm\"` control row.",
    "name": "--avatar-size-sm",
    "tier": "component",
    "value": "var(--control-height-sm)"
  },
  {
    "description": "The 36px step — the mark for a `size=\"lg\"` row (a list row's leading identity).",
    "name": "--avatar-size-lg",
    "tier": "component",
    "value": "var(--control-height-lg)"
  },
  {
    "description": "Initials TYPE per step — one step of the type scale per step of the box, so the two letters in a 24px mark are not the 14px set for a 32px one. The ratio holds (~0.44 of the box at every step), which is what keeps initials centred and legible rather than clipped.",
    "name": "--avatar-font-size",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Initials in the 24px mark — one step below sm on the type scale.",
    "name": "--avatar-font-size-xs",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Initials in the 28px mark — the same step a `size=\"sm\"` control's label reads.",
    "name": "--avatar-font-size-sm",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Initials in the 36px mark — one step above the body step.",
    "name": "--avatar-font-size-lg",
    "tier": "component",
    "value": "var( --font-size-lg, calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)) )"
  },
  {
    "description": "Glyph box per step — the `--icon-size-*` scale the `Icon` primitive was minted on (gh#712), multiplied by --scaling exactly as --control-icon-size is, so a glyph inside a sized mark tracks density like every other control glyph. Only a SIZED avatar sizes its glyph: there is deliberately no global `.ui-avatar svg` rule, because it would out-rank the per-call-site icon classes existing avatars already carry.",
    "name": "--avatar-glyph-size-xs",
    "tier": "component",
    "value": "calc(var(--icon-size-xs) * var(--scaling))"
  },
  {
    "description": "Glyph in the 28px mark — --icon-size-sm, the step --control-icon-size-sm also reads.",
    "name": "--avatar-glyph-size-sm",
    "tier": "component",
    "value": "calc(var(--icon-size-sm) * var(--scaling))"
  },
  {
    "description": "Glyph in the 36px mark — --icon-size-lg.",
    "name": "--avatar-glyph-size-lg",
    "tier": "component",
    "value": "calc(var(--icon-size-lg) * var(--scaling))"
  },
  {
    "description": "Entity-header mark — `<Avatar shape=\"square\">` (gh#249): the compact rounded SQUARE an organization/service header uses, as opposed to the round person avatar. Every value is a knob (rule #45) so a service matches the mark to its own grid without a className override. --avatar-square-background / --avatar-square-foreground are role-mirror knobs: `initial` so the --primary / --primary-foreground defaults re-resolve at the CALL SITE under a scoped [data-tenant]/.dark theme (a :root binding to a role var would freeze at the :root value). Defaults = --radius-lg corners · --control-height box (same as the circle avatar, so swapping shape never reflows a header) · hsl(var(--primary)) fill · hsl(var(--primary-foreground)) glyph. gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--avatar-square-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-square-size",
    "tier": "component",
    "value": "var(--control-height)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-square-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-square-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Capability medallion — `<Avatar appearance=\"tinted\">` (gh#12): the tinted plate a capability / feature glyph sits on, as opposed to the SOLID entity mark above. Pair it with shape=\"square\" for the canonical rounded square. --avatar-tinted-background / --avatar-tinted-foreground are role-mirror knobs (`initial`, docs/TOKENS.md) so the --primary defaults resolve at the CALL SITE and a scoped [data-tenant]/.dark override of --primary reaches them — the exact reason this is a token and not the `hsl(var(--primary) / 0.1)` literal consumers were writing in page CSS. Defaults = hsl(var(--primary) / 0.1) wash · hsl(var(--primary)) glyph · --control-icon-size glyph box.",
    "name": "--avatar-tinted-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-tinted-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-tinted-glyph-size",
    "tier": "component",
    "value": "var(--control-icon-size)"
  },
  {
    "description": "PRESENCE INDICATOR — `<Avatar presence=\"online|away|busy|offline\">` (gh#309): the realtime reachability dot pinned to the block-end/inline-end corner of the mark. Every constant below is a knob (rule #45) and the separator ring is chrome that reads a token (rule #44), because the hand-rolled workaround this replaces — `bg-green-500 ring-2 ring-background -end-0.5 -bottom-0.5` on a wrapper span — bakes four service-tunable constants and a raw palette colour into a consumer page. --avatar-presence-size is a PROPORTION of the mark, not a px step. One value therefore tracks EVERY avatar the system paints — the --control-height default box, a `size-12` call site, the --avatar-square-size entity mark, --org-switcher-avatar-size (1.75rem), --upload-avatar-size (6rem), the 36px ListRow density=\"compact\" leading mark — instead of freezing one diameter that is a boulder on a 24px mark and a speck on a 96px one. --avatar-presence-min-size is the legibility floor for the smallest marks; --avatar-presence-inset lets a service pull the dot further into a round mark than into a square one. --avatar-presence-ring-color and the four state colours are ROLE-MIRROR knobs: declared `initial` here so the --background / --success / --warning / --destructive / --muted-foreground defaults resolve at the CALL SITE and a scoped [data-tenant] / .dark override of the ROLE still reaches them (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Binding them to the role here would freeze the ring light-mode-white on a dark avatar. Presence is never colour-alone (WCAG 1.4.1): the colour rides with a SHAPE — filled · half filled · barred · hollow — and a localized sr-only string, so --avatar-presence-stroke-width and --avatar-presence-bar-* are part of the accessible encoding, not decoration. Defaults = 30% of the mark, floor 0.5rem · flush with the mark's corner · 2px separator ring in --background · 1.5px state stroke · a 56%-wide, 1.5px dnd bar.",
    "name": "--avatar-presence-size",
    "tier": "component",
    "value": "30%"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-min-size",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-inset",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--avatar-presence-ring-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-sm), resolved at the call site (gh#906)",
    "name": "--avatar-presence-stroke-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-bar-inline-size",
    "tier": "component",
    "value": "56%"
  },
  {
    "description": "default = var(--stroke-sm), resolved at the call site (gh#906)",
    "name": "--avatar-presence-bar-block-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-ring-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-online-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-away-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-busy-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--avatar-presence-offline-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Progress track + fill — `initial` so the role defaults re-resolve under a scoped theme. Track reads --secondary, the default (`primary`) fill reads the brand mark; a service re-tones once. Defaults = hsl(var(--secondary)) track · hsl(var(--mark-primary, var(--primary))) fill (gh#1308 — it was the success mark; status tones are opt-in and do not read this knob).",
    "name": "--progress-track-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--progress-track-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--progress-fill-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "BREAKDOWN geometry (`segments`) — its own block size and corner, not the meter's. A 0.5rem pill carries ONE fill legibly; three abutting fills at that height read as a coloured hairline and the ratios stop being comparable, which is the only thing a breakdown is for. The corner follows --radius rather than --radius-pill: pill ends would round the first and last slice only, so the partition would look like it starts and stops somewhere other than where it does.",
    "name": "--progress-breakdown-block-size",
    "tier": "component",
    "value": "1.375rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--progress-breakdown-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`size=\"sm\"` — the SAME two forms, thinner, for a bar that annotates a row rather than being the subject of the screen (an in-table capacity column). The meter step is half its default hairline; the breakdown step lands exactly on the meter's default 0.5rem, which is the thinnest a partition can be and still show three fills apart. Below that the ratios are gone, which is why there is no `xs`.",
    "name": "--progress-meter-block-size",
    "tier": "component",
    "value": "0.5rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--progress-meter-block-size-sm",
    "tier": "component",
    "value": "0.25rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--progress-breakdown-block-size-sm",
    "tier": "component",
    "value": "0.5rem"
  },
  {
    "description": "RING geometry (`shape=\"ring\"`) — the SAME meter, drawn as an arc. The diameter is a control tier rather than a new scale: a ring lives beside a title in an app bar, so it has to sit level with the controls around it the way the bar does. The stroke is the emphasis stroke (`--stroke-lg`), thick enough that the arc reads as a quantity at 2.75rem rather than as a hairline outline; `sm` keeps the same stroke on a smaller circle, because a thinner arc at a smaller diameter stops being readable as a proportion at all.",
    "name": "--progress-ring-size",
    "tier": "component",
    "value": "2.75rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--progress-ring-size-sm",
    "tier": "component",
    "value": "2rem"
  },
  {
    "description": "default = var(--stroke-lg), resolved at the call site (gh#906)",
    "name": "--progress-ring-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "A KNOB, with the derivation at the CALL SITE — and the first attempt got this wrong. It was `--font-size-xs`, one value for every diameter, so a 32px `sm` ring carried the same 12.47px label as the 44px default and \"18/42\" measured 32.6px — wider than the ring, painting over the arc. \"0/42\" fits, which is why the demo looked correct. The fix was `calc(var(--progress-ring-size) * 0.28)` HERE, and that does not work: a custom property substitutes its var() where it is DECLARED, so this reads the `:root` diameter and freezes. Measured after that change — both the 44px and the 32px ring rendered a 12.32px label, i.e. the sm ring was not scaled at all and only `max-inline-size` was saving it. The same freeze rule this repo documents for `--ring` and the primary family, walked into while fixing something else. So it is `initial`, and the formula lives at the element that PAINTS it, where `--progress-ring-size` is whatever `[data-size=\"sm\"]` last said. 0.28 reproduces the previous default (44 × 0.28 = 12.3px ≈ the 12.47 it replaces), so the md ring does not move.",
    "name": "--progress-ring-label-font-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Legend — the key for a colour-coded surface. Small chrome, so it carries its own rhythm rather than the stack scale: the swatch is a MARK the size of a character, not a control, and the gap that reads as \"these two belong together\" is tighter than any named step. scale-exempt: the legend's rhythm follows its TYPE (11-12px), not the layout space scale — --space-3 (12px) is close enough to the item gap that a swatch starts binding to the label on its left, and --space-4 (16px) breaks three keys into three objects.",
    "name": "--legend-gap",
    "tier": "component",
    "value": "0.875rem"
  },
  {
    "description": "scale-exempt: half the swatch, so a mark and its label read as one word; derived from --legend-swatch-size, not from the layout scale.",
    "name": "--legend-item-gap",
    "tier": "component",
    "value": "0.3125rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--legend-swatch-size",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "scale-exempt: --radius (6px) on a 10px square is 60% of the mark and reads as a DOT, a different symbol; this is the smallest corner that softens the square without becoming one.",
    "name": "--legend-swatch-radius",
    "tier": "component",
    "value": "0.125rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--legend-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "`initial` so the muted role re-resolves at the call site under a scoped theme. Default = hsl(var(--muted-foreground)).",
    "name": "--legend-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Swatch — a read-only sample of ONE colour a person chose (gh#527). The mark is Legend's square, one step larger: a legend swatch rides an 11-12px label, while this one stands beside a NAME at body size, and at 0.625rem beside 14px type it reads as a bullet rather than as a sample of a colour.",
    "name": "--swatch-size",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "scale-exempt: the same corner as --legend-swatch-radius — --radius (6px) on a 16px square reads as a DOT, a different symbol, and a sample and a key mark must be the same shape.",
    "name": "--swatch-radius",
    "tier": "component",
    "value": "0.125rem"
  },
  {
    "description": "The hairline that keeps a white value visible on a white card. It is the resting border weight, not a decision of this component. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--swatch-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`initial` so the border role re-resolves at the call site under a scoped theme. Default = hsl(var(--border)).",
    "name": "--swatch-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The caller's colour — the only knob here that is PER-INSTANCE. swatch.tsx writes it inline on the element, and an inline declaration outranks this one, so this is the value only when the prop is empty. It has to be declared all the same: an undeclared custom property has no fallback to fall back TO, which is the failure check-dist-tokens-resolve.mjs exists to catch. `--muted` is the right default because an unset sample should read as \"no colour recorded\" rather than as a colour nobody chose.",
    "name": "--swatch-color",
    "tier": "component",
    "value": "hsl(var(--muted))"
  },
  {
    "description": "Between statements: tight enough that the column reads as one list, loose enough that a two-line item does not merge with the next one.",
    "name": "--feature-list-space-gap",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "Glyph column ↔ label.",
    "name": "--feature-list-space-inline",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--feature-list-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--feature-list-description-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "The glyph takes the same step a Button's icon takes, so a feature list beside a control tier reads at the same weight. The mark BOX is `1lh` in the stylesheet — deliberately not a token, because the one correct value is \"however tall this text's line is\".",
    "name": "--feature-list-mark-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Thumbnail — a framed picture at a fixed height, intrinsic width. Three steps, chosen for the surfaces that asked for them rather than derived: an inline attachment strip, a gallery row, and a review screen. The `height` axis has no named scale in this library on purpose (see scripts/token-scale-bypass-rules.mjs — container heights barely repeat). 64px — an attachment chip beside its filename.",
    "name": "--thumbnail-block-size-sm",
    "tier": "component",
    "value": "4rem"
  },
  {
    "description": "96px — the default: a gallery row that still shows the shot.",
    "name": "--thumbnail-block-size",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "160px — a review screen, where the picture IS the content.",
    "name": "--thumbnail-block-size-lg",
    "tier": "component",
    "value": "10rem"
  },
  {
    "description": "Image `size` frame: width = the Thumbnail height × this ratio.",
    "name": "--thumbnail-width-ratio",
    "tier": "component",
    "value": "4 / 3"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--thumbnail-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--thumbnail-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TextDiff (gh#1096) — the grounds under a removed and an added run. The INK stays the text colour: the mark that carries the meaning is the strike-through / underline plus a spoken label, so the tint only has to separate the run from its neighbours. The grounds read the status surface role (gh#866) and fall back to the tone at these alphas.",
    "name": "--text-diff-removed-background-alpha",
    "tier": "component",
    "value": "0.12"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--text-diff-added-background-alpha",
    "tier": "component",
    "value": "0.16"
  },
  {
    "description": "The underline/strike weight — the resting hairline, so it survives forced-colors as ink.",
    "name": "--text-diff-mark-line-width",
    "tier": "component",
    "value": "var(--stroke-hairline)"
  },
  {
    "description": "Space between the before and after columns in split mode, and around a folded run.",
    "name": "--text-diff-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--text-diff-space-inset",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Timeline accents — `initial` so the dot/line role defaults re-resolve under a scoped theme. ONE HUE down the whole progress column (gh#731): done, current and the travelled line all default to hsl(var(--primary)), the way Steps paints `finish` and `process`; current is told apart by its ring, not by a second role. To restore the pre-27.9 green/violet pairing, set the done dot's FILL and its INK together — the two roles have opposite ink polarity, so the fill alone leaves a near-white glyph on 若竹 green at 2.19:1 (gh#643): --timeline-dot-done-background: hsl(var(--success)); --timeline-dot-done-foreground: hsl(var(--success-foreground));",
    "name": "--timeline-dot-done-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-dot-done-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-dot-current-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-line-completed-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The current dot's ring is the ONLY chromatic difference from a done dot, so it is `--steps-dot-process-ring-width` token-for-token — the same ring, meaning the same thing. default = var(--stroke-xl), resolved at the call site (gh#906)",
    "name": "--timeline-dot-current-ring-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Space between items and between rail and body. `initial` so `Timeline density=\"compact\"` can retune it on the root; default = var(--space-stack-md), compact = --timeline-item-gap-compact (default var(--space-stack-sm)), resolved at the call site.",
    "name": "--timeline-item-gap",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-item-gap-compact",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "QR codes stay scanner-safe in light and dark application themes. Consumers may override these component tokens only when the resulting pair retains strong contrast.",
    "name": "--qr-code-foreground",
    "tier": "component",
    "value": "0 0% 0%"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--qr-code-background",
    "tier": "component",
    "value": "0 0% 100%"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--qr-code-size-xs",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--qr-code-size-sm",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--qr-code-size-md",
    "tier": "component",
    "value": "10rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--qr-code-size-lg",
    "tier": "component",
    "value": "12.5rem"
  },
  {
    "description": "TIMELINE GRID — the time-axis half of the Timeline family (#354 item 7). Every measure the hand-rolled week grids in docs/showcase baked as a literal is a knob here: the height of one hour is what a service tunes when a 24-hour axis has to fit one screen, and the column floor is what decides when the grid scrolls instead of collapsing into slivers. --timeline-grid-hour-height is a RAW rem on the unenforced height axis: it is a rhythm the consumer picks per surface (a 6-hour shift board wants a taller hour than a 24-hour one), not a step of the spacing scale.",
    "name": "--timeline-grid-hour-height",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-axis-width",
    "tier": "component",
    "value": "3.25rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-column-min-width",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "Sàn hiển thị của một khối sự kiện, tính bằng PHÚT chứ không bằng pixel. Đây là NGUỒN DUY NHẤT: CSS suy chiều cao tối thiểu từ nó, và thuật toán xếp làn cũng dùng đúng con số này để biết hai khối có đè nhau trên màn hình hay không. Nếu để sàn bằng pixel thì thuật toán tính theo thời gian còn CSS lại kéo chiều cao lên, và hai ca không trùng giờ vẫn vẽ chồng.",
    "name": "--timeline-grid-event-min-height-minutes",
    "tier": "component",
    "value": "36"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-axis-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-head-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-event-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-event-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-event-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--timeline-grid-event-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--timeline-grid-event-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-sm), resolved at the call site (gh#906)",
    "name": "--timeline-grid-now-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Role-mirror knobs (docs/TOKENS.md): `initial` so the defaults re-resolve at the CALL SITE and a scoped [data-tenant]/.dark override of the role still reaches them. Defaults = hsl(var(--border)) hour rules · hsl(var(--primary)) block accent · hsl(var(--destructive)) now marker · hsl(var(--primary)) current-column wash.",
    "name": "--timeline-grid-line-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-event-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Chữ phụ trong khối sự kiện nằm trên nền ĐÃ TÔ theo màu của bên tiêu thụ, nên --muted-foreground vốn hiệu chỉnh cho nền trang không còn đủ tương phản: đo được 4,24 trên nền tô 12%, dưới ngưỡng 4,5 mà cỡ chữ này đòi. Mặc định dùng chính màu chữ chính, thứ bậc do độ đậm của tiêu đề đảm nhiệm; một service biết bảng màu của mình có thể dịu lại.",
    "name": "--timeline-grid-event-muted-color",
    "tier": "component",
    "value": "hsl(var(--foreground))"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-now-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--timeline-grid-current-tint",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "PERMISSION MATRIX — the sticky-first-column grid. Nothing here was themeable: the class `.ui-permission-matrix` existed as a bare hook with no CSS rule at all, so every constant lived on the component (#319). A JA/VI service whose role names run longer than the English ones could not widen the label column without forking.",
    "name": "--permission-matrix-label-width",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--permission-matrix-role-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--permission-matrix-name-space-gap",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--permission-matrix-cell-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size)"
  },
  {
    "description": "Floor for the scrolling body — below this the columns collapse into unreadable slivers, so the table scrolls instead. Mirrors --table-surface-min-inline-size on DataTable.",
    "name": "--permission-matrix-min-width",
    "tier": "component",
    "value": "48rem"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-label-width",
    "tier": "component",
    "value": "var(--app-shell-sidebar-width)"
  },
  {
    "description": "The most of the timeline's own width the label column may take (a cqi share), so bars and the resize divider stay on screen on a phone.",
    "name": "--range-timeline-label-max-inline-size",
    "tier": "component",
    "value": "60cqi"
  },
  {
    "description": "Label-column resize divider (gh#1189): the hit area straddles the column border and meets WCAG 2.5.8's 24px; the visible rule is the border itself, thickened on hover/focus.",
    "name": "--range-timeline-resizer-inline-size",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-resizer-active-width",
    "tier": "component",
    "value": "var(--stroke-md, 2px)"
  },
  {
    "description": "`busy` (gh#1189): how far the body dims while a new range loads, and the progress line.",
    "name": "--range-timeline-busy-body-alpha",
    "tier": "component",
    "value": "0.55"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-busy-line-block-size",
    "tier": "component",
    "value": "var(--stroke-md, 2px)"
  },
  {
    "description": "Floor for ONE axis unit, so a day column never collapses; the live knob the canvas reads. `density` re-points it per instance at the three steps below — set THIS one in a theme to move every step's baseline, set a step to retune one density.",
    "name": "--range-timeline-unit-width",
    "tier": "component",
    "value": "var(--range-timeline-unit-width-default)"
  },
  {
    "description": "Day-column steps on the `density` axis (gh#730). `default` is the shipped 56px, unchanged, so no existing Gantt moves; `compact` is 1.5 control-sm (42px), which leaves a 24px content box — measured, the widest two-digit day label across the ja/en/vi/ar/fa/hi/th/bn numbering systems is 19.86px (Thai ๒๗), so the tick still fits; `comfortable` is 2.5 (70px) for a wide screen. Multiples of --control-height-sm, never literals, so the axis follows the global density/scaling factor too.",
    "name": "--range-timeline-unit-width-compact",
    "tier": "component",
    "value": "calc(var(--control-height-sm) * 1.5)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-unit-width-default",
    "tier": "component",
    "value": "calc(var(--control-height-sm) * 2)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-unit-width-comfortable",
    "tier": "component",
    "value": "calc(var(--control-height-sm) * 2.5)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-row-height",
    "tier": "component",
    "value": "var(--control-height-lg)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-bar-height",
    "tier": "component",
    "value": "var(--control-height-sm)"
  },
  {
    "description": "Per-row bar state (gh#1189 follow-up): a done row recedes, an overdue row gets a danger edge that keeps its status colour. `--range-timeline-bar-color` / `-ink` are set per row from data.",
    "name": "--range-timeline-bar-muted-alpha",
    "tier": "component",
    "value": "0.45"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-bar-overdue-width",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "Planned vs actual (予定 / 実績): the ghost outline of the plan, the overrun segment past it, and the early marker where the actual ends before it.",
    "name": "--range-timeline-plan-border-width",
    "tier": "component",
    "value": "var(--stroke-hairline)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-early-marker-inline-size",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "Schedules: a milestone diamond, a finish-only tick, a one-sided plan tick, an open end's fade, a cancelled hatch, dependency connectors and the row emphasis accent.",
    "name": "--range-timeline-milestone-size",
    "tier": "component",
    "value": "var(--range-timeline-bar-height)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-finish-inline-size",
    "tier": "component",
    "value": "calc(var(--stroke-md) * 2)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-plan-tick-inline-size",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-open-end-fade-inline-size",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-cancelled-hatch-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-cancelled-hatch-line-width",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "default = hsl(var(--foreground) / 0.45), resolved at the call site",
    "name": "--range-timeline-cancelled-hatch-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted-foreground)), resolved at the call site",
    "name": "--range-timeline-link-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-link-width",
    "tier": "component",
    "value": "var(--stroke-hairline)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-link-violation-size",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Data-display component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--range-timeline-emphasis-width",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "The OUTER FRAME of the timeline and its label-column divider — the --border tier, the same rule weight a Card edge and a DataTable row use. The grid INSIDE it now reads the same tier (see --range-timeline-grid-color), which is the point of gh#730: the day grid may never be heavier than the frame around it, and at one tier it cannot become so under any theme.",
    "name": "--range-timeline-border-color",
    "tier": "component",
    "value": "var(--border)"
  },
  {
    "description": "Body grid (`RangeTimeline bordered`, on by default): row rules, the header rule and a vertical rule per column down the whole body. Colour `initial` on purpose — the role default is read at the call site as `var(--range-timeline-grid-color, hsl(var(--border)))` so it follows a scoped theme. The --border tier: L* 93.80 / contrast 1.149 on the card in light, L* 20.76 / 1.270 in dark — identical to the outer frame and to a DataTable row rule, which is the whole point. Asked for three times: 25.3.0 drew the grid at all, 27.6.0 lightened the full --input (3.47) to --input/0.5 (1.74, L* 78.67), and gh#730 reported that still darker than the --border (L* 93.80) every card and table uses, so the eye followed the grid instead of the bars. Set any colour to retint, e.g. `hsl(var(--input) / 0.5)` for the 27.6.0 weight.",
    "name": "--range-timeline-grid-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Weight of every grid rule, header column rules included, so header and body stay aligned. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--range-timeline-grid-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Fill for `columns[].muted` (a non-working day), full body height. `initial`; call-site default `hsl(var(--muted))`, the header's own surface, so a muted column reads as part of the axis.",
    "name": "--range-timeline-muted-column-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Label-column indent per `rows[].depth` level (gh#724). The label column keeps its width.",
    "name": "--range-timeline-indent-width",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "RecordPicker — chiều cao TỐI ĐA của danh sách trong Dialog (gh#932). Một hằng số ở đây là thứ không theme nào với tới: một service dùng hàng dày hơn, hoặc một Dialog cao hơn, cần đổi được con số này mà không phải đè selector của thư viện.",
    "name": "--record-picker-list-max-block-size",
    "tier": "component",
    "value": "22rem"
  },
  {
    "description": "Danh sách gợi ý dưới ô inline (gh#944) — ngắn hơn danh sách trong Dialog, vì nó nằm TRONG dòng chảy của form chứ không phải trong một lớp phủ riêng.",
    "name": "--record-picker-suggest-max-block-size",
    "tier": "component",
    "value": "14rem"
  },
  {
    "description": "Data-entry component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--password-strength-score-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Data-entry component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--password-strength-checklist-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Stack rhythm between the mode radios, the subset box and the error line (was `gap-3`).",
    "name": "--branch-scope-picker-gap",
    "tier": "component",
    "value": "0.75rem"
  },
  {
    "description": "Read-only summary: the wrapped run of branch Badges (was `gap-1.5`).",
    "name": "--branch-scope-picker-badges-gap",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "The `mode=\"selected\"` subset box — its inner stack rhythm and the inset that clears its indent rule (was `gap-2` / `ps-4`).",
    "name": "--branch-scope-picker-subset-gap",
    "tier": "component",
    "value": "0.5rem"
  },
  {
    "description": "Data-entry component tokens — small-by-design text knobs (rule #45/#46).",
    "name": "--branch-scope-picker-subset-padding-inline",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "The indent rule itself is CHROME (#44), so it is a knob: a service that wants the flat treatment sets it to 0 rather than forking the component. Default = today's `border-s-2`. default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--branch-scope-picker-subset-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Bounded height of the scrollable branch list (was `max-h-64`). Flat by design: the box is a keyboard-reachable scroll region whose job is to cap the control's measure, so it must not grow with density and push the surrounding form off a 390px frame.",
    "name": "--branch-scope-picker-list-max-height",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "TranslatableInput / TranslatableTextarea (gh#1336). The rhythm between the locale tab strip and the field it switches — a service aligning its forms to a tighter grid sets it once. 4px",
    "name": "--translatable-field-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The error mark beside a locale's name on its tab. The ICON scale one step below the tab's own 14px text, so it reads as a mark on the label rather than a second word. 12px",
    "name": "--translatable-field-error-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xs)"
  },
  {
    "description": "Width of the label column when <Descriptions layout=\"horizontal\">. Labels align to this shared column so the values line up (the horizontal-detail look, mirroring <Form layout>). A rem value gives a fixed aligned column; set `max-content` to size each label to its text. (rule #44/#45 — a service theme tunes it here instead of forking CSS.)",
    "name": "--descriptions-label-width",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "Row-to-row gap (gh#294). Default = the historical hardcoded `gap-y-3`, so nothing changes visually by default. A consumer composing Descriptions beside a Form/FormField (a read-only block above an editable field on the same card) retunes this to `var(--space-4)` to match Form's own field-to-field rhythm instead of the two blocks reading as visually unrelated.",
    "name": "--descriptions-row-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Column-to-column gap of the <dl> grid (#319). Was a hardcoded `gap-x-6`, the one axis of the grid rhythm a service could NOT reach while --descriptions-row-gap was already a knob — so a 2/3-column detail block could be retuned vertically but never horizontally. A RAW rem, deliberately NOT var(--space-6): `gap-x-6` reads Tailwind's own --spacing grid, which this repo does NOT density-scale, so a --space-* default would silently rescale the column gap under a compact/comfortable density. Point it at var(--space-6) to opt in.",
    "name": "--descriptions-column-gap",
    "tier": "component",
    "value": "1.5rem"
  },
  {
    "description": "Label → value gap inside ONE item when layout=\"horizontal\" (was `gap-x-3`). Pairs with --descriptions-label-width: a service that narrows the label column usually wants to close this gap in the same step. Raw rem for the same --spacing reason as above.",
    "name": "--descriptions-label-gap",
    "tier": "component",
    "value": "0.75rem"
  },
  {
    "description": "VALUE TYPOGRAPHY (gh#294 + #319). `FormField staticText` renders its read-only value with the SAME typography as a <dd> so a static Form row and a Descriptions value are indistinguishable when mixed on one card. That contract used to be two copies of the literal `text-sm` plus a comment asking future editors to keep them in sync; both call sites now read these tokens, so the mirror is mechanical and a service retunes BOTH from one place.",
    "name": "--descriptions-value-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Companion to --descriptions-value-font-size (the gh#260 bug). The `text-sm` utility this replaces ALSO set a line-height, via Tailwind's default `--text-sm--line-height` (= calc(1.25 / 0.875)); the theme remaps --text-sm but never that companion. Without this the value would silently inherit ambient leading instead of its own 20px line box.",
    "name": "--descriptions-value-line-height",
    "tier": "component",
    "value": "calc(1.25 / 0.875)"
  },
  {
    "description": "LABEL TYPOGRAPHY. The label was a hard-coded `text-xs` utility while the value beside it read a token, so the pair sat ONE TYPE STEP APART (`--font-size-xs` ≈12.5px against `--font-size-sm`, which IS `--font-size-base` at 14px) and every row rendered its value BIGGER than its own label. What separates a label from its value is COLOUR, not size. The LABEL is raised to the value's step rather than the value shrunk to the label's: the value is the DATA, and shrinking it would move every consumer's field panel and `FormField staticText` with it. Defaulting to the value token locks the pair together by construction while leaving each side reachable. Measured by check:descriptions-label-value-step.",
    "name": "--descriptions-label-font-size",
    "tier": "component",
    "value": "var(--descriptions-value-font-size)"
  },
  {
    "description": "Companion, for the same reason the value has one (gh#260): the `text-xs` utility this replaces ALSO carried a line-height, so dropping it without a replacement would leave the label inheriting ambient leading instead of its own line box.",
    "name": "--descriptions-label-line-height",
    "tier": "component",
    "value": "var(--descriptions-value-line-height)"
  },
  {
    "description": "ROW CHROME (gh#414) — the ruled property panel. Both knobs are QUIET by default (rule #44), so an existing Descriptions is byte-identical: no rule, no band height. Same shape as --page-header-divider / --page-toolbar-divider / --page-footer-divider on PageContainer: a `border` shorthand a service opts into with ONE declaration (`--descriptions-row-border: var(--stroke-hairline) solid hsl(var(--border))`), read at the call site. Bound at :root rather than `initial` because the default is a plain CSS keyword, not another role token — there is nothing for a scoped [data-tenant]/.dark override to re-resolve, and the keyword is worth reading here (the same reasoning --page-toolbar-background records). The rule is drawn only on an UNBORDERED grid: `bordered` already draws a rule between every cell, and a second block-end border would double every line it owns. --descriptions-row-min-height gives the ruled variant its band height — a ruled row whose value is one short line otherwise reads as a hairline sandwich. `auto` = today. A continuously ruled panel sets --descriptions-row-gap to `0` in the same declaration block: the row gap is the space BETWEEN rules, so leaving it at the default 12px draws a ladder of detached hairlines rather than a ruled list.",
    "name": "--descriptions-row-border",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Descriptions component tokens.",
    "name": "--descriptions-row-min-height",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "BORDERED grid (antd `bordered`). The rule between cells and the frame around them. Width is a stroke step so a service that thickens every hairline gets this one with it; colour is deliberately left to the global `border-color` role so a scoped [data-tenant] override still reaches it. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--descriptions-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--descriptions-border-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Inset inside one bordered cell. Only read while `bordered` is set — an unbordered Descriptions has no cell box to pad, and gains nothing.",
    "name": "--descriptions-cell-padding-y",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Descriptions component tokens.",
    "name": "--descriptions-cell-padding-x",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Shaded label cell, the half of antd's bordered table that makes the pairs readable at a glance. `initial` so the --muted default re-resolves under a scoped theme. Default = hsl(var(--muted)).",
    "name": "--descriptions-label-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Resting inset from the viewport edge at the panel's placement corner.",
    "name": "--draggable-panel-inset",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Applied offset from that corner, in CSS pixels. Written by the component.",
    "name": "--draggable-panel-offset-x",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-offset-y",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "Keyboard nudge, one arrow press. Shift takes the larger step (WCAG 2.1.1 path).",
    "name": "--draggable-panel-step-offset",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-step-offset-lg",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "Width ladder. A floating assistant is a column of text, so these are reading measures.",
    "name": "--draggable-panel-width-sm",
    "tier": "component",
    "value": "18rem"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-width",
    "tier": "component",
    "value": "22rem"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-width-lg",
    "tier": "component",
    "value": "28rem"
  },
  {
    "description": "xl: nearest wide-content tier on the shell measure ladder (gh#607), not a one-off 46rem.",
    "name": "--draggable-panel-width-xl",
    "tier": "component",
    "value": "var(--centered-shell-width-md)"
  },
  {
    "description": "Definite height when set; `auto` keeps the pre-607 shrink-to-content behaviour.",
    "name": "--draggable-panel-block-size",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-max-block-size",
    "tier": "component",
    "value": "70vh"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--draggable-panel-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-shadow",
    "tier": "component",
    "value": "var(--shadow-lg)"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--draggable-panel-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-bar-padding",
    "tier": "component",
    "value": "var(--space-2) var(--space-3)"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-bar-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-body-padding",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "DRAGGABLE PANEL — a floating, movable surface (gh#560). Geometry only. The two offset knobs are written by the component as UNITLESS numbers and multiplied by 1px in `styles/layout.css`, which is how a JS-computed position reaches CSS without a literal in the TSX (`check:no-inline-magic-numbers`).",
    "name": "--draggable-panel-handle-size",
    "tier": "component",
    "value": "var(--control-affix-icon-size)"
  },
  {
    "description": "── Shell — the 480px transactional-email geometry ─────────────────────────────────────── canonical transactional card width",
    "name": "--email-shell-width",
    "tier": "component",
    "value": "480px"
  },
  {
    "description": "card inset — mirrors --space-8 (2rem)",
    "name": "--email-shell-padding",
    "tier": "component",
    "value": "32px"
  },
  {
    "description": "gutter between the client viewport and the card (--space-6)",
    "name": "--email-shell-page-padding",
    "tier": "component",
    "value": "24px"
  },
  {
    "description": "card edge — mirrors the 1px --border hairline",
    "name": "--email-shell-border-width",
    "tier": "component",
    "value": "1px"
  },
  {
    "description": "mirrors --card-radius (--radius-xl = 6px × φ ≈ 10px)",
    "name": "--email-card-radius",
    "tier": "component",
    "value": "10px"
  },
  {
    "description": "canonical invitation reference measures 480×407",
    "name": "--email-card-reference-height",
    "tier": "component",
    "value": "407px"
  },
  {
    "description": "block rhythm — mirrors --space-stack-lg (1.5rem)",
    "name": "--email-stack-gap",
    "tier": "component",
    "value": "24px"
  },
  {
    "description": "tight rhythm — mirrors --space-3 (0.75rem)",
    "name": "--email-stack-gap-sm",
    "tier": "component",
    "value": "12px"
  },
  {
    "description": "The mark ARTWORK is the same 32×32 capsule + glyph `<Logo mark=\"godx\" />` paints; only the RENDERED BOX differs. The canonical SCR-302 header sets it at 22px next to a 13px/700 \"GoDX\" wordmark, which is smaller than the web --logo-godx-size (2rem) — an email header carries the identity, not the navigation, so the lockup sits quieter (gh#250). canonical SCR-302 header lockup mark box",
    "name": "--email-mark-width",
    "tier": "component",
    "value": "22px"
  },
  {
    "description": "EMAIL component tokens — the geometry/typography half of the transactional-email contract (`@godxjp/ui/email`). HTML email cannot read CSS custom properties: Outlook/Gmail strip <style> blocks and require LITERAL inline values, so a Blade/Twig/MJML template can never `var()` these. They still live in the component tier because this is the ONE source a maintainer edits — the `@godxjp/ui/email` export is GENERATED from this file plus the colour roles in foundation.css (scripts/gen-email-tokens.mjs), so an email template and a web screen can never drift apart. Every value is a LITERAL px/number (never rem, never calc, never var): email clients resolve neither the cascade nor relative units reliably, and the export must serialise to a plain hex/px string. Where a value mirrors a web token the comment names it, so a retune stays traceable. Colours are deliberately NOT redeclared here — they derive from the semantic roles (--card/--background/--foreground/--muted/--border/--primary/--ring/--brand) and are converted HSL→hex at module load, so a re-themed role re-tints the email with zero copy-paste. The identity mark reads --brand, NOT --success: --success is the wakatake status green, and the two are deliberately distinct roles (gh#250).",
    "name": "--email-mark-height",
    "tier": "component",
    "value": "22px"
  },
  {
    "description": "mark ↔ wordmark — mirrors --logo-wordmark-gap (--space-2)",
    "name": "--email-mark-gap",
    "tier": "component",
    "value": "8px"
  },
  {
    "description": "canonical wordmark size (≈ --font-size-xs 12.5px)",
    "name": "--email-wordmark-font-size",
    "tier": "component",
    "value": "13px"
  },
  {
    "description": "mirrors --logo-wordmark-font-weight",
    "name": "--email-wordmark-font-weight",
    "tier": "component",
    "value": "700"
  },
  {
    "description": "The DXS canonical face is Noto Sans JP (see src/styles/fonts.css; product override, direct instruction). Email clients honour NO @font-face, so the stack ships the face NAME first and degrades through the platform JP faces to a generic — a client with Noto Sans JP installed (or a webmail that already loaded it, which is common — it is a widely preinstalled/CDN-cached Google face, more likely to actually render than the niche M PLUS 2 ever was) renders the canonical face, everything else lands on Hiragino (macOS/iOS) → Yu Gothic (Windows) → M PLUS 2 → Meiryo → the system UI face → Arial → sans-serif. Family names are SINGLE-quoted on export (the generator normalises) because an inline `style=\"…\"` attribute is double-quoted; only ASCII aliases are listed, since a non-ASCII family name does not survive every transfer encoding.",
    "name": "--email-font-family-sans",
    "tier": "component",
    "value": "\"Noto Sans JP\", \"Hiragino Sans\", \"Hiragino Kaku Gothic ProN\", \"Yu Gothic Medium\", YuGothic, \"M PLUS 2\", Meiryo, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, system-ui, Arial, sans-serif"
  },
  {
    "description": "Tabular/reference strings — invoice ids, masked card numbers, ISO dates, amounts — are set in the mono face in the canonical card. Mirrors --font-family-mono.",
    "name": "--email-font-family-mono",
    "tier": "component",
    "value": "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"
  },
  {
    "description": "mirrors --font-size-base (0.875rem)",
    "name": "--email-body-font-size",
    "tier": "component",
    "value": "14px"
  },
  {
    "description": "1.9, NOT the web --line-height-body (1.7) — the canonical email card runs its JP body copy looser than a screen, because a mail client gives the reader no density control.",
    "name": "--email-body-line-height",
    "tier": "component",
    "value": "1.9"
  },
  {
    "description": "mirrors --font-weight-normal",
    "name": "--email-body-font-weight",
    "tier": "component",
    "value": "400"
  },
  {
    "description": "canonical card title (≈ --heading-h2, base × φ^¼² ≈ 17.6px)",
    "name": "--email-heading-font-size",
    "tier": "component",
    "value": "17px"
  },
  {
    "description": "the title shares the card's body leading, not a tight ramp",
    "name": "--email-heading-line-height",
    "tier": "component",
    "value": "1.7"
  },
  {
    "description": "mirrors --font-weight-medium — an email title is calm, not bold",
    "name": "--email-heading-font-weight",
    "tier": "component",
    "value": "500"
  },
  {
    "description": "TOUCH TARGET, deliberately DECOUPLED from --control-height-lg (36px). Do not \"restore\" the mirror: email is a mobile-first, touch-only medium. There is no hover state, no precise pointer, and mail clients do not reliably offer zoom or a focus affordance — so the web's AA floor (SC 2.5.8, 24x24, which 36px clears) is the wrong bar here. 44px is the AAA target size (SC 2.5.5, 44x44) and the Apple HIG 44pt / Material 48dp convention. A service that must keep the old box sets --email-cta-height + --email-cta-line-height in its own theme.",
    "name": "--email-cta-height",
    "tier": "component",
    "value": "44px"
  },
  {
    "description": "equal to the height: bulletproof vertical centring in Outlook",
    "name": "--email-cta-line-height",
    "tier": "component",
    "value": "44px"
  },
  {
    "description": "mirrors --space-4",
    "name": "--email-cta-padding-x",
    "tier": "component",
    "value": "16px"
  },
  {
    "description": "mirrors the --radius base (0.375rem)",
    "name": "--email-cta-radius",
    "tier": "component",
    "value": "6px"
  },
  {
    "description": "mirrors --font-size-base",
    "name": "--email-cta-font-size",
    "tier": "component",
    "value": "14px"
  },
  {
    "description": "mirrors --font-weight-medium",
    "name": "--email-cta-font-weight",
    "tier": "component",
    "value": "500"
  },
  {
    "description": "── Legal footer ───────────────────────────────────────────────────────────────────────── mirrors --font-size-2xs (base ÷ φ^¼² ≈ 11.1px)",
    "name": "--email-footer-font-size",
    "tier": "component",
    "value": "11px"
  },
  {
    "description": "the legal band runs looser than the web --line-height-normal",
    "name": "--email-footer-line-height",
    "tier": "component",
    "value": "1.8"
  },
  {
    "description": "horizontal separation between footer links (--space-3)",
    "name": "--email-footer-link-gap",
    "tier": "component",
    "value": "12px"
  },
  {
    "description": "space above the legal band",
    "name": "--email-footer-padding-top",
    "tier": "component",
    "value": "20px"
  },
  {
    "description": "the hairline above the legal band",
    "name": "--email-footer-border-width",
    "tier": "component",
    "value": "1px"
  },
  {
    "description": "── Focus affordance (webmail preview panes that DO honour :focus) ─────────────────────── mirrors --focus-ring-width",
    "name": "--email-focus-border-width",
    "tier": "component",
    "value": "2px"
  },
  {
    "description": "── Mobile reflow — applied under the narrow media query and by inline fallbacks ───────── the reflow breakpoint (card width + both gutters)",
    "name": "--email-mobile-max-width",
    "tier": "component",
    "value": "520px"
  },
  {
    "description": "the card goes fluid below the breakpoint",
    "name": "--email-mobile-width",
    "tier": "component",
    "value": "100%"
  },
  {
    "description": "reduced card inset — mirrors --space-5",
    "name": "--email-mobile-padding",
    "tier": "component",
    "value": "20px"
  },
  {
    "description": "reduced viewport gutter — mirrors --space-3",
    "name": "--email-mobile-page-padding",
    "tier": "component",
    "value": "12px"
  },
  {
    "description": "One step below the 17px desktop title. The canonical 390px reference raster is unusable (it is 435px wide and already clips the card — dxs-platform/platform#496), so this is the library's documented contract rather than a measured canonical value.",
    "name": "--email-mobile-heading-font-size",
    "tier": "component",
    "value": "16px"
  },
  {
    "description": "the CTA goes full-bleed so the tap target spans the card",
    "name": "--email-mobile-cta-width",
    "tier": "component",
    "value": "100%"
  },
  {
    "description": "Measure of the surface block. Caps the status code + body + metadata column so a long ja/vi headline wraps at a readable width in BOTH shells, including the application shell where PageContainer is much wider than the copy wants to be.",
    "name": "--error-surface-max-width",
    "tier": "component",
    "value": "32rem"
  },
  {
    "description": "Rhythm between the status code, the EmptyState body, the metadata list and the progress meter.",
    "name": "--error-surface-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Block padding of the surface inside the shell it is placed in. Desktop (1440/1024) default; the 390 step steps it down so a phone loses no vertical space (see styles/shell-layout.css).",
    "name": "--error-surface-padding-block",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "ErrorSurface — the 403 / 404 / 500 / 503 exception surface (gh#221, gh#251). Package-owned geometry: a service retunes the surface here (or in its own theme.css) instead of forking `.ui-error-surface` or adding a `className` to the component. Chrome defaults are QUIET (cardinal rule #44): the metadata block ships with no divider — a service opts IN.",
    "name": "--error-surface-padding-block-compact",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Brand slot (a Logo) above the status code, system mode only.",
    "name": "--error-surface-brand-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Metadata description list: row rhythm and the label↔value gap inside one row.",
    "name": "--error-surface-meta-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "ErrorSurface — the 403 / 404 / 500 / 503 exception surface (gh#221, gh#251). Package-owned geometry: a service retunes the surface here (or in its own theme.css) instead of forking `.ui-error-surface` or adding a `className` to the component. Chrome defaults are QUIET (cardinal rule #44): the metadata block ships with no divider — a service opts IN.",
    "name": "--error-surface-meta-row-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Chrome, default quiet (#44). A service opts in with `--error-surface-meta-border: var(--stroke-hairline) solid hsl(var(--border));`.",
    "name": "--error-surface-meta-border",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "ErrorSurface — the 403 / 404 / 500 / 503 exception surface (gh#221, gh#251). Package-owned geometry: a service retunes the surface here (or in its own theme.css) instead of forking `.ui-error-surface` or adding a `className` to the component. Chrome defaults are QUIET (cardinal rule #44): the metadata block ships with no divider — a service opts IN.",
    "name": "--error-surface-meta-padding-block",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "Width of the maintenance progress meter — narrower than the measure, so it reads as metadata rather than as the primary content of the page.",
    "name": "--error-surface-progress-max-width",
    "tier": "component",
    "value": "18rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-width-default",
    "tier": "component",
    "value": "22.5rem"
  },
  {
    "description": "Overlay scrims — `initial` so the shared semantic --overlay-background re-resolves at the CALL SITE under a scoped [data-tenant]/.dark theme (a :root binding to it freezes at :root and a scoped override never reaches the overlay). Each surface takes a SHARE of that one scrim rather than a private literal, so a service retints every backdrop with one --overlay-background while the calibrated per-surface depth survives: a slide-in Sheet washes the page more lightly than a modal Dialog. Defaults resolve to rgb(0 0 0 / 0.16) (sheet) and rgb(0 0 0 / 0.24) (dialog).",
    "name": "--sheet-overlay-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "A SHARE OF `--overlay-background`, NOT THE RESULTING ALPHA (gh#886). The base is a finished colour that already carries `/0.4`, so `40%` composites to **0.16**, and a theme author who sets `62%` gets 0.248. That is the library-wide convention for a `--*-alpha` knob in the `color-mix(in srgb, <base> <alpha>, transparent)` share form — 100% means \"the base as authored\", 0% means gone — and it is deliberate: the calibrated depth lives ONCE in `--overlay-background` so a service retints every scrim with one line. Want an absolute opacity instead? Set `--sheet-overlay-background` directly; it wins outright. Pinned by src/styles/__tests__/overlay-alpha-share-886.test.ts. 40% of rgb(0 0 0 / 0.4) = rgb(0 0 0 / 0.16)",
    "name": "--sheet-overlay-alpha",
    "tier": "component",
    "value": "40%"
  },
  {
    "description": "GLASS — ON THE SCRIM, for the same two reasons the dialog's note below spells out. A drawer covers content that must stay unreadable-but-present, so this is the surface whose blur does the most work, and the panel's own fill belongs at the OPAQUE end of the range (docs/GLASSMORPHISM-STANDARD.md §4). `initial` = no blur and no backdrop root. default = none — the scrim blurs nothing",
    "name": "--sheet-overlay-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE PANEL FILL (gh#880 item 4). This was `bg-background` baked into the Sheet's own className, which is a Tailwind utility — `@layer utilities` outranks every component-layer rule, so the drawer's surface was not merely un-knobbed, it was unreachable by any rule this package could write. The utility is gone and `.ui-sheet-panel` paints from this knob instead; unset, the default resolves to the same `hsl(var(--background))` at the call site. default = hsl(var(--background)) at the call site",
    "name": "--sheet-surface-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`initial` + the ramp default at the call site — see --tooltip-shadow (gh#880 item 7). default = var(--shadow-lg), resolved at the call site",
    "name": "--sheet-shadow",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-header-space-gap",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-title-block-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-title-row-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-extra-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-footer-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-title-font-size",
    "tier": "component",
    "value": "var( --font-size-lg, calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)) )"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-description-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "The scroll region keeps a sliver of padding so a focused control's ring is never clipped at the scroll edges — retune together with --focus-ring-width.",
    "name": "--sheet-body-space-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Close button: offset from the panel corner, and the inline room the header reserves so a title never runs under it.",
    "name": "--sheet-close-offset",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-close-rest-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-header-close-space-inline-end",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-width-default",
    "tier": "component",
    "value": "32rem"
  },
  {
    "description": "Per-instance width, set by DialogContent `width` (gh#1174) — `initial`, so the default above resolves at the call site; the viewport cap (minus --dialog-viewport-inset) always wins.",
    "name": "--dialog-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ENTER / EXIT TIMING (gh#1178). `initial`, default `var(--duration-fast)` (150ms) at the call site, so a scoped motion retune reaches them. A full-screen overlay that takes half a second to arrive reads as lag; `prefers-reduced-motion: reduce` stops the animation outright (styles/dialog-layout.css, unlayered block).",
    "name": "--dialog-motion-duration",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-enter-duration",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--sheet-exit-duration",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-viewport-inset",
    "tier": "component",
    "value": "1.5rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-overlay-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "A SHARE OF `--overlay-background`, NOT THE RESULTING ALPHA (gh#886) — the miss that was reported, because this knob carried no note of its own and `60%` reads as \"0.6\". The base is a finished colour with `/0.4` baked in, so the product is **0.24**, and `62%` gives 0.248 rather than the darker scrim that was asked for. See `--sheet-overlay-alpha` above for the convention and for the escape hatch: `--dialog-overlay-background` is an absolute colour and wins outright. Pinned by src/styles/__tests__/overlay-alpha-share-886.test.ts. 60% of rgb(0 0 0 / 0.4) = rgb(0 0 0 / 0.24)",
    "name": "--dialog-overlay-alpha",
    "tier": "component",
    "value": "60%"
  },
  {
    "description": "GLASS — THE BLUR IS ON THE SCRIM, NEVER ON THE DIALOG BOX (gh#880). Two reasons, and both are already written down in this repo. `backdrop-filter` filters what is painted BEHIND an element, and the scrim is the layer that covers the page, so the box would only ever blur the (flat) scrim. And an element with a `backdrop-filter` becomes the containing block for its fixed descendants, which would pin the dialog to itself — the trap `src/styles/shell-layout.css` documents where the app-launcher launchpad puts its blur on the overlay for exactly this reason. docs/GLASSMORPHISM-STANDARD.md §4 states the same rule. `initial` = no blur AND no backdrop root, so nothing about the shipped modal moves. The dialog's own translucency is `--dialog-surface-background` below, not a second blur. default = none — the scrim blurs nothing",
    "name": "--dialog-overlay-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE PANEL FILL — a role-mirror knob, `initial`, default `hsl(var(--background))` at the call site (gh#880 item 4). `dialog-layout.css` hard-coded that colour, which made the modal one of the surfaces a theme could not make translucent at all: `--background` is a raw HSL triplet that is already composed with an alpha elsewhere, so a theme cannot add a second `/` to it. A whole colour here can. The panel's INK is stated on the same rule (`color: hsl(var( --foreground))`, gh#877) rather than inherited — a translucent fill over inherited text is how an invisible label ships, and that is the half of this surface that was already fixed. default = hsl(var(--background)) at the call site",
    "name": "--dialog-surface-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Dialog inset defaults to the shared global chrome tokens (override --space-chrome-* once for the whole system, or --dialog-space-x/-y for dialogs only).",
    "name": "--dialog-space-x",
    "tier": "component",
    "value": "var(--space-chrome-x)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-space-y",
    "tier": "component",
    "value": "var(--space-chrome-y)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-space-inset",
    "tier": "component",
    "value": "var(--dialog-space-y) var(--dialog-space-x)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-space-gap",
    "tier": "component",
    "value": "var(--space-stack-md)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-close-space-offset",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Dialog chrome rhythm (#319) — the exact mirror of the --sheet-* set above, because Dialog's header markup is byte-identical to Sheet's. --dialog-space-x/-y already governed the panel inset, but every gap INSIDE the chrome (header stack, title/subtitle pair, the extra-slot row) was a literal on the component, so a service could retune the outer padding and still be stuck with the inner rhythm. Defaults are the values the literals resolved to.",
    "name": "--dialog-header-space-gap",
    "tier": "component",
    "value": "var(--space-stack-xs)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-title-row-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-title-block-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-extra-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Confirm/alert leading icon (antd `Modal.confirm` parity). antd paints a 22px status glyph to the inline-start of the title and leaves the surface untinted; the icon IS the danger signal. 22px is not a step on the icon scale, so this rides --icon-size-xl (24px) — the nearest named step, and no new value enters the scale. The gap mirrors antd's 12px margin on the glyph.",
    "name": "--dialog-confirm-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xl)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--dialog-confirm-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Inline room the header reserves so a long title or the extra slot never runs under the absolutely-positioned close button; retune together with --dialog-close-space-offset. Mirrors --sheet-header-close-space-inline-end.",
    "name": "--dialog-header-close-space-inline-end",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Close button rest opacity — quiet at rest, full on hover (rule #44). Was a hard 0.7 baked into dialog-layout.css with no way for a theme to make the ✕ louder. Mirrors --sheet-close-rest-alpha so the two overlay siblings retune together.",
    "name": "--dialog-close-rest-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "THE CLOSE BUTTON'S TARGET, WHICH IS NOT ITS PAINT (gh#806 · WCAG 2.2 SC 2.5.8 AA). The ✕ glyph is --control-affix-icon-size (16px) and the button had nothing around it, so the button measured 16x16 and all four +-11px probes MISSED — measured on the real Dialog frame, not a fixture. A consumer's a11y gate had to exclude the selector, and rule #47 forbids them re-sizing it themselves. The paint must NOT grow: the ✕ sits at a fixed offset from the panel corner and enlarging the glyph moves the optical weight of every overlay in the system. So the hit area is carried by a centred pseudo-element, the same answer `.ui-data-table-sort-button::after` already ships — verified there the same way (paint 53.1x17.8, all four probes HIT). Raisable because SC 2.5.8 is a floor, not a target: a touch-first service sets this higher.",
    "name": "--dialog-close-size",
    "tier": "component",
    "value": "var(--touch-target-min)"
  },
  {
    "description": "Type-to-confirm challenge: the step-up failure line under the input. Its size + ink were `text-sm text-destructive` on the component, i.e. unreachable from a theme.",
    "name": "--dialog-step-up-error-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Alert corner radius (gh#268 — rule #45): a full-width Alert often sits in the same page column as a Card — so the DEFAULT IS the Card radius (gh#282); a service re-tunes by overriding this once. Default keeps the historical --radius-md. `initial`, not `var(--card-radius)` — a :root binding freezes (gh#888); default resolves at the call site. Default = var(--card-radius).",
    "name": "--alert-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--alert-space-inset",
    "tier": "component",
    "value": "var(--space-section-active)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--alert-space-gap",
    "tier": "component",
    "value": "var(--space-inline-md)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--alert-inner-space-gap",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--alert-dismiss-space-offset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Leading tone glyph (the ⚠/✓/ⓘ at the start of the strip). It was a bare `1.25rem` in alert-layout.css with no token at all, so the ONLY ways to resize it were `!important` or a forked stylesheet — the two things the icon axis's tier 2 exists to abolish (gh#326). Same step, so nothing moves; a service now scopes `--alert-icon-size` to one Alert instead. Deliberately NOT --scaling-multiplied: the literal it replaces did not track density.",
    "name": "--alert-icon-size",
    "tier": "component",
    "value": "var(--icon-size-lg)"
  },
  {
    "description": "Dismiss ✕ — rest opacity (quiet at rest, full on hover, rule #44) and glyph size. The rest alpha was a hard 0.7 in alert-layout.css whose `:hover` companion lived on the COMPONENT as `hover:opacity-100`, so the two halves of one affordance sat in two files and neither was themeable. Mirrors --sheet-close-rest-alpha. The icon size carries a raw rem, not var(--space-N): it replaces a flat Tailwind `size-4` step and must not start tracking the density axis.",
    "name": "--alert-dismiss-rest-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--alert-dismiss-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Soft (subtle) semantic tint ratios — themeable so a service can hit its exact spec (a brand's success-bg/-border are often more present than the faint 5%/30% default).",
    "name": "--alert-bg-alpha",
    "tier": "component",
    "value": "0.05"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--alert-border-alpha",
    "tier": "component",
    "value": "0.3"
  },
  {
    "description": "BANNER — the page-level Alert treatment (gh#255). Every constant a service would want to match to its page grid is a knob (rule #45). --banner-radius and --banner-border-width are NOT declared here (gh#327). They used to be, and both copies were dead: components/banner.css declares the same two names at the same `:root`, base.css imports banner AFTER feedback, so banner won every time. Radius agreed at `0`, but border-width did not — this file said `0` and banner.css says `1px`, and `1px` is what alert-layout.css actually paints as the strip's block-end hairline. So anyone who read THIS file for the default was told the strip has no rule when it has one, and the MCP token catalog carried both entries with the two conflicting values. banner.css owns the strip geometry; these two live there and only there. The inline inset tracks the live page gutter, so a banner mounted above a PageContainer lines its text up with the page title instead of sitting at a second, unrelated margin. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--banner-border-block-end-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--banner-space-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Inline inset tracks the page gutter so a banner's text lines up with the page title. `--space-page-active-x` steps down to the compact gutter on `.ui-page-container` only, and custom properties inherit — so a banner rendered INSIDE the container picks the compact value up for free, while the normal case (a banner mounted ABOVE the container, or in AppShell) would keep the desktop gutter and sit 8px out at 390px. The compact step below is what actually keeps the two aligned; retune it rather than hard-coding a mobile inset at the call site.",
    "name": "--banner-space-inline",
    "tier": "component",
    "value": "var(--space-page-active-x)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--banner-space-inline-compact",
    "tier": "component",
    "value": "var(--space-page-compact-x)"
  },
  {
    "description": "Dismiss offset is measured from the banner's own (shorter) block inset, so the ✕ stays optically centred on a one-line strip instead of floating at the inline-alert offset.",
    "name": "--banner-dismiss-space-offset",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Brand glow layer for the raised dialog/sheet panel — invisible no-op at rest (rule #44). Paired AFTER --shadow-lg in the surface box-shadow so a service can wash the overlay with the global glow, e.g. --dialog-content-glow: var(--shadow-glow), with no markup change.",
    "name": "--dialog-content-glow",
    "tier": "component",
    "value": "0 0 0 0 transparent"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-space-y",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-space-x",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Measure of the description paragraph (rule #45 — a service-tunable constant gets a knob). 28rem reads ~65 Latin characters per line; a JA/VI service that needs a shorter or longer measure for its own copy retunes this once instead of forking `.ui-empty-state-description`.",
    "name": "--empty-state-description-max-width",
    "tier": "component",
    "value": "28rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-section-space-y",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-section-space-x",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-compact-space-y",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-compact-space-x",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "EmptyState icon medallion colour — `initial` so the role defaults re-resolve at the call site under a scoped theme (rule #44). A service recolours the glyph (--empty-state-icon-foreground) or washes the medallion fill (--empty-state-icon-tint) without forking. Defaults = hsl(var(--muted-foreground)) glyph · hsl(var(--muted)) fill.",
    "name": "--empty-state-icon-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-icon-tint",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Medallion box + the glyph inside it. Both were literal (`width: 3rem` in the stylesheet, a `size-6` utility on the icon), so a service could not scale the empty-state mark to its own page rhythm — and the two must move TOGETHER or the glyph stops sitting centred in its circle, which is exactly the kind of pair rule #45 exists to keep tunable as one.",
    "name": "--empty-state-icon-size",
    "tier": "component",
    "value": "var(--icon-size-4xl)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--empty-state-icon-glyph-size",
    "tier": "component",
    "value": "var(--icon-size-xl)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-row-gap",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-cell-gap",
    "tier": "component",
    "value": "var(--space-inline-lg)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-card-inset",
    "tier": "component",
    "value": "var(--space-section-active)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--skeleton-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Skeleton placeholder fill — `initial` so the --muted default re-resolves at the call site under a scoped theme (a :root binding to a role var freezes at :root). A service tints the shimmer to its surface (rule #44) without forking the keyframes. Default = hsl(var(--muted)).",
    "name": "--skeleton-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Skeleton bar heights + widths (#319). These carry RAW rem, not var(--space-N): the literals they replace were plain Tailwind steps, which are not multiplied by --scaling. Routing them through the spacing scale would silently make the loading state track the density axis while the loaded content it stands in for does not. Names say what each bar STANDS IN FOR, so a service retuning its type scale knows which one to move.",
    "name": "--skeleton-block-height",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-caption-height",
    "tier": "component",
    "value": "0.75rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-title-height",
    "tier": "component",
    "value": "1.75rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-label-width",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-detail-value-max-width",
    "tier": "component",
    "value": "28rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-stat-value-width",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-stat-caption-width",
    "tier": "component",
    "value": "5rem"
  },
  {
    "description": "SKELETON · antd 6 parity (ant-design/components/skeleton/style/index.ts). antd derives every element box from `controlHeight` and its ±steps; the same boxes here read the `--control-height` tier, so a skeleton input is exactly as tall as the Input it stands in for and follows density with it. The RATIO is antd's own multiplier (input = 5× the box); it is unitless on purpose — a service widens the stand-in without leaving the height tier. gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--skeleton-element-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-input-width-ratio",
    "tier": "component",
    "value": "5"
  },
  {
    "description": "ARTICLE rhythm. antd: avatar gutter = `padding` (16), title offset beside an avatar = `marginSM` (12), title→paragraph = `controlHeightSM` (24), line→line = `controlHeightXS` (16). antd's fourth value — 28px (`marginLG + marginXXS`) for title→paragraph WITH an avatar — is not a step of this repo's spacing scale (it goes 24 → 32), and docs/DESIGN-AUTHORITY.md says take a step or leave it rather than invent a number, so both cases take the 24px step.",
    "name": "--skeleton-article-avatar-gap",
    "tier": "component",
    "value": "var(--space-inline-lg)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-article-avatar-title-offset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-article-title-gap",
    "tier": "component",
    "value": "var(--space-stack-lg)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--skeleton-article-line-gap",
    "tier": "component",
    "value": "var(--space-stack-md)"
  },
  {
    "description": "antd's `li:last-child:not(:first-child):not(:nth-child(2))` short last line.",
    "name": "--skeleton-paragraph-last-width",
    "tier": "component",
    "value": "61%"
  },
  {
    "description": "The `active` sheen. One knob, not a from/to pair, so a service retunes the whole sweep once (#45); `initial` keeps the default resolving at the call site under a scoped theme (#44). Default = linear-gradient(90deg, hsl(var(--muted)) 25%, hsl(var(--border)) 37%, hsl(var(--muted)) 63%) — antd's three stops, on this library's neutral surfaces.",
    "name": "--skeleton-sweep-gradient",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "QUERY LIFECYCLE FOOTERS — the two rows `<InfiniteQueryState>` appends under a paginated feed: the \"load more\" button row and the \"loading more…\" caption. Both gaps were Tailwind literals on the component (`pt-4` / `pt-2`), so a service running a denser (or airier) feed could not align them to its own vertical rhythm without forking the component (rule #45). They live in the feedback tier because these ARE query feedback surfaces and there is no query stylesheet. Defaults = var(--space-stack-md) (16px) and var(--space-stack-sm) (8px) — the exact values the Tailwind steps resolved to, so adopting this changes nothing until a theme opts in.",
    "name": "--query-load-more-space-block-start",
    "tier": "component",
    "value": "var(--space-stack-md)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--query-loading-more-space-block-start",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "The sign-in fallback a query surface paints for an expired session when no AuthExpiryProvider handles it (gh#1022). An expired session is an expected, recoverable condition, so it is capped at a reading measure instead of spanning the page body its DataState wraps. `none` restores the full-width alert.",
    "name": "--query-auth-alert-max-inline-size",
    "tier": "component",
    "value": "36rem"
  },
  {
    "description": "TOOLTIP — the transient label surface. Every constant here was a Tailwind literal baked into the component (`max-w-xs px-2 py-1 rounded-md text-xs shadow-md`), so a service could not retune tooltip density or measure without forking the component (rule #45). Defaults reproduce the previous look exactly, so adopting this changes nothing until a theme opts in.",
    "name": "--tooltip-max-width",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--tooltip-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--tooltip-space-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--tooltip-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--tooltip-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Raised-surface depth — role-mirror knob, so a flat service theme sets `none` once. `initial` rather than `var(--shadow-md)`: a `:root` binding to the ramp substitutes at `<html>` and a scope that restates the ramp can never reach it (docs/TOKEN-RESOLUTION.md §3, gh#880 item 7). The default resolves on `.ui-tooltip-content`. default = var(--shadow-md), resolved at the call site",
    "name": "--tooltip-shadow",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "GLASS (gh#880 item 1) — `initial`, so unset there is no blur and no backdrop root. A tooltip is the smallest surface in the system and sits over arbitrary content, so it follows §4's dropdown rule: if it is made translucent at all, it needs the most opaque fill of the family. Saturate is shared (`--surface-backdrop-saturate`). default = none — a tooltip blurs nothing",
    "name": "--tooltip-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Surface colours — `initial` so the popover roles re-resolve at the CALL SITE under a scoped [data-tenant]/.dark theme (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Defaults = hsl(var(--popover)) fill · hsl(var(--popover-foreground)) text.",
    "name": "--tooltip-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--tooltip-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--tooltip-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--tooltip-border-color-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "POPOVER — the interactive overlay panel. Same story as Tooltip: `w-72 rounded-md p-4 shadow-md` were literals, so a service could not align the panel to its own grid or width scale.",
    "name": "--popover-width",
    "tier": "component",
    "value": "18rem"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--popover-space-inset",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--popover-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`initial` + the ramp default at the call site — same freeze, same reason as --tooltip-shadow. default = var(--shadow-md), resolved at the call site",
    "name": "--popover-shadow",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "GLASS (gh#880 item 1) — `initial`, no blur and no backdrop root by default. This one carries a second warning: a Popover is a CONTAINER, so turning its blur on makes it the containing block for any `position: fixed` descendant it holds. default = none — a popover blurs nothing",
    "name": "--popover-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--popover-header-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--popover-header-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Role-mirror knobs — `initial`, defaults resolve at the call site (see Tooltip above).",
    "name": "--popover-surface-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--popover-surface-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Feedback primitive tokens: dialog, alert, empty state.",
    "name": "--popover-surface-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--popover-surface-border-color-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Width knob, for a panel that owns its own box — a time column pair, a calendar. The three colour knobs above already existed and padding already read `--popover-space-inset`; width was the one surface property left absolute, so a modifier could only reach it by re-declaring the property — which loses to import order (styles/__tests__/popover-surface-knob-cascade).",
    "name": "--popover-surface-inline-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TOAST (Sonner) — the status glyph in the toast's leading slot. WHY A KNOB AND NOT A UTILITY: sonner renders the toast body itself and takes the five status glyphs through ONE `icons={{ success, info, warning, error, loading }}` config prop. That prop is all-or-nothing — a consumer who wants a different glyph size must re-declare all five icons, re-importing lucide and re-deriving the aria wiring. Routing the size through a token makes it a one-line theme override instead (rule #45). Raw rem, not var(--space-N): it replaces a flat Tailwind `size-4` step, and the 16px box sonner gives `[data-icon]` is itself fixed — scaling the glyph with density alone would overflow it. NAMESPACE NOTE: sonner publishes its own `--toast-*` custom properties (--toast-icon-margin-*, --toast-svg-margin-*, --toast-button-margin-*, --toast-close-button-*). Neither name below collides with those; keep it that way when adding to this group.",
    "name": "--toast-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "THE TOAST SURFACE (gh#880 item 1). Sonner paints the toast body itself from its own `--normal-bg`, which `sonner.tsx` sets to `hsl(var(--popover))`. That made the fill reachable only by re-declaring sonner's private variable, so this knob is the package's own name for it: the component now passes `var(--toast-background, hsl(var(--popover)))` through, and the default resolves in the browser, on the toaster, under whatever scope it is in. The blur goes on `[data-sonner-toast]` from `alert-layout.css`. `initial` = no blur and no backdrop root; a toast holds an action Button and a close ✕, neither of which is `fixed`, but the rule is the rule. default = hsl(var(--popover)) at the call site",
    "name": "--toast-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = none — a toast blurs nothing",
    "name": "--toast-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Viewport gutter of the mobile toast stack. Sonner passes `mobileOffset` straight into inline CSS, so a var() string resolves normally. Flat 16px on purpose: this is a fixed inset from the device edge (thumb reach / safe area), not a density-scaled gap inside a surface.",
    "name": "--toast-mobile-offset",
    "tier": "component",
    "value": "16px"
  },
  {
    "description": "Extra clearance the toast stack keeps above the viewport's bottom edge, ADDED to the gutter on both desktop (sonner's 24px) and mobile (`--toast-mobile-offset`) — gh#1271. `0px` = the stack sits where it always did. A service whose layout pins its own bottom chrome (a fixed bar the library does not render) sets it once in theme.css. Never unitless `0`: it is a `calc()` term, and a bare number there invalidates the whole offset.",
    "name": "--toast-offset-bottom",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "RUNTIME-PUBLISHED, not a theme knob (gh#1271). A mounted, visible sticky action bar — `PageContainer stickyFooter`, or `MobileShell actions`/`tabBar` in a viewport shell — writes its block size here inline on <html> (`src/lib/toast-clearance.ts`), and the Toaster adds it to its bottom offset so the stack never covers the primary action. Removed again when the bar unmounts or is hidden, which falls back to this `0px`. Set `--toast-offset-bottom` instead of this one: the runtime value overwrites any theme value.",
    "name": "--toast-sticky-bar-height",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Rule #24 companion for the overlay ✕ (gh#1138): the 24px floor is the WCAG 2.5.8 AA minimum for a mouse; under a finger the target lifts to the 44px tap floor the control ladder already uses. Only the hit area grows (the `::after` above the glyph) — the 16px paint stays put.",
    "name": "--dialog-close-size",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Lightweight row surfaces and hover actions; theme overrides remain scoped component knobs.",
    "name": "--flex-surface-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Lightweight row surfaces and hover actions; theme overrides remain scoped component knobs.",
    "name": "--flex-surface-warning-alpha",
    "tier": "component",
    "value": "0.04"
  },
  {
    "description": "Lightweight row surfaces and hover actions; theme overrides remain scoped component knobs.",
    "name": "--flex-surface-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Lightweight row surfaces and hover actions; theme overrides remain scoped component knobs.",
    "name": "--flex-actions-offset-block",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Lightweight row surfaces and hover actions; theme overrides remain scoped component knobs.",
    "name": "--flex-actions-offset-inline",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE TWO CORNER INSETS gh#558 ASKED FOR BY NAME. Ant Design's are `marginXXL` (48px) from the bottom and `marginLG` (24px) from the inline end. Spelled here in this library's own stack/inline steps, which land on the same two numbers: --space-stack-xl = --space-10 = 40px, --space-6 = 24px. The block inset is the one a service actually has to move — a sticky action bar, a cookie strip, a mobile tab bar all live in that corner — and moving it is now retuning ONE custom property, not writing a media query at the call site (which is `no-arbitrary-spacing` and has no legal spelling).",
    "name": "--float-button-offset-block-end",
    "tier": "component",
    "value": "var(--space-stack-xl)"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-offset-inline-end",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "The control box. antd's float button is `controlHeightLG` square (40px); this reads the same tier the rest of the library's large controls read, so a density switch moves it with them.",
    "name": "--float-button-size",
    "tier": "component",
    "value": "var(--control-height-lg)"
  },
  {
    "description": "A square float button carrying a line of text keeps the WIDTH and grows on the block axis, which is antd's `height: auto`; this is the floor it grows from.",
    "name": "--float-button-min-block-size",
    "tier": "component",
    "value": "var(--control-height-lg)"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-padding-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-padding-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The glyph. antd derives it as `fontSizeIcon * 1.5` = 18px; `--icon-size-md` is this library's step at that weight, and it is the step `Button` already gives an icon-only control.",
    "name": "--float-button-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "The line under the glyph, in the square shape. The smallest step, because it is a caption on a control, not body text.",
    "name": "--float-button-content-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-content-line-height",
    "tier": "component",
    "value": "var(--line-height-tight)"
  },
  {
    "description": "Elevation. The mark sits ABOVE the page, so it needs the shadow that says so; the same step Popover and DropdownMenu sit on.",
    "name": "--float-button-shadow",
    "tier": "component",
    "value": "var(--shadow-lg)"
  },
  {
    "description": "Gap between the buttons of an open group, and between the group's list and its trigger. antd uses `padding` (16px) for both, so one token answers both.",
    "name": "--float-button-group-gap",
    "tier": "component",
    "value": "var(--space-stack-md)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--float-button-group-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The corner count/dot mark. `--float-button-badge-background` is `initial` so a scoped [data-tenant]/.dark theme that retunes --destructive still reaches the mark; the fallback is resolved at the call site in float-button-layout.css.",
    "name": "--float-button-badge-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-badge-foreground",
    "tier": "component",
    "value": "hsl(var(--destructive-foreground))"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-badge-size",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-badge-padding-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-badge-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-badge-inset-block-start",
    "tier": "component",
    "value": "calc(var(--space-1) * -1)"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-badge-inset-inline-end",
    "tier": "component",
    "value": "calc(var(--space-1) * -1)"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-badge-dot-size",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "BackTop's `showProgress` ring. The component writes `--float-button-progress-offset: <n>turn` inline (a custom property, the sanctioned escape from `no-inline-magic-numbers`) and the ring is drawn from it with `conic-gradient` — no per-frame geometry ever reaches the call site.",
    "name": "--float-button-progress-offset",
    "tier": "component",
    "value": "0turn"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-progress-width",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "default = hsl(var(--primary)), resolved at the call site",
    "name": "--float-button-progress-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Float button component tokens — the corner action and its group (Ant Design FloatButton).",
    "name": "--float-button-progress-track-color",
    "tier": "component",
    "value": "hsl(var(--border))"
  },
  {
    "description": "How far a group's list travels on the way in. TIMING IS NOT HERE — `--duration-fast` and `--ease-standard` live in the motion tier (foundation.css) and the stylesheet reads them directly, the rule activity.css states: the component-token name shape has no property word for a duration, and a second copy of the motion scale is how the two drift apart.",
    "name": "--float-button-motion-translate",
    "tier": "component",
    "value": "var(--float-button-size)"
  },
  {
    "description": "Fixed aligned label column by default (gh#284) — `max-content` sized each field's label column to its own label, so horizontal forms (especially columns={2} grids) had controls starting at ragged x positions. 8rem mirrors --descriptions-label-width so edit forms and show pages share the same optical grid; the Form/FormField `labelWidth` prop overrides.",
    "name": "--form-label-width",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "Column gap between the label and its control in horizontal/inline layout. 16px",
    "name": "--form-label-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Type in the label column. Inherits the body size by default, so nothing moves unless a service opts in. It is a knob because the label column already is one: --form-label-width lets a service align forms to its grid, and a service whose grid was drawn around a smaller label had no way to say so — leaving it to hand-write font-size per label, which is exactly what the width token exists to prevent. CHAINED to the Label primitive's own knob (gh#824), where it used to read var(--text-sm) directly. FormField passes `text-[length:var(--form-label-font-size)]` on its Label, and a utility outranks `.ui-label { font-size: var(--control-label-font-size) }` in `@layer components` — so this was not an override of the broad knob, it was a SHADOW of it: a service that set --control-label-font-size moved its 4 standalone labels and none of its 21 FormField ones (measured at 1280px, 37px on :root -> 37px vs 14px). Reading the broad knob as the default makes this one an override again, which is what \"a per-instance escape\" meant. FREE: base.css declares --text-sm AS var(--font-size-sm), the step --control-label-font-size already read, so both sides are 0.875rem and nothing moves. 14px",
    "name": "--form-label-font-size",
    "tier": "component",
    "value": "var(--control-label-font-size, var(--text-sm))"
  },
  {
    "description": "Row rhythm between a Form's own top-level blocks (gh#295) — e.g. the field group's CardContent and its CardFooter action row, or two FormFields that happen to be Form's OWN direct children (no Card framing). Modern block spacing is 24px. 24px",
    "name": "--form-block-gap",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "THE VALIDATION FEEDBACK GLYPH. It was `controlIconClass`, which is `size-[length:var(--control-height)]` — the height of a whole CONTROL, meant for something that fills a control-sized box like the ColorPicker swatch. On a `text-xs` feedback line that rendered a ~32px icon beside ~12px text, which is what a reader actually saw and reported. A glyph that sits inline with text belongs on the ICON scale, one step above the text it accompanies so it reads as a mark rather than a letter. 14px beside 12px text",
    "name": "--form-feedback-icon-size",
    "tier": "component",
    "value": "var(--icon-size-sm)"
  },
  {
    "description": "Field-to-field row rhythm (gh#295) — mirrors --descriptions-row-gap so a read-only value mixed in via `FormField.staticText` (gh#294) and a real Descriptions block share ONE canonical rhythm. Applied via margin-based sibling spacing on FormField itself (not Form's flex `gap`, which only reaches DIRECT children — dead in the common `Form > CardContent > FormField*` composition every real Save-button form needs), so it holds at any DOM depth relative to Form. 12px — shared with Descriptions",
    "name": "--form-field-row-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Row rhythm between the ROWS of a `<Form columns={n}>` grid (gh#304). The grid path cannot use the margin above — a per-item margin inside a grid double-counts the track gap AND leaves the first item of row 1 unshifted while its row-mates drop, so row 1's columns end up misaligned. The rhythm therefore rides the grid's own `row-gap`, and it DEFAULTS TO THE SAME --form-field-row-gap the stacked path uses so `columns={1}` — and every `columns={n}` form once it collapses to one column on a narrow container — is pixel-identical to a Form with no `columns` at all. Retune this alone only to give multi-column forms a looser row rhythm than stacked ones; retune --form-field-row-gap to move both together. 12px",
    "name": "--form-grid-row-gap",
    "tier": "component",
    "value": "var(--form-field-row-gap)"
  },
  {
    "description": "Gutter between the COLUMNS of a `<Form columns={n}>` grid (gh#304). Was ResponsiveGrid's generic 16px stack gap with no way to say otherwise; it is a form's inter-field gutter and a service aligning forms to its design grid needs it as a knob (rule #45). The default keeps the historical 16px, so nothing moves unless a theme opts in. 16px",
    "name": "--form-grid-column-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "The hover/focus veil over the thumbnail. default = --overlay-background",
    "name": "--image-mask-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--background))",
    "name": "--image-mask-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "IMAGE — a picture that opens large, and its full-viewport preview (`src/components/data-display/image.tsx`, antd `Image` + `Image.PreviewGroup`). The preview's scrim is the shared `--overlay-background` itself — antd's preview mask is its modal mask — so a brand that retunes every overlay's scrim retunes this one too. It is used whole, never as a share of a share (gh#886). ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\").",
    "name": "--image-mask-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "default = var(--radius)",
    "name": "--image-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The preview stage. default = --overlay-background, as antd's mask",
    "name": "--image-preview-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--background))",
    "name": "--image-preview-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "IMAGE — a picture that opens large, and its full-viewport preview (`src/components/data-display/image.tsx`, antd `Image` + `Image.PreviewGroup`). The preview's scrim is the shared `--overlay-background` itself — antd's preview mask is its modal mask — so a brand that retunes every overlay's scrim retunes this one too. It is used whole, never as a share of a share (gh#886). ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\").",
    "name": "--image-preview-inset",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "IMAGE — a picture that opens large, and its full-viewport preview (`src/components/data-display/image.tsx`, antd `Image` + `Image.PreviewGroup`). The preview's scrim is the shared `--overlay-background` itself — antd's preview mask is its modal mask — so a brand that retunes every overlay's scrim retunes this one too. It is used whole, never as a share of a share (gh#886). ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\").",
    "name": "--image-preview-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Every round control on the stage (close, prev/next, tools). ≥ the 24px WCAG 2.5.8 floor.",
    "name": "--image-preview-button-size",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "IMAGE — a picture that opens large, and its full-viewport preview (`src/components/data-display/image.tsx`, antd `Image` + `Image.PreviewGroup`). The preview's scrim is the shared `--overlay-background` itself — antd's preview mask is its modal mask — so a brand that retunes every overlay's scrim retunes this one too. It is used whole, never as a share of a share (gh#886). ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\").",
    "name": "--image-preview-button-background-alpha",
    "tier": "component",
    "value": "10%"
  },
  {
    "description": "IMAGE — a picture that opens large, and its full-viewport preview (`src/components/data-display/image.tsx`, antd `Image` + `Image.PreviewGroup`). The preview's scrim is the shared `--overlay-background` itself — antd's preview mask is its modal mask — so a brand that retunes every overlay's scrim retunes this one too. It is used whole, never as a share of a share (gh#886). ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\").",
    "name": "--image-preview-button-hover-background-alpha",
    "tier": "component",
    "value": "20%"
  },
  {
    "description": "IMAGE — a picture that opens large, and its full-viewport preview (`src/components/data-display/image.tsx`, antd `Image` + `Image.PreviewGroup`). The preview's scrim is the shared `--overlay-background` itself — antd's preview mask is its modal mask — so a brand that retunes every overlay's scrim retunes this one too. It is used whole, never as a share of a share (gh#886). ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\").",
    "name": "--image-preview-icon-size",
    "tier": "component",
    "value": "var(--icon-size-lg)"
  },
  {
    "description": "Readable document measure. Caps the header, the section column and the footer so a 1440px viewport still reads at ~75-90 characters per line.",
    "name": "--legal-document-measure-max-width",
    "tier": "component",
    "value": "46rem"
  },
  {
    "description": "Rail ↔ document column gutter (two-column mode only).",
    "name": "--legal-document-column-gap",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "Sticky table-of-contents rail width (two-column mode only).",
    "name": "--legal-document-toc-width",
    "tier": "component",
    "value": "15rem"
  },
  {
    "description": "Page inline margin of a shell used BARE, the way a public reader page uses it (gh#1296): default = --space-page-x, --space-page-compact-x at ≤720px, resolved at the call site because both re-derive under a density scope. Inside PageContainer / CenteredShell, which already pad, it resolves to 0 so the gutter is never doubled.",
    "name": "--legal-document-page-padding-inline",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Document title size — two type-scale steps above a section heading, so the h1 reads as the page title and not as one more section (gh#1296). Default = the --font-size-2xl step.",
    "name": "--legal-document-title-font-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Distance the pinned rail keeps from the top of the scrollport.",
    "name": "--legal-document-toc-inset-block-start",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Cap for a long contents list so the rail never outgrows the viewport.",
    "name": "--legal-document-toc-max-height",
    "tier": "component",
    "value": "calc(100dvh - var(--space-12))"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-toc-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-toc-item-padding",
    "tier": "component",
    "value": "var(--space-1) var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--legal-document-toc-item-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-toc-title-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-toc-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Leading marker on the active contents entry — a non-colour affordance so the active state is never colour-only (WCAG 1.4.1). default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--legal-document-toc-marker-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Gap between the `documentNavigation` slot and the contents list inside the rail.",
    "name": "--legal-document-nav-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-header-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-meta-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-meta-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-section-gap",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-section-title-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Long-form leading — legal prose reads looser than UI text.",
    "name": "--legal-document-body-line-height",
    "tier": "component",
    "value": "1.8"
  },
  {
    "description": "`scroll-margin-block-start` on every section: the offset a hash jump / anchor activation leaves above the heading so it is not hidden under sticky chrome.",
    "name": "--legal-document-scroll-offset",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-footer-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "── Chrome — quiet by default (rule #44) ───────────────────────────────────",
    "name": "--legal-document-toc-border",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-header-border",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "LegalDocumentShell component tokens — the long-form legal/policy document surface (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky table-of-contents rail. Rule #45 — every service-tunable constant is a knob: the readable measure, the rail width/offset, the section rhythm and the body leading are exactly the values a service theme wants to re-tune to match its design grid, so NONE of them are hard-coded in `src/styles/layout.css`. Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to `none`. A service opts IN via theme, e.g. --legal-document-toc-border: var(--stroke-hairline) solid hsl(var(--border)); Colour knobs whose default is a ROLE token are declared `initial` here with the role default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\" — so a scoped `[data-tenant]` / `.dark` override of the role still reaches them.",
    "name": "--legal-document-footer-border",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "── Role-mirror knobs — `initial` here, role default at the call site ─────── default = hsl(var(--muted-foreground))",
    "name": "--legal-document-meta-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted-foreground))",
    "name": "--legal-document-summary-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted-foreground))",
    "name": "--legal-document-toc-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--foreground))",
    "name": "--legal-document-toc-active-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--accent))",
    "name": "--legal-document-toc-active-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--primary))",
    "name": "--legal-document-toc-marker-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ListRow component tokens — a single-line entity row for short lists inside a Card (sessions / API tokens / linked accounts / passkeys / notifications …). Sits in a flush CardContent; rows separate with a quiet divider (#44 — chrome defaults to the calm semantic border).",
    "name": "--list-row-padding-y",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "ListRow component tokens — a single-line entity row for short lists inside a Card (sessions / API tokens / linked accounts / passkeys / notifications …). Sits in a flush CardContent; rows separate with a quiet divider (#44 — chrome defaults to the calm semantic border).",
    "name": "--list-row-padding-x",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "ListRow component tokens — a single-line entity row for short lists inside a Card (sessions / API tokens / linked accounts / passkeys / notifications …). Sits in a flush CardContent; rows separate with a quiet divider (#44 — chrome defaults to the calm semantic border).",
    "name": "--list-row-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Row divider — `initial` so the --border default re-resolves at the call site under a scoped theme (a :root binding to a role var freezes at :root). Default = 1px solid hsl(var(--border)).",
    "name": "--list-row-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Inline size the content column keeps before the trailing actions wrap onto their own line (#45 — a service retunes the stack threshold to its grid). Clamped with min(…, 100%) at the call site, so a container narrower than the knob can never force page-root overflow (#224).",
    "name": "--list-row-body-min-width",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "Gap BETWEEN trailing actions — they also wrap among themselves at narrow widths (#224).",
    "name": "--list-row-trailing-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "── Compact inline-actions geometry (`density=\"compact\"`, #246) ────────────────────────── The canonical invitation / history row: a 36px leading avatar, a shrinkable title + description body and one or two small trailing Buttons, all on ONE line inside the canonical 358px card (326px content after the row's own inline inset) at a 390px viewport. These knobs only LOWER the geometry — the #224 wrap contract (row + trailing cluster wrap, body clamped with min(…, 100%)) is untouched, so a cluster that genuinely cannot fit still wraps instead of widening the page root. Declared `initial` so the spacing defaults re-resolve at the CALL SITE — --space-2 is density-scaled and re-declared inside a `.ui-density-*` subtree, so a :root binding would freeze compact rows at the :root density (docs/TOKENS.md — the :root freeze rule). Defaults = var(--space-2) block padding · var(--list-row-padding-x) inline padding · var(--space-2) gap.",
    "name": "--list-row-compact-padding-y",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Inline inset defaults to the default row axis so compact and default rows in the same Card keep one optical axis; a service retunes it to its own grid (#45).",
    "name": "--list-row-compact-padding-x",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ListRow component tokens — a single-line entity row for short lists inside a Card (sessions / API tokens / linked accounts / passkeys / notifications …). Sits in a flush CardContent; rows separate with a quiet divider (#44 — chrome defaults to the calm semantic border).",
    "name": "--list-row-compact-gap",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Compact body threshold — small enough that avatar + body + two compact Buttons fit the canonical column (36 + 8 + 96 + 8 + 146 = 294 ≤ 326), and still a readable measure.",
    "name": "--list-row-compact-body-min-width",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "Read (default) row surface — `initial`, documented default = transparent, i.e. the Card surface shows through untouched (#44 — chrome defaults to the quietest state).",
    "name": "--list-row-read-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Unread emphasis surface (`unread` rows) — `initial` so the --muted default re-resolves at the call site under a scoped theme. Documented default = hsl(var(--muted)), the same quiet emphasis role the table header uses; it keeps the xs muted description line at WCAG AA (4.63:1 light / 5.47:1 dark), which hsl(var(--accent)) would not (4.23:1 light).",
    "name": "--list-row-unread-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Unread indicator dot fill — `initial` so the --primary default re-resolves at the call site under a scoped theme. Documented default = hsl(var(--primary)).",
    "name": "--list-row-indicator-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Diameter of the read/unread indicator dot; the gutter is reserved on read rows too so the titles of a mixed list stay on one optical axis.",
    "name": "--list-row-indicator-size",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--logo-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-size-xs",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-size-sm",
    "tier": "component",
    "value": "1.5rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-size-md",
    "tier": "component",
    "value": "1.75rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-size-lg",
    "tier": "component",
    "value": "2.25rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-font-size-xs",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-font-size-sm",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-font-size-md",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-font-size-lg",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Semantic identity fill reads the --brand IDENTITY role: independent of --primary (a re-themed action colour never recolours the mark) AND of --success (the 若竹 STATUS green stays on badges/progress/\"saved\" text — the mark used to borrow it and rendered ΔE76 ≈ 17.5 off the canonical emerald, gh#250). Services retune the role once for every Logo. ROLE-MIRROR KNOBS — declared `initial` here with the role default at the CALL SITE (logo-layout.css), so a scoped `.dark` / `[data-tenant]` override of --brand actually reaches the mark instead of freezing at the :root value (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Documented defaults: --logo-success-background = hsl(var(--brand)) --logo-success-foreground = hsl(var(--logo-identity-foreground)) --logo-godx-color = hsl(var(--brand))",
    "name": "--logo-success-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-success-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-godx-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Identity-fill INK — the ink `mark=\"glyph\"` sets its (caller-supplied) TEXT in when it sits on the --brand identity fill. This is deliberately NOT --brand-foreground. --brand-foreground is the identity artwork's KNOCKOUT colour, not an ink: it tracks --background in both themes (light 60 33% 99% = --background; dark 48 9% 9% = --background) because `<Logo mark=\"godx\">` punches its inner bar as an evenodd HOLE and the email mark has to paint that hole as a solid fill to match. Negative space only has to clear WCAG 2.2 SC 1.4.11 (3:1, non-text) — and at 3.67:1 on the emerald it does. The boxed glyph is a different thing: it renders real TEXT, so SC 1.4.3 applies at 4.5:1 (14px bold is NOT \"large text\" — that needs 18.66px bold / 24px). THIS INK USED TO BE THEME-INVARIANT, AND THE VIOLET IDENTITY ENDED THAT. While --brand was 翠 emerald the fill was light in BOTH themes, so one near-black ink cleared AA on both. Brand identity v2.3 makes the fill #7A00FF in light and #DCBCFF in dark — dark and light respectively — so a single ink cannot serve both: measured, near-black on the light-theme violet is 2.77:1, a real AA failure, while the same ink on the dark-theme violet is 10.72:1. The GoDX emerald-teal of gh#1345 keeps the same polarity (#008066 light, #5CD6BE dark). So the ink now FLIPS with the theme, and each side is measured on the GoDX preset: light ink 60 33% 99% (#fdfdfb) on #008066 = 4.86:1 dark ink 48 9% 9% (#191815) on #5CD6BE = 9.99:1 The dark override lives HERE and not in foundation.css on purpose: `:root` and `.dark` have equal specificity, and tokens/base.css imports this file AFTER foundation.css — so a `.dark` rule there would lose to the `:root` rule here. Same file, later block, no ambiguity. A service that re-themes --brand to a fill of the opposite lightness overrides --logo-success-foreground (the public knob) to re-invert the ink. NOT a role-mirror knob: its default is a real value, not a role token, so there is no role to freeze at :root and the `initial` + call-site rule (docs/TOKENS.md) does not apply to it.",
    "name": "--logo-identity-foreground",
    "tier": "component",
    "value": "60 33% 99%"
  },
  {
    "description": "── The LOGOTYPE ink (`<Logo mark=\"godx-lockup\" />`, identity v2.3) ──────────────────────── The lockup's letters G, o and D are the kit's indigo #0B0F3B; the mark and the X are the brand identity colour and read --logo-godx-color instead. They are two ROLES, not a decorative split, so they get two knobs. A TOKEN AND NOT THE LITERAL, because the literal only works in one theme: #0B0F3B is 18.00:1 on the light canvas and 1.03:1 on the dark one — invisible. Dark takes the kit's own dark text colour instead (#F7FAF8, 16.87:1), flipped in the block at the end of this file the same way the boxed glyph's ink is.",
    "name": "--logo-godx-ink-color",
    "tier": "component",
    "value": "235 68.6% 13.7%"
  },
  {
    "description": "── Optical centring of the boxed GLYPH (`<Logo glyph=\"…\" />`, gh#370) ───────────────────── A vertical nudge of the glyph's INK inside the mark box, in `em` so one value holds at every tier. Applied with `translate` (styles/logo-layout.css): the box, the fill and the layout are untouched, only the letterform moves. WHY THERE ARE FOUR. `place-items: center` centres a LINE BOX, and a line box is not a letterform. Every CSS rule available is ONE constant shift that cannot see which character it is moving, and the glyph classes do not share an optical centre: measured over Noto Sans JP, M PLUS 2, Hiragino Sans and the system stack × xs/sm/md/lg, their ink centres lie 0.21em apart. So the COMPONENT classifies the glyph string it was handed — the only layer that can — and emits `data-ink`; these are the per-band constants it selects between. The band is the (top edge, bottom edge) of the UNION of the string's ink, so `\"gX\"` is cap→descender, not `\"g\"`'s x-height→descender. Every CJK and kana form counts as a cap-height top: the em box overshoots the cap band above the baseline and below it by about the same amount, so it centres where a capital does (measured -0.001em against -0.008em). MEASURED — worst |ink offset| from the box centre over 4 faces × 4 tiers × the sample listed: cap-baseline -0.01em 1.38px G GX TH A 8 b kt J 神 あ ン ゴ 神A Aあ cap-descender -0.09em 1.25px gX Gy Bp hy 神g gあ 東y x-baseline -0.11em 0.88px x o xo ae s x-descender -0.21em 0.94px g y p q go Worst case 1.38px, against 2.25px for the best glyph-blind rule (`text-box: trim-both ex alphabetic`) and 3.94px untreated, on that same sample. The residual is within-band variation — kana do not all fill the em box (ゴ sits 0.04em above 神) — plus the half-pixel the browser snaps a line box by; no classifier can remove either.",
    "name": "--logo-glyph-cap-baseline-optical-offset",
    "tier": "component",
    "value": "-0.01em"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-glyph-cap-descender-optical-offset",
    "tier": "component",
    "value": "-0.09em"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-glyph-x-baseline-optical-offset",
    "tier": "component",
    "value": "-0.11em"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-glyph-x-descender-optical-offset",
    "tier": "component",
    "value": "-0.21em"
  },
  {
    "description": "The escape hatch, for a mark none of the four bands fits — a face with unusual metrics, or a glyph the classifier cannot see (an inline `<svg>`, which is left unclassified on purpose). Set once and it PINS every band to that value. Declared `initial` (guaranteed-invalid) so it is inert by default and the per-band default at the CALL SITE wins — the same pattern as --logo-godx-size (docs/TOKENS.md). Documented default: --logo-glyph-optical-offset = the --logo-glyph-*-optical-offset for the band the glyph was classified into, or 0 when it was not classified.",
    "name": "--logo-glyph-optical-offset",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── Fitting the glyph to the mark box (`<Logo glyph=\"東京\" size=\"xs\" />`, gh#377) ─────────── `.ui-logo` is a fixed square and the glyph was set at a fixed per-tier font-size, so nothing related the string's INLINE ADVANCE to the box it had to fit in. A full-width form occupies a whole em, and CJK offers a line-break opportunity between EVERY pair of ideographs — so two kanji in the 20px `xs` box did not overflow, they WRAPPED into a two-line mark. Latin never showed this because a Latin word has no interior break opportunity: it silently spilled instead. Measured across Noto Sans JP / M PLUS 2 / Hiragino Sans / the system stack × the four tiers, the wrap hit 東京 神戸 ゴジ 株式 at xs and sm, 東京都 at every tier, and — already inside the gh#370 sample — 神A and Aあ on Hiragino at xs. THE FIX IS THE SAME SHAPE AS gh#370. CSS cannot see the string, so it cannot know what advance to make room for; the COMPONENT can. It counts the string's characters in four classes and emits them as --logo-glyph-fullwidth-count / --logo-glyph-wide-count / --logo-glyph-narrow-count / --logo-glyph-space-count (pure, no measurement, no layout read, SSR-safe). styles/logo-layout.css turns those counts into a modelled advance and caps the glyph's font-size at the size that advance fits in — `min()`, so a mark whose advance already fits keeps its tier font-size EXACTLY and nothing that renders correctly today moves. `white-space: nowrap` sits under it as the invariant: a brand mark is one line. EACH CONSTANT IS AN UPPER BOUND OF ITS CLASS — that is the entire contract. Over-stating an advance sets the mark a little smaller than it had to be; under-stating it puts the mark OUTSIDE the box, which is the defect this whole mechanism exists to remove. The first cut carried one constant for every proportional form and dropped white space from the count, and both under-states shipped as spill (`WW` 3.50px, `東 京` 2.63px — see below). THE INVARIANT, stated as the gate asserts it: for every mark, at every tier, on every bundled face, the FITTED font-size times the PAINTED advance stays inside the box. Not \"each constant bounds its class in isolation\" — see the recorded slack below. MEASURED advance in em, per character, max over the four faces (a DOM advance read at 200px, never a canvas `fillText`: that substitutes a fallback face for a webfont): full-width form 1 ← 1.000 神 · 東 · あ · ゴ · 株 · 「 · 、 · Ｇ, every one 1.0000 em-wide Latin 1.06 ← 1.058 W 1.0580 · m 1.0100 · M 0.9870 — all Hiragino Sans other Latin/digit 0.81 ← 0.863 w 0.8630 · O/Q 0.8380 · U 0.8291 · H 0.8260 · N 0.8210 · X 0.8110 · 8 0.7120 · k/t 0.5435 · l 0.3150 collapsible space 0.34 ← 0.333 Hiragino 0.3330 · M PLUS 2 0.2730 · Noto 0.2270 · system 0.1978 `M W m` get a class of their own because they REACH the full-width em — `W` passes it, at 1.058em WIDER than a kanji — so no proportional constant holds them without shrinking every other Latin mark to fit. With them out of the way the narrow class stays at 0.81. RECORDED SLACK, not an oversight: six forms (w · O · Q · U · H · N · X) measure 0.811–0.863em, above the 0.81 constant, by at most 0.053em. Measured, none of them reaches the box edge at its tier's font-size — `ww` at xs paints 19.2px of a 20px box — so raising the constant to 0.87 would shrink 120 of 480 measured cells to buy nothing, against this file's own rule that a mark which already fits keeps its tier font-size to the byte. The gate re-derives the margin from the shipped tokens, so a change to the type scale or the box ramp re-tests it rather than inheriting this conclusion. --logo-glyph-fit-max-width is the share of the box a FITTED glyph's modelled advance may take. 0.95 leaves 0.50px (xs) / 0.60px (sm) / 0.70px (md) of fill clear of the modelled ink on each side of a two-kanji mark — measured on the paint, 0.50–1.50px at xs across the four faces, against the 0.5px minimum the library already ships (神A on M PLUS 2 at xs). It is a CAP, not a target: it only binds on the marks that do not fit.",
    "name": "--logo-glyph-fullwidth-width",
    "tier": "component",
    "value": "1"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-glyph-wide-width",
    "tier": "component",
    "value": "1.06"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-glyph-narrow-width",
    "tier": "component",
    "value": "0.81"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-glyph-space-width",
    "tier": "component",
    "value": "0.34"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-glyph-fit-max-width",
    "tier": "component",
    "value": "0.95"
  },
  {
    "description": "── Identity-mark box (`<Logo mark=\"godx\" />`) ────────────────────────────────────────────── The `size` prop drives the identity mark exactly like it drives the boxed glyph — a public prop that renders identically at every tier is a silent no-op, and the godx LOCKUP already scaled its wordmark per tier, so a fixed mark broke the mark↔wordmark proportion at `size=\"lg\"` (gh#163 follow-up). The godx artwork is a horizontal capsule inside a square viewBox, so it carries less optical weight than the fully-filled glyph box: each tier sits +0.25rem above its --logo-size-* sibling. `md` is 2rem — the historical fixed value — so every existing default-size identity surface renders byte-identically. --logo-godx-size is the PIN: declared `initial` (guaranteed-invalid) here with the per-tier default at the CALL SITE (logo-layout.css), so it is inert by default and a service that sets it once freezes the mark at that box on EVERY tier — the same call-site pattern the role-mirror colour knobs use (docs/TOKENS.md). Retune a single tier via --logo-godx-size-*. Documented default: --logo-godx-size = unset (tiers apply).",
    "name": "--logo-godx-size-xs",
    "tier": "component",
    "value": "1.5rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-godx-size-sm",
    "tier": "component",
    "value": "1.75rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-godx-size-md",
    "tier": "component",
    "value": "2rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-godx-size-lg",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-godx-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── Wordmark / lockup (`<Logo wordmark=\"GoDX\" />`) ───────────────────────────────────────── The readable product name set beside the mark. The package ships NO wordmark artwork: the wordmark is typeset in the design-system display face, so a service retunes face, weight, tracking, size and the mark↔wordmark gap here instead of writing page CSS. The colour is a role-mirror knob whose default is the IDENTITY role --brand (never --primary, never the --success status green): the GoDX/`success` lockup is canonical emerald out of the box, and every other lockup reads --foreground. Documented defaults: --logo-wordmark-font-family = var(--font-family-display); --logo-wordmark-color = hsl(var(--foreground)), or hsl(var(--brand)) on the godx / tone=\"success\" lockup.",
    "name": "--logo-wordmark-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-font-size-xs",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-font-size-sm",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-font-size-md",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-font-size-lg",
    "tier": "component",
    "value": "var( --font-size-lg, calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)) )"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-font-weight",
    "tier": "component",
    "value": "700"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-letter-spacing",
    "tier": "component",
    "value": "-0.01em"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-font-family",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-wordmark-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── The PRODUCT SUFFIX (`<Logo mark=\"godx-lockup\" productSuffix=\"ID\" />`, gh#649) ────────── \"GoDX | ID\" — the brand lockup followed by a rule and the name of ONE product. Later also \"GoDX | Console\", \"GoDX | Admin\", and each of those localized. WHY THE SUFFIX IS TYPESET AND NOT DRAWN. The kit hands over \"GoDX | ID\" as a single flattened lockup in its own coordinate space (`0 0 1234 242`, against this package's `30 30 871.29 182`), so shipping it would put a SECOND master next to the one above — different box, different gradients, its own `id=\"title\"`/`id=\"desc\"`, its own hardcoded `#0B0F3B` ink and `#C5C8D6` rule. That is four of the defects gh#649 was opened about, and it buys nothing that survives the next product: a drawn suffix means one more master, one more release and one more dark variant for every name that is ever added, and it cannot be localized at all. So the suffix is TEXT — the same decision, and the same tokens, the readable `wordmark` already uses. The brand's own construction (the G, the arrow, the \"GoDX\" logotype, the golden ratio between them) stays untouched inside the master; a PRODUCT NAME is not part of that construction. SIZE / FACE / TRACKING ARE THE WORDMARK'S, ON PURPOSE. The suffix sits on the same baseline, in the same lockup, at the same optical level as the wordmark, so it reads --logo-wordmark-font-size-* / --logo-wordmark-font-family / --logo-wordmark-letter-spacing rather than growing a parallel ramp a service would then have to keep in step. Only the two knobs whose ROLE differs get their own token: the suffix is not the brand logotype, so it is set in UI ink (--foreground) at a lighter weight, and \"GoDX\" stays the dominant word. THE RULE. --logo-divider-height is `1em` of the suffix's own type, so the tick is exactly as tall as the word it separates at every tier with no per-tier token: 12.5 / 14 / 14 / 17.6px against a 24 / 28 / 32 / 40px lockup box. ITS COLOUR IS THE LOGOTYPE'S INK AT 0.25 ALPHA, NOT A GREY AND NOT --border. Measured on the shipped tokens: light #0B0F3B at 0.25 over --background #fdfdfb → #c1c2cb, 1.74:1 the kit's hardcoded rule #c5c8d6 → 1.64:1 (ΔRGB ≤ 11, no dark counterpart) --border (the table-grid hairline) → 1.15:1 (its own note above records this) dark #F7FAF8 at 0.25 over --background #191815 → #515150, 2.30:1 So the rule lands on the kit's grey in the theme the kit drew it for, and — unlike the literal — it has a dark theme at all, because it is derived from --logo-godx-ink-color, which already flips. ALPHA rather than a mix with --background, so the rule is still correct on a coloured topbar. Nothing here is WCAG-load-bearing: SC 1.4.11 exempts a part of a logo or brand name. ROLE-MIRROR KNOBS — `initial` here, role default at the CALL SITE (docs/TOKENS.md). Documented defaults: --logo-divider-color = var(--logo-godx-ink-color) --logo-product-suffix-color = hsl(var(--foreground)) default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--logo-divider-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-divider-height",
    "tier": "component",
    "value": "1em"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-divider-alpha",
    "tier": "component",
    "value": "0.25"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-divider-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-product-suffix-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-product-suffix-font-weight",
    "tier": "component",
    "value": "500"
  },
  {
    "description": "Logo component tokens — the product brand-mark box (a glyph on the primary fill), used in the app shell header, auth screens, and topbars. Size + radius + per-tier font-size are knobs so a service theme retunes the mark without forking CSS (rules #44/#45). Colours read the primary role tokens directly, so a re-themed --primary re-tints the mark automatically.",
    "name": "--logo-product-suffix-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The other half of the ink flip above — see --logo-identity-foreground. The dark fill is the LIGHT green #5CD6BE in the GoDX preset, so the glyph goes back to the near-black spine (9.99:1).",
    "name": "--logo-identity-foreground",
    "tier": "component",
    "value": "48 9% 9%"
  },
  {
    "description": "The kit's dark text colour — #F7FAF8, 16.87:1 on the dark canvas.",
    "name": "--logo-godx-ink-color",
    "tier": "component",
    "value": "140 23.1% 97.5%"
  },
  {
    "description": "Space between items inside one copy AND between copies — they are the same rhythm, so they are one knob. The trailing gap is painted as the copy's own `padding-inline-end`, which is what makes the seam between two copies indistinguishable from the seam between two items. The `gap` prop overrides it per instance; this is the resting value a service sets once.",
    "name": "--marquee-gap-inline",
    "tier": "component",
    "value": "var(--space-inline-lg)"
  },
  {
    "description": "Width of the fade at each edge under `fade`. A MASK, so it reveals whatever the surface behind it is — the prior art paints an opaque `gradientColor` (default \"white\"), which is a white smear on a dark theme.",
    "name": "--marquee-mask-width",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "Resting spacing between tiles, per axis, when the `gap` prop is omitted. Ant Design's `gutter` defaults to `0` and this ports that default exactly — a service that wants every masonry in the product to breathe sets these two once in its theme.css, and a per-instance `gap` still wins. The packer READS the resolved `row-gap` back off the container, so this token (or the `gap` prop that overrides it) is the single source for both the painted spacing and the arithmetic. There is no second number in the TypeScript.",
    "name": "--masonry-gap-inline",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Masonry component tokens — Ant Design `Masonry` (6.0.0): tiles of unequal height packed into columns. antd retunes this surface through `classNames` / `styles` semantic maps. Those are deliberately not ported (cardinal rules #44/#45, docs/DESIGN-AUTHORITY.md — \"a knob that only a fork could reach is not parity either\"); this file is the answer instead. TIMING IS NOT HERE. The re-flow and the appear fade read `--duration-base` / `--ease-standard` from the motion tier (src/tokens/foundation.css), because the component-token name shape (`--{component}-{part}-{property}`) has no property word for a duration and a second copy of the motion scale is how the two drift apart — the same note `float-button.css` and `activity.css` carry. The COLUMN COUNT is not a token. It is `columns`, a prop, because a masonry's column count is the call site's decision about that collection and not a global design knob.",
    "name": "--masonry-gap-block",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Bar",
    "name": "--mega-menu-bar-gap",
    "tier": "component",
    "value": "var(--space-inline-xs)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-height",
    "tier": "component",
    "value": "var(--control-height)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-padding-x",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--mega-menu-trigger-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-foreground",
    "tier": "component",
    "value": "hsl(var(--foreground))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-background",
    "tier": "component",
    "value": "transparent"
  },
  {
    "description": "ROLE-MIRROR KNOBS — `initial`, NOT `hsl(var(--accent))` (gh#687, docs/TOKENS.md). A tier that binds to a tenant-scoped role computes ONCE at `:root` and every descendant inherits that computed colour, so a `[data-tenant]` block redefining `--accent` would leave this bar on the root brand while its neighbours followed. The knob stays empty here and the role is the FALLBACK at the call site in styles/navigation-layout.css, which re-resolves per scope. Documented defaults: hover/open = accent on accent-foreground, current = primary.",
    "name": "--mega-menu-trigger-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--mega-menu-trigger-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-hover-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-open-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-open-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-current-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-trigger-disabled-alpha",
    "tier": "component",
    "value": "0.5"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-expand-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size-sm)"
  },
  {
    "description": "Panel surface",
    "name": "--mega-menu-panel-background",
    "tier": "component",
    "value": "hsl(var(--popover))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-panel-foreground",
    "tier": "component",
    "value": "hsl(var(--popover-foreground))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-panel-border-color",
    "tier": "component",
    "value": "hsl(var(--border))"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--mega-menu-panel-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--mega-menu-panel-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-panel-padding",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-panel-shadow",
    "tier": "component",
    "value": "var(--shadow-md)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-panel-offset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "A forty-link panel must not run off the bottom of a laptop; past this it scrolls in the block axis and nothing is unreachable.",
    "name": "--mega-menu-panel-max-height",
    "tier": "component",
    "value": "70vh"
  },
  {
    "description": "Travel of the open animation. Zeroed under prefers-reduced-motion, where the panel SNAPS into place — it is never removed, only un-animated.",
    "name": "--mega-menu-panel-translate",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Panel columns",
    "name": "--mega-menu-groups-gap",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-group-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "A column may not get narrower than this before the grid drops to fewer columns; this is what keeps a 40-link panel readable instead of pouring it into one ribbon.",
    "name": "--mega-menu-group-min-width",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-group-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-group-label-foreground",
    "tier": "component",
    "value": "hsl(var(--muted-foreground))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-group-description-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-group-description-foreground",
    "tier": "component",
    "value": "hsl(var(--muted-foreground))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-group-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size-sm)"
  },
  {
    "description": "Panel rows",
    "name": "--mega-menu-link-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-padding-x",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-padding-y",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--mega-menu-link-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-foreground",
    "tier": "component",
    "value": "hsl(var(--foreground))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--mega-menu-link-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-hover-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-current-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-description-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-description-foreground",
    "tier": "component",
    "value": "hsl(var(--muted-foreground))"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-link-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size-sm)"
  },
  {
    "description": "A nav row is a WCAG 2.2 SC 2.5.8 target: the AA floor, scale-exempt like the token itself.",
    "name": "--mega-menu-link-min-height",
    "tier": "component",
    "value": "var(--touch-target-min)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-panel-footer-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "MegaMenu — the disclosure navigation bar and its full-width panel. Every knob a theme would want to move lives here: nothing in navigation-layout.css writes a literal length for this component. The trigger's BOX HEIGHT is deliberately a pointer at the `--control-height` tier and never an offset of it (cardinal rule #45 / check:control-sizing) — a bar cell must sit on the same step as the Buttons beside it in a real top bar, and that step is density-aware.",
    "name": "--mega-menu-panel-footer-border-color",
    "tier": "component",
    "value": "hsl(var(--border))"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--pagination-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--pagination-item-gap",
    "tier": "component",
    "value": "var(--space-inline-xs)"
  },
  {
    "description": "Size-changer trigger MIN width (gh#286) - the trigger sizes to its content (w-max) so localized labels (ja 100/ページ) never clip; this token only keeps short labels from collapsing below the control rhythm.",
    "name": "--pagination-size-width",
    "tier": "component",
    "value": "5.5rem"
  },
  {
    "description": "Inline padding on a page button. The button keeps min-width: var(--control-height), so this only takes effect once a number outgrows that box. Deliberately --space-1 rather than --space-2: at the wider value a two-digit label (14.8px of text + 2 * 8px + 2px border) came to 32.8px and pushed the common 1–2 digit buttons off square by 0.8px.",
    "name": "--pagination-page-padding-x",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--pagination-total-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Chevron glyph inside the `simple` form's Prev/Next Buttons (#319). Those are size=\"sm\" Buttons, so `.ui-button--sm svg` would draw them at --control-icon-size-sm; the component pinned them larger with a literal `size-4` class instead, because in simple mode the chevron IS the control — there is no label beside it to carry the affordance. The knob keeps that deliberate override themeable (rule #45) and tracks the default control-icon tier, so it now follows density like every other control glyph instead of staying a flat 1rem.",
    "name": "--pagination-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size)"
  },
  {
    "description": "Ant Design `size=\"small\"`. Retuned as ONE local --control-height on the bar, so the page buttons, the size-changer trigger and the quick-jumper field shrink together instead of each carrying its own tier — exactly how a service would retune the whole footer. Declared `initial` (gh#705): the documented default is `var(--control-height-sm)`, resolved at the bar, so a small pager inside a density scope (a compact DataTable, whose toolbar Buttons are 25.76px) sits on the same step as its neighbours instead of a frozen 28px band.",
    "name": "--pagination-control-height-sm",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Ant Design `showQuickJumper`. The field is sized to a page NUMBER, not to a sentence, so it gets its own width rather than the shared control measure.",
    "name": "--pagination-jumper-gap",
    "tier": "component",
    "value": "var(--space-inline-xs)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--pagination-jumper-width",
    "tier": "component",
    "value": "4rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--pagination-jumper-font-size",
    "tier": "component",
    "value": "var(--pagination-total-font-size)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-bar-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-bar-padding-y",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-picker-width-sm",
    "tier": "component",
    "value": "11rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-picker-width-md",
    "tier": "component",
    "value": "14rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-inline-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-inline-item-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-inline-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-inline-separator-size",
    "tier": "component",
    "value": "var(--control-icon-size-sm)"
  },
  {
    "description": "Inline-step emphasis (gh#12). The step number's weight and tint are separate knobs so a service can express progression the canonical way — an accent TINT at normal weight — instead of the original bold. --steps-inline-index-color / --steps-inline-separator-color are role-mirror knobs (docs/TOKENS.md): `initial` so their defaults (the inherited step colour and the --muted-foreground role) resolve at the CALL SITE and a scoped [data-tenant]/.dark override still reaches them. Defaults reproduce today's row byte for byte.",
    "name": "--steps-inline-index-font-weight",
    "tier": "component",
    "value": "var(--font-weight-bold)"
  },
  {
    "description": "default = currentColor at the call site",
    "name": "--steps-inline-index-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted-foreground))",
    "name": "--steps-inline-separator-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "AppSettingPicker `compact` (gh#217) — the small, content-hugging labelled trigger used in an auth/legal footer, where the square icon-only default reads as a stray button and the full labelled trigger is too tall. Box height comes from the official --control-height-sm tier (never a literal / ad-hoc calc), and every other knob is themeable (rule #45).",
    "name": "--app-setting-picker-compact-control-height",
    "tier": "component",
    "value": "var(--control-height-sm)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-compact-padding-x",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-compact-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-compact-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--breadcrumb-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Ant Design `BreadcrumbItemType.menu` — the sibling picker hung off a segment. The trigger is the segment's own text plus a disclosure chevron, so it only needs the gap between them.",
    "name": "--breadcrumb-menu-trigger-gap",
    "tier": "component",
    "value": "var(--space-inline-xs)"
  },
  {
    "description": "`BreadcrumbItemProp.ellipsis` (gh#1046) — the widest a truncating crumb may grow. `none` = it only cuts when the one-line trail runs out of room; a theme may cap it (e.g. `16em`).",
    "name": "--breadcrumb-item-max-inline-size",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-shortcut-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-list-max-inline-size",
    "tier": "component",
    "value": "100%"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-list-overflow",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "THE DEFAULT STRIP'S TRACK AND ITS SELECTED SLAB (gh#880 item 3) — the pair whose absence was the defect the owner spotted by eye: a translucent Card whose Tabs strip stayed opaque `--muted`, so \"các card này có đồng bộ đéo đâu\". Both used to be Tailwind utilities on the component (`data-[variant=default]:bg-muted` on the list, `data-[state=active]:bg-background` on the trigger), i.e. `@layer utilities`, which outranks every rule this package can write — the strip was not merely un-knobbed, it was unreachable. `--segmented-track-background` / `--segmented-item-selected-background` are the SAME track-and-slab pair and have been knobs since gh#848; `segmented.css` says in so many words that its role ports \"are the ones `Tabs` ALREADY MADE\". So these two are named after that pair and default to exactly the roles the utilities painted. `initial` with the default at the call site, for the reason that file measured: written `var(--muted)` here the binding substitutes on `<html>` and a scope below root inherits the root's answer, which reads as correct only because `.dark` also lands on `<html>`. default = hsl(var(--muted)) at the call site",
    "name": "--tabs-list-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--tabs-list-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--background)) at the call site",
    "name": "--tabs-trigger-active-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--tabs-trigger-active-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Width at or below which `tabPlacement=\"start\"`/`\"end\"` folds to `top`/`bottom` (gh#502) — a vertical strip and its panel share one inline axis and a phone has room for one of them. Same line `--sheet-responsive-breakpoint-width` draws; `0px` (which no viewport matches) turns the fold off. Read in JS (src/lib/breakpoint-token.ts) because the fold also swaps which arrow keys move the roving focus — see the note on `foldVerticalPlacement` in navigation/tabs.tsx.",
    "name": "--tabs-placement-responsive-breakpoint-width",
    "tier": "component",
    "value": "48rem"
  },
  {
    "description": "Tabs `line` active indicator (gh#248) — the ONLY selected-state decoration the line variant paints. The surrounding active ring belongs to the default/card lists, so `:focus-visible` keeps its own distinct keyboard ring here (WCAG 2.4.7). `--tabs-indicator-background` is a role-mirror knob: `initial` so hsl(var(--primary)) re-resolves at the CALL SITE under a scoped [data-tenant]/.dark theme (a :root binding to a role var would freeze at :root). Default = hsl(var(--primary)) · 2px thick · flush with the trigger edge (offset 0 = quietest, rule #44); a service raises the offset to park the bar on a thicker strip hairline.",
    "name": "--tabs-indicator-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-indicator-size",
    "tier": "component",
    "value": "2px"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-indicator-offset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Ant Design `indicator.size` — the bar's LENGTH along the strip, as the inset it leaves at EACH end of the trigger. `0px` = antd's own default (`getLength` returns `origin`, the tab's whole offset width), so the default paint does not move. `indicator={{ size: \"label\" }}` on the component repoints this at the trigger's own inline/block padding, which is what `size: (origin) => origin - 2 * padding` is written to produce upstream (@rc-component/tabs src/hooks/useIndicator.ts).",
    "name": "--tabs-indicator-inset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Gap between the tab strip and the panel below it.",
    "name": "--tabs-root-gap",
    "tier": "component",
    "value": "0.5rem"
  },
  {
    "description": "Inset of the `line` strip. The default/pill strip keeps its own padding box; the line strip is a flat underlined rail, so its default is the quietest value — none (rule #44). Raise it to give the rail breathing room above its hairline.",
    "name": "--tabs-list-line-space-inset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "GUTTER BETWEEN TRIGGERS on the `line` strip — Ant Design's `tabBarGutter`, which is declined as a PROP and lives here instead (cardinal rules #44/#45): a number of pixels handed straight to the caller is not a semantic axis, it is a constant, and a constant belongs to the theme. A RAW rem, not `var(--space-1)` — the same rule the block above states and for the same reason: `gap-1` reads Tailwind's own --spacing grid, which this repo does NOT density-scale, so a --space-* default would silently widen the gutter under a comfortable density. 0.25rem is byte for byte what `gap-1` resolved to, so no strip moves. A service that wants the gutter to follow density points this at var(--space-1) itself. The other two strips already had their knob: the card strip reads `--tabs-card-list-space-gap`, and the pill strip has no gutter at all by design (its triggers are `flex-1` inside one padded box). This was the one strip a service could only retune by forking the class list. scale-exempt: it must equal what the `gap-1` it replaces painted. --space-1 is 0.25rem at the default density but calc(0.25rem * var(--scaling)) under any other, and Tailwind's own --spacing grid — which this repo does not density-scale — is what the strip was drawn against. Binding it to the step would move a gutter this commit exists not to move.",
    "name": "--tabs-list-line-space-gap",
    "tier": "component",
    "value": "0.25rem"
  },
  {
    "description": "BLOCK HEADROOM FOR THE FOCUS RING (gh#376). The horizontal strip is a scroll container (`overflow-x: auto` + `overflow-y: hidden`), and a block-axis clip shaves whatever a trigger paints outside its own box — measured in Chromium, the `line` strip gives its triggers 0px of block headroom, so the entire focus ring was cut off top and bottom. The headroom has to come from LAYOUT, not from relaxing the clip: `overflow-y: visible` beside `overflow-x: auto` computes back to `auto` per spec (a second scroll container, not a ring), and Chromium honours `overflow-clip-margin` only when BOTH axes are `clip`, so a single-axis clip silently drops it. The strip therefore pads its block axis by the ring's outer reach and pulls the same amount back with a negative block margin, so the ring paints INSIDE the scrollport while the strip occupies exactly the space it did before. `initial` (the role-mirror rule in docs/TOKENS.md, not a :root binding) because the default is derived from `--focus-ring-*`, which components and tenants DO re-scope; binding it at :root would freeze the headroom while the ring it is sized from moved. Documented default = `calc(var(--focus-ring-width) + var(--focus-ring-glow-width))` — the ring's outer reach, read at the call site so the two can never disagree.",
    "name": "--tabs-list-focus-ring-space-inset",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`line` trigger box. Square corners because the selected state is the token-owned ::after bar, never a pill; the hit box is wider/taller than the pill trigger so the underline spans a real column of the rail.",
    "name": "--tabs-trigger-line-radius",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-line-padding-x",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-line-padding-y",
    "tier": "component",
    "value": "0.5rem"
  },
  {
    "description": "TABS SIZE TIERS — Ant Design's `size` (`small`/`middle`/`large`) expressed as this library's own control bands, so a tab strip and the Buttons beside it land on the same rhythm instead of on antd's 24/32/40 ladder. `md` reproduces today's trigger exactly: `--band-height-md` is the default control band and `--font-size-base` is what the `text-sm` step already resolved to.",
    "name": "--tabs-trigger-height-sm",
    "tier": "component",
    "value": "var(--band-height-sm)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-height-md",
    "tier": "component",
    "value": "var(--band-height-md)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-height-lg",
    "tier": "component",
    "value": "var(--band-height-lg)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-font-size-sm",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-font-size-md",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-font-size-lg",
    "tier": "component",
    "value": "var( --font-size-lg, calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-padding-x-sm",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-padding-x-md",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-padding-x-lg",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "TABS CARD FACE (`variant=\"card\"` / `\"editable-card\"`). The strip loses the pill container — transparent, no inset, no radius — and gains a rail its tabs sit on; each tab becomes a boxed face rounded on the leading block edge only, and the ACTIVE one drops its block-end edge so it reads as joined to the panel. `--tabs-card-background` is a role-mirror knob (docs/TOKENS.md): `initial` so the --muted default re-resolves at the CALL SITE under a scoped [data-tenant] or .dark theme instead of freezing at :root.",
    "name": "--tabs-card-list-radius",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-card-list-space-inset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-card-list-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Read via `rounded-s-[var(--tabs-card-radius)]` / `rounded-e-[var(--tabs-card-radius)]` in tabs.tsx — a Tailwind utility (`@layer utilities`) this package cannot hand a fallback to from CSS, so (same reasoning as `--button-radius` in control.css) this stays a plain :root binding rather than `initial`. The `var(--radius-md, …)` fallback is gh#888: without it, the tier's global unfreeze leaves `--radius-md` unset and this — and every card-variant Tab corner — would go to 0. The formula keeps the declaration byte-identical to before gh#888.",
    "name": "--tabs-card-radius",
    "tier": "component",
    "value": "var(--radius-md, calc(var(--radius) / var(--radius-ratio)))"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--tabs-card-rail-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--muted) at the call site",
    "name": "--tabs-card-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--tabs-card-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TABS JOINED BODY (`bodied`, gh#762). The card strip alone is half an object: antd's active face repaints the edge FACING the panel in the surface colour, which only reads as \"opened into\" when there IS a surface under it — and the package shipped no such body, so every consumer picked a box and every box was wrong (measured on 28.0.0: `<Card>` 8px gap + a second 1px border at a 9.7px radius, `<Card variant=\"borderless\">` 8px gap, no box 8px gap). `--tabs-panel-background` is a role-mirror knob (docs/TOKENS.md): `initial` so the --background default re-resolves at the CALL SITE under a scoped [data-tenant]/.dark theme. It is read BOTH by the body and by the active card face's merged edge, so the two can never disagree — a theme that retints the body retints the tab that opens into it. The radius mirrors the tab's own (`--tabs-card-radius`), because the body and the faces are two halves of one outline; the border width mirrors the rail's, for the same reason. default = var(--background) at the call site",
    "name": "--tabs-panel-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--tabs-panel-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-panel-border-width",
    "tier": "component",
    "value": "var(--tabs-card-rail-border-width, var(--stroke-hairline))"
  },
  {
    "description": "`initial`, not `var(--tabs-card-radius)` — a :root binding freezes (gh#888); default resolves at the call site. Default = var(--tabs-card-radius).",
    "name": "--tabs-panel-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-panel-space-inset",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "TAB COUNTER PILL (`TabItemProp.count`, gh#762) — the SAME counter Button and Toggle already draw, so 「未対応 12」 on a tab and on a filter chip are one thing at one size. Values mirror `--toggle-count-*` verbatim; the two tints are role-mirror knobs (`initial` + a call-site fallback) so a scoped theme re-resolves them.",
    "name": "--tabs-count-min-width",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-count-space-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-count-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-count-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-count-radius",
    "tier": "component",
    "value": "var(--radius-pill)"
  },
  {
    "description": "default = hsl(var(--muted)) at the call site",
    "name": "--tabs-count-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "…and on a CARD tab, whose own resting fill is already `--muted`, the pill would land on its own colour (measured 1.00:1 — invisible; the gh#602 failure on a third control). It takes the page surface there, exactly as `.ui-toggle-soft .ui-toggle-count` does. default = hsl(var(--background)) at the call site",
    "name": "--tabs-count-card-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted-foreground)) at the call site",
    "name": "--tabs-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--primary)) at the call site",
    "name": "--tabs-count-active-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--tabs-count-active-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--primary-foreground)) at the call site",
    "name": "--tabs-count-active-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--tabs-count-forced-outline-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TABS BAR ROW — the one inline run that holds the strip, the `editable-card` add button and the `extra` (antd `tabBarExtraContent`) slots.",
    "name": "--tabs-bar-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-extra-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "OVERFLOW MENU TRIGGER (`overflow=\"menu\"`, antd `more`). Sized off the same control band as the add button so the two affordances that flank the strip land on one rhythm; unlike the add button it draws no card face, because it is bar chrome rather than a tab.",
    "name": "--tabs-overflow-size",
    "tier": "component",
    "value": "var(--band-height-md)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--tabs-overflow-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-overflow-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-add-size",
    "tier": "component",
    "value": "var(--band-height-md)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--tabs-add-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-add-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-icon-size",
    "tier": "component",
    "value": "var(--control-icon-size)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-tab-remove-size",
    "tier": "component",
    "value": "var(--band-height-xs)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--tabs-tab-remove-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-tab-remove-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xs)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-tab-remove-space-inline-end",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Menu item hover/highlight tint — `initial` so the --accent default re-resolves at the call site under a scoped theme (a :root binding to a role var freezes at :root). Defaults = hsl(var(--accent)) fill · hsl(var(--accent-foreground)) text.",
    "name": "--menu-item-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--menu-item-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-item-hover-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Sticky offset for the pinned filter strip (Toolbar `sticky`, #197). Default 0 (chrome, rule #44); raise it so the strip parks below a fixed topbar.",
    "name": "--filter-bar-sticky-offset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Fill painted only when the filter strip is pinned. Role-mirror knob (rule #45): `initial` so --background re-resolves at the call site under a scoped [data-tenant]/.dark theme.",
    "name": "--filter-bar-sticky-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "FilterBar typed model (gh#258) — token-owned geometry so every list page gets the SAME search width, filter width, chip rhythm and section stacking without page-local CSS. All are rule-#45 knobs: a service theme retunes them once, props/className override per instance. Below 640px the strip stacks (search/filters full-width); the widths apply from the 640px breakpoint up, always clamped by min(100%, …) so a narrow container never overflows at 390px with long JA/EN/VI labels.",
    "name": "--filter-bar-search-width",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-bar-filter-width",
    "tier": "component",
    "value": "var(--filter-picker-width-md)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-bar-chip-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--filter-bar-section-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "MENU SURFACES — one row rhythm shared by DropdownMenu and Select's listbox. The row height was a literal `2rem` in the CSS and DropdownMenu had not been converted at all, so it carried the whole box as Tailwind literals on the component (#319). A service tunes the menu rhythm once here instead of once per surface.",
    "name": "--menu-item-height",
    "tier": "component",
    "value": "var(--band-height-md)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--menu-item-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-item-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-item-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-item-font-size",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "`DropdownMenuItem description` (gh#1246): the muted second line takes the shortcut's xs step, and a two-line row swaps its fixed height for this block padding.",
    "name": "--menu-item-description-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-item-description-space-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Inset rows (a checkbox/radio row without its own indicator) reserve the indicator column so labels stay aligned with their checked siblings.",
    "name": "--menu-item-inset-space-inline-start",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-indicator-size",
    "tier": "component",
    "value": "0.875rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-indicator-inset-inline-start",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-content-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-content-min-width",
    "tier": "component",
    "value": "10rem"
  },
  {
    "description": "DropdownMenu is anchored to a small trigger, so it opens narrower than a context menu.",
    "name": "--dropdown-content-min-width",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "Ceiling of the menu surface's intrinsic width (gh#1103). The surface is `width: max-content` so its width never depends on the provisional `left` it is first laid out at; this keeps a long label inside the viewport, less React Aria's default 12px container padding each side.",
    "name": "--dropdown-content-max-width",
    "tier": "component",
    "value": "calc(100vw - 1.5rem)"
  },
  {
    "description": "THE MENU SURFACE (gh#880). `.ui-dropdown-menu-content` painted `hsl(var(--popover))` with no knob, while `.ui-popover-content` — the same kind of floating panel, in the same portal — had `--popover-surface-background`. That asymmetry is the shape of defect this repo keeps paying for: the theme reaches two of the three menu surfaces and the third silently stays opaque. A DROPDOWN IS THE MOST OPAQUE MEMBER OF THE FAMILY, by the standard's own rule (docs/GLASSMORPHISM-STANDARD.md §4): it is small, it sits over arbitrary content, and a 7-line menu over a photograph is unreadable at a card's alpha. It therefore gets its OWN fill knob rather than sharing the popover's — the two are meant to be able to differ. default = hsl(var(--popover)) at the call site",
    "name": "--dropdown-content-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = none — a menu blurs nothing",
    "name": "--dropdown-content-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "MENU WIDTH LADDER (gh#396) — the measures `<DropdownMenuContent width=\"sm|md|lg\">` selects. Read ONLY when the prop is set, so an untouched menu keeps --dropdown-content-min-width above and moves by nothing. They exist because a menu wider than its trigger — a user menu, a project switcher, a notification panel — had exactly one mechanism left at the call site (`className=\"min-w-56\"`), which put the width of every menu in the app beyond a theme's reach. A regular ladder, not the three literals one app happened to write: a service that wants 22.5rem notification panels retunes --menu-content-width-lg once.",
    "name": "--menu-content-width-sm",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-content-width-md",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-content-width-lg",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "Ant Design `arrow` — the pointer at the anchored edge. Radix stamps a 10×5 svg; these two knobs override it so the pointer scales with a service theme's menu chrome. `--dropdown-arrow- background` is a role-mirror knob: `initial`, so --popover re-resolves at the CALL SITE.",
    "name": "--dropdown-arrow-width",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--dropdown-arrow-height",
    "tier": "component",
    "value": "var(--space-inline-xs)"
  },
  {
    "description": "default = var(--popover) at the call site",
    "name": "--dropdown-arrow-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-separator-space-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--menu-separator-space-inline",
    "tier": "component",
    "value": "calc(var(--space-1) * -1)"
  },
  {
    "description": "STEPS — the full (non-inline) variant. `--steps-inline-*` already covers the compact inline form; the marker, connector and text rhythm of the main variant were still literal on the component (#319), so a service could not resize the dot, retighten the vertical run, or move the horizontal connector to match its own grid.",
    "name": "--steps-dot-size",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "default = var(--stroke-xl), resolved at the call site (gh#906)",
    "name": "--steps-dot-process-ring-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--steps-marker-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-marker-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-marker-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-wait-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xs)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-title-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-title-font-size-compact",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-subtitle-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Vertical run: gap between marker and text, and the drop to the next step.",
    "name": "--steps-vertical-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-vertical-space-block-end",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-vertical-text-space-block-start",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Horizontal run: the text sits under the marker, and the connector spans the gap between two markers — inset by the marker radius on each side so it never runs under a marker.",
    "name": "--steps-horizontal-text-space-block-start",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-horizontal-text-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-connector-inset",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-connector-space-block-start",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "STEPS `navigation` (Ant Design `type=\"navigation\"`) — each step becomes a slab that points at the next one. The rail's hairline connector is switched OFF for this type, so the join is the chevron plus this gap; the slab tint is the same `--muted` / `--accent` pair every other quiet surface in the library uses, so a service retunes it once at the role.",
    "name": "--steps-nav-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-nav-space-inline",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-nav-space-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--steps-nav-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--steps-nav-separator-size",
    "tier": "component",
    "value": "var(--control-icon-size-sm)"
  },
  {
    "description": "STEPS `percent` (Ant Design) — the determinate arc around the CURRENT marker. It is a ring drawn in a padding box AROUND the existing marker, so no status face changes geometry. `--steps-progress-track-color` is a role-mirror knob (docs/TOKENS.md): `initial`, so the --muted default re-resolves at the CALL SITE under a scoped [data-tenant]/.dark theme. default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--steps-progress-ring-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--muted) at the call site",
    "name": "--steps-progress-track-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "APP SETTING PICKER — per-kind trigger widths (#319). Each picker is sized to the longest value it can show: a timezone name is far wider than a theme name. These were literal `sm:w-*` steps in a lookup table, so a service whose locale renders longer labels (a German timezone list, a Japanese density label) could not widen just the one that overflows.",
    "name": "--app-setting-picker-locale-width",
    "tier": "component",
    "value": "10rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-timezone-width",
    "tier": "component",
    "value": "14rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-date-format-width",
    "tier": "component",
    "value": "11rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-time-format-width",
    "tier": "component",
    "value": "11rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-theme-width",
    "tier": "component",
    "value": "9rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-brand-width",
    "tier": "component",
    "value": "11rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-density-width",
    "tier": "component",
    "value": "10rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-font-size-width",
    "tier": "component",
    "value": "9rem"
  },
  {
    "description": "The width the labelled trigger actually RENDERS at — the one above that `data-kind` selected, or `auto` when no per-kind width applies (below the breakpoint, or `compact`). The trigger consumes this through a single `w-*` utility, because a width declared in @layer components loses to the utilities the Select trigger emits and the eight tokens above were therefore inert (gh#819). Set a per-kind token to retune one picker; set this one to override the axis at a call site.",
    "name": "--app-setting-picker-trigger-width",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "Below this the trigger hugs its content instead of taking the per-kind width, so a picker dropped into a narrow topbar never stretches the bar (gh#165).",
    "name": "--app-setting-picker-width-breakpoint",
    "tier": "component",
    "value": "40rem"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-bar-border-width",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-bar-shadow",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--app-setting-picker-icon-rest-alpha",
    "tier": "component",
    "value": "0.7"
  },
  {
    "description": "Rule #24 for the two row-shaped surfaces in this file (gh#1146). Measured at 390px with `(pointer: coarse)`: a DropdownMenu / Select row 32px, a tab trigger 34px. Rows sit flush against each other and a horizontal tab list clips its block overflow, so neither can borrow a larger target from a pseudo-element the way an isolated control does — the ROW itself reaches the 44px tap floor, as every touch platform's menus and tab bars do. Tab sizes collapse onto the floor under a finger, exactly as the control ladder's compact/default steps already do.",
    "name": "--menu-item-height",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-height-sm",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-height-md",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Navigation primitive tokens: pagination, filters, compact pickers.",
    "name": "--tabs-trigger-height-lg",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "The box. A fixed inline size, so siblings line up in even columns and the connector bus has a predictable pitch; long names wrap inside it instead of widening one box.",
    "name": "--org-chart-node-inline-size",
    "tier": "component",
    "value": "13rem"
  },
  {
    "description": "ORG CHART — boxes joined by lines, top-down (`src/lab/org-chart.tsx`). Every length the chart paints is a knob (cardinal rule #45) and the defaults are the quiet reading (#44): a hairline connector in the border hue, a card-coloured box with the hairline edge every other surface here has. An `agent` box differs by its STROKE STYLE only (dashed), so a theme that retunes the edge colour retunes both kinds at once. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"), so a scoped `[data-tenant]` / `.dark` override reaches them instead of freezing at `:root`.",
    "name": "--org-chart-node-padding-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "ORG CHART — boxes joined by lines, top-down (`src/lab/org-chart.tsx`). Every length the chart paints is a knob (cardinal rule #45) and the defaults are the quiet reading (#44): a hairline connector in the border hue, a card-coloured box with the hairline edge every other surface here has. An `agent` box differs by its STROKE STYLE only (dashed), so a theme that retunes the edge colour retunes both kinds at once. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"), so a scoped `[data-tenant]` / `.dark` override reaches them instead of freezing at `:root`.",
    "name": "--org-chart-node-padding-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "ORG CHART — boxes joined by lines, top-down (`src/lab/org-chart.tsx`). Every length the chart paints is a knob (cardinal rule #45) and the defaults are the quiet reading (#44): a hairline connector in the border hue, a card-coloured box with the hairline edge every other surface here has. An `agent` box differs by its STROKE STYLE only (dashed), so a theme that retunes the edge colour retunes both kinds at once. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"), so a scoped `[data-tenant]` / `.dark` override reaches them instead of freezing at `:root`.",
    "name": "--org-chart-node-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "ORG CHART — boxes joined by lines, top-down (`src/lab/org-chart.tsx`). Every length the chart paints is a knob (cardinal rule #45) and the defaults are the quiet reading (#44): a hairline connector in the border hue, a card-coloured box with the hairline edge every other surface here has. An `agent` box differs by its STROKE STYLE only (dashed), so a theme that retunes the edge colour retunes both kinds at once. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"), so a scoped `[data-tenant]` / `.dark` override reaches them instead of freezing at `:root`.",
    "name": "--org-chart-node-text-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--org-chart-node-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-hairline)",
    "name": "--org-chart-node-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--border))",
    "name": "--org-chart-node-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--card))",
    "name": "--org-chart-node-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--card-foreground))",
    "name": "--org-chart-node-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted-foreground))",
    "name": "--org-chart-node-title-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ORG CHART — boxes joined by lines, top-down (`src/lab/org-chart.tsx`). Every length the chart paints is a knob (cardinal rule #45) and the defaults are the quiet reading (#44): a hairline connector in the border hue, a card-coloured box with the hairline edge every other surface here has. An `agent` box differs by its STROKE STYLE only (dashed), so a theme that retunes the edge colour retunes both kinds at once. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"), so a scoped `[data-tenant]` / `.dark` override reaches them instead of freezing at `:root`.",
    "name": "--org-chart-node-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "The `agent` variant's stroke style. A dashed edge, not a second colour — the difference must survive greyscale, and the sr-only \"AI agent\" carries it for a screen reader.",
    "name": "--org-chart-agent-border-style",
    "tier": "component",
    "value": "dashed"
  },
  {
    "description": "Spacing of the tree itself: the vertical run between a parent and its children's row, and the gutter between two siblings. The connector is drawn inside these gaps, half above the bus and half below it.",
    "name": "--org-chart-level-gap",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "ORG CHART — boxes joined by lines, top-down (`src/lab/org-chart.tsx`). Every length the chart paints is a knob (cardinal rule #45) and the defaults are the quiet reading (#44): a hairline connector in the border hue, a card-coloured box with the hairline edge every other surface here has. An `agent` box differs by its STROKE STYLE only (dashed), so a theme that retunes the edge colour retunes both kinds at once. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"), so a scoped `[data-tenant]` / `.dark` override reaches them instead of freezing at `:root`.",
    "name": "--org-chart-sibling-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "The connector. default = var(--stroke-hairline)",
    "name": "--org-chart-line-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--border))",
    "name": "--org-chart-line-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Room around the chart inside its scroll region, so an edge box's focus ring is not clipped.",
    "name": "--org-chart-padding",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Separator layout thickness; focus paint must not reserve extra space.",
    "name": "--resizable-handle-size",
    "tier": "component",
    "value": "var(--control-border-width, var(--stroke-hairline))"
  },
  {
    "description": "`thin` reproduces the old 10px rail closely on the platforms that draw a classic scrollbar; `auto` gives the full-width platform bar, which is what a touch/coarse-pointer console wants. Only `auto | thin | none` are valid — a length is not (that is the standard property's whole bargain, and the reason `--scroll-area-bar-size` could not survive as a rem).",
    "name": "--scroll-area-scrollbar-width",
    "tier": "component",
    "value": "thin"
  },
  {
    "description": "Role-mirror knobs: `initial` so the defaults re-resolve at the CALL SITE under a scoped [data-tenant] / .dark theme. Defaults = hsl(var(--border)) thumb on a transparent track.",
    "name": "--scroll-area-thumb-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "SCROLL AREA — the scrollbar, and the bottom-anchoring contract (gh#311). The hand-drawn rail knobs (--scroll-area-bar-size / -bar-padding / --scroll-area-thumb-radius) are GONE with the Radix rail they sized (v23): the browser draws the scrollbar now, and what a service can retune about it is the three standard scrollbar properties below. They live here, beside the anchoring constant, so every ScrollArea knob is in one file.",
    "name": "--scroll-area-track-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`scrollbar-gutter`: `auto` (reflow when a bar appears) | `stable` | `stable both-edges`. Reach for `stable` where content starting to overflow must not shift the layout under the reader.",
    "name": "--scroll-area-scrollbar-space",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "`scrollbar=\"always\"` geometry (gh#798). Only these two, and only for that value: the always-on bar is DRAWN by this package via `::-webkit-scrollbar`, so unlike the platform bar it has a size this package must name. The colours are NOT duplicated — the always-on rules read the same `--scroll-area-thumb-color` / `-track-color` role-mirrors as the standard ones.",
    "name": "--scroll-area-always-bar-size",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "SCROLL AREA — the scrollbar, and the bottom-anchoring contract (gh#311). The hand-drawn rail knobs (--scroll-area-bar-size / -bar-padding / --scroll-area-thumb-radius) are GONE with the Radix rail they sized (v23): the browser draws the scrollbar now, and what a service can retune about it is the three standard scrollbar properties below. They live here, beside the anchoring constant, so every ScrollArea knob is in one file.",
    "name": "--scroll-area-always-thumb-radius",
    "tier": "component",
    "value": "var(--radius-pill)"
  },
  {
    "description": "SCROLL AREA — the scrollbar, and the bottom-anchoring contract (gh#311). The hand-drawn rail knobs (--scroll-area-bar-size / -bar-padding / --scroll-area-thumb-radius) are GONE with the Radix rail they sized (v23): the browser draws the scrollbar now, and what a service can retune about it is the three standard scrollbar properties below. They live here, beside the anchoring constant, so every ScrollArea knob is in one file.",
    "name": "--scroll-area-anchor-offset",
    "tier": "component",
    "value": "3rem"
  },
  {
    "description": "track padding = the bold line width = 2px. Half the base spacing step rather than a raw length, so it rides `--scaling` with everything else.",
    "name": "--segmented-track-padding",
    "tier": "component",
    "value": "calc(var(--space-1) / 2)"
  },
  {
    "description": "track background — the recessed ground a control group sits in. default = var(--muted), resolved at the call site",
    "name": "--segmented-track-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--segmented-track-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "track radius = the base radius; item radius = one step DOWN the radius scale, not `radius − trackPadding` (the two coincide only because the source scale happens to step by 2). This scale is φ-spaced, so \"one step down\" from --radius is --radius-md (6px → 3.71px, against the source's 6 → 4); --radius-sm is two steps and reads visibly squarer. The same pair is already what TabsList (`rounded-lg`) and TabsTrigger (`rounded-md`) use — this library's other track-and-slab control. gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--segmented-track-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--segmented-item-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "item padding-inline = control padding-x − one border width.",
    "name": "--segmented-item-padding-inline",
    "tier": "component",
    "value": "calc(var(--control-padding-x) - 1px)"
  },
  {
    "description": "xs type step = the step Button xs already reads, so an xs bar and an xs Button on one row carry the same label size. One step of the existing scale, not a new constant.",
    "name": "--segmented-xs-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "xs item padding-inline = the SAME derivation as the md step (control padding-x − one border width), taken one rung down the control padding scale: 8 − 1 = 7 against 12 − 1 = 11. At 11px around a 12.47px label a three-option bar no longer reads as dense.",
    "name": "--segmented-xs-item-padding-inline",
    "tier": "component",
    "value": "calc(var(--control-padding-x-compact) - 1px)"
  },
  {
    "description": "icon gap = the small margin step / 2.",
    "name": "--segmented-item-gap",
    "tier": "component",
    "value": "calc(var(--space-3) / 2)"
  },
  {
    "description": "item ink = the label ink · hover / selected ink = the body ink. default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--segmented-item-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--foreground), resolved at the call site (gh#906)",
    "name": "--segmented-item-hover-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--foreground), resolved at the call site (gh#906)",
    "name": "--segmented-item-selected-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "item hover fill = the lighter neutral · active fill = the heavier of the pair. default = var(--accent), resolved at the call site (the freeze rule)",
    "name": "--segmented-item-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--segmented-item-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Segmented (one-of-N control) component tokens. EVERY VALUE BELOW IS A PORT OF AN ESTABLISHED SEGMENTED SPEC, NOT A CHOICE. The geometry and the role assignments come from the widely-implemented enterprise Segmented control, transcribed as ratios rather than as pixels: track padding: the bold line width → 2px track background: the page's recessed neutral item colour: the label ink · hover / selected colour: the body ink item hover fill: the lighter neutral · item active fill: the heavier neutral item selected fill: the elevated surface label height = control height − track padding × 2 → 32 − 4 = 28 label padding-inline = control padding-x − border width → 12 − 1 = 11 icon gap = the small margin step / 2 → 6 THE ROLE PORTS ARE THE ONES `Tabs` ALREADY MADE. TabsList is `bg-muted` and an active TabsTrigger is `bg-background` + `shadow-sm` — the same track-and-slab pair, so a Segmented and a default Tabs strip read as one control family in both themes rather than two near-misses. That matters more than reproducing the source dark ramp literally: that ramp's dark track is BLACK with a lighter slab on it, while this palette's dark `--muted` sits above `--background`, so a literal port would invert the pairing relative to every Tabs strip on the same page. NOT ONE OF THEM READS THE BRAND SEED. The spec's own derivation produces identical Segmented values for its default seed and for this system's `#0071bd` — the control is neutral by construction, and the only brand ink it can carry is the focus mark, which styles/focus-ring.css owns. So the ports below are ROLE references (the same neutrals this system already names), never copied hex. The disabled state is the ONE place this departs. The source recolours to a disabled ink and changes nothing else; this system disables every control with the one `--disabled-opacity` knob, and a single library-wide answer outranks a per-component one. The other thing NOT ported is the sliding thumb: it exists to animate between items, and the implementations that have one remove the `-item-selected` class while it runs, which means the selected state lives in two places at once. A static selected slab reads identically at rest and cannot desynchronise.",
    "name": "--segmented-item-active-background",
    "tier": "component",
    "value": "var(--secondary)"
  },
  {
    "description": "Segmented (one-of-N control) component tokens. EVERY VALUE BELOW IS A PORT OF AN ESTABLISHED SEGMENTED SPEC, NOT A CHOICE. The geometry and the role assignments come from the widely-implemented enterprise Segmented control, transcribed as ratios rather than as pixels: track padding: the bold line width → 2px track background: the page's recessed neutral item colour: the label ink · hover / selected colour: the body ink item hover fill: the lighter neutral · item active fill: the heavier neutral item selected fill: the elevated surface label height = control height − track padding × 2 → 32 − 4 = 28 label padding-inline = control padding-x − border width → 12 − 1 = 11 icon gap = the small margin step / 2 → 6 THE ROLE PORTS ARE THE ONES `Tabs` ALREADY MADE. TabsList is `bg-muted` and an active TabsTrigger is `bg-background` + `shadow-sm` — the same track-and-slab pair, so a Segmented and a default Tabs strip read as one control family in both themes rather than two near-misses. That matters more than reproducing the source dark ramp literally: that ramp's dark track is BLACK with a lighter slab on it, while this palette's dark `--muted` sits above `--background`, so a literal port would invert the pairing relative to every Tabs strip on the same page. NOT ONE OF THEM READS THE BRAND SEED. The spec's own derivation produces identical Segmented values for its default seed and for this system's `#0071bd` — the control is neutral by construction, and the only brand ink it can carry is the focus mark, which styles/focus-ring.css owns. So the ports below are ROLE references (the same neutrals this system already names), never copied hex. The disabled state is the ONE place this departs. The source recolours to a disabled ink and changes nothing else; this system disables every control with the one `--disabled-opacity` knob, and a single library-wide answer outranks a per-component one. The other thing NOT ported is the sliding thumb: it exists to animate between items, and the implementations that have one remove the `-item-selected` class while it runs, which means the selected state lives in two places at once. A static selected slab reads identically at rest and cannot desynchronise.",
    "name": "--segmented-item-active-background-alpha",
    "tier": "component",
    "value": "100%"
  },
  {
    "description": "selected fill = the elevated surface + a soft shadow — the selected slab reads as lifted off the recessed track, which is the whole affordance. default = var(--background), resolved at the call site",
    "name": "--segmented-item-selected-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--segmented-item-selected-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`initial` + the ramp default at the CALL SITE (gh#880 item 7). Bound to `var(--shadow-md)` here it substituted on `<html>`, so a scope that restated the elevation ramp could not move the selected slab — the same freeze the two knobs above this one were converted for in gh#848, left on the one property that carries the lift. docs/TOKEN-RESOLUTION.md §3. default = var(--shadow-md), resolved at the call site",
    "name": "--segmented-item-selected-shadow",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "A SECOND SIGNAL, because the first one is nearly invisible on a light canvas (gh#843). The lifted-slab idea is right and the tokens express it, but measured on /showcase/theme-customization the slab is `rgb(253,253,252)` on a `rgb(244,243,240)` track — **1.09:1**, against the 3:1 floor WCAG 2.2 SC 1.4.11 sets for a non-text indicator. The reporter's words were \"chọn thì đéo thấy có thay đổi gì\", and the ratio says why: selection was carried by fill and shadow alone, and both are near-zero here. Weight does not depend on the canvas at all, which is the point — a 500 label reads as chosen on white, on near-white and in dark. antd's Segmented does the same; this is not a new idea, it is the one signal this port left out. The shadow steps `sm` → `md` alongside it so the elevation is doing visible work rather than nominal work.",
    "name": "--segmented-item-selected-font-weight",
    "tier": "component",
    "value": "var(--font-weight-medium)"
  },
  {
    "description": "THE SIGNAL THAT ACTUALLY CLEARS THE FLOOR (gh#843, second pass). Weight above is a second signal; it is not a fix for the first one, because SC 1.4.11 is about the NON-TEXT indicator and a font weight is text. Measured from foundation.css: light slab rgb(253,253,252) on track rgb(244,243,240) → 1.09:1 dark slab rgb(25,24,21) on track rgb(49,47,43) → 1.33:1 Neither is fixable by moving the FILL. The slab is `--background` and the track is `--muted`; for the pair to reach 3:1 on a near-white canvas one of them has to become a mid grey (relative luminance ≈ 0.26, about #8a8a88), which either inverts the lifted-white-slab idea this control shares with TabsList/TabsTrigger, or re-seeds `--muted` for the whole system — a repaint of every recessed surface in the library to fix one control. Both are far larger than the defect. So the indicator moves to a BOUNDARY, which is what SC 1.4.11 asks for and what costs one hairline: `--input` is this palette's documented control-boundary role, already held at ≥3:1 in both themes for exactly this purpose. Measured against both of its neighbours: light vs track 3.18:1 · vs slab 3.47:1 dark vs track 3.17:1 · vs slab 4.22:1 It is painted as an INSET shadow next to the elevation shadow, so the selected item gains a ring without gaining a border box — no reflow, and `--segmented-item-padding-inline` (which already subtracts one border width) stays honest. `initial` + a call-site fallback, per docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\": a `:root` binding to `var(--input)` would freeze at the root's light value and a scoped dark region would keep the light ring. default = var(--input), resolved at the call site",
    "name": "--segmented-item-selected-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Counter pill beside the label (gh#602). Geometry matches Button/Toggle count pills; COLOUR follows `Tabs` (gh#1019): resting = `--background` / `--muted-foreground`, byte-identical to a resting `.ui-tabs-count` on a CARD tab — the Tabs rule for a pill whose host surface is `--muted`, which the Segmented track is (a `--muted` pill there is 1.00:1, shape gone). The selected segment's pill = `--primary` / `--primary-foreground`, identical to the active tab's. gh#602 had painted EVERY pill primary — four identical blobs that dropped the one thing a count pill in a one-of-N control can say, \"this is the chosen one\". The resting number is held to SC 1.4.3 (≥ 4.5:1 in both themes, measured in segmented-count-tabs-convention-1019.test.ts); it is not the selection indicator, so its fill only has to stand off the track, not reach 3:1. antd has no `count` on SegmentedItemType; this knob exists because every faceted filter in the wild needs one and nesting Badge in `label` was the only API until now.",
    "name": "--segmented-count-min-width",
    "tier": "component",
    "value": "var(--button-count-min-width)"
  },
  {
    "description": "Segmented (one-of-N control) component tokens. EVERY VALUE BELOW IS A PORT OF AN ESTABLISHED SEGMENTED SPEC, NOT A CHOICE. The geometry and the role assignments come from the widely-implemented enterprise Segmented control, transcribed as ratios rather than as pixels: track padding: the bold line width → 2px track background: the page's recessed neutral item colour: the label ink · hover / selected colour: the body ink item hover fill: the lighter neutral · item active fill: the heavier neutral item selected fill: the elevated surface label height = control height − track padding × 2 → 32 − 4 = 28 label padding-inline = control padding-x − border width → 12 − 1 = 11 icon gap = the small margin step / 2 → 6 THE ROLE PORTS ARE THE ONES `Tabs` ALREADY MADE. TabsList is `bg-muted` and an active TabsTrigger is `bg-background` + `shadow-sm` — the same track-and-slab pair, so a Segmented and a default Tabs strip read as one control family in both themes rather than two near-misses. That matters more than reproducing the source dark ramp literally: that ramp's dark track is BLACK with a lighter slab on it, while this palette's dark `--muted` sits above `--background`, so a literal port would invert the pairing relative to every Tabs strip on the same page. NOT ONE OF THEM READS THE BRAND SEED. The spec's own derivation produces identical Segmented values for its default seed and for this system's `#0071bd` — the control is neutral by construction, and the only brand ink it can carry is the focus mark, which styles/focus-ring.css owns. So the ports below are ROLE references (the same neutrals this system already names), never copied hex. The disabled state is the ONE place this departs. The source recolours to a disabled ink and changes nothing else; this system disables every control with the one `--disabled-opacity` knob, and a single library-wide answer outranks a per-component one. The other thing NOT ported is the sliding thumb: it exists to animate between items, and the implementations that have one remove the `-item-selected` class while it runs, which means the selected state lives in two places at once. A static selected slab reads identically at rest and cannot desynchronise.",
    "name": "--segmented-count-space-inline",
    "tier": "component",
    "value": "var(--button-count-space-inline)"
  },
  {
    "description": "Segmented (one-of-N control) component tokens. EVERY VALUE BELOW IS A PORT OF AN ESTABLISHED SEGMENTED SPEC, NOT A CHOICE. The geometry and the role assignments come from the widely-implemented enterprise Segmented control, transcribed as ratios rather than as pixels: track padding: the bold line width → 2px track background: the page's recessed neutral item colour: the label ink · hover / selected colour: the body ink item hover fill: the lighter neutral · item active fill: the heavier neutral item selected fill: the elevated surface label height = control height − track padding × 2 → 32 − 4 = 28 label padding-inline = control padding-x − border width → 12 − 1 = 11 icon gap = the small margin step / 2 → 6 THE ROLE PORTS ARE THE ONES `Tabs` ALREADY MADE. TabsList is `bg-muted` and an active TabsTrigger is `bg-background` + `shadow-sm` — the same track-and-slab pair, so a Segmented and a default Tabs strip read as one control family in both themes rather than two near-misses. That matters more than reproducing the source dark ramp literally: that ramp's dark track is BLACK with a lighter slab on it, while this palette's dark `--muted` sits above `--background`, so a literal port would invert the pairing relative to every Tabs strip on the same page. NOT ONE OF THEM READS THE BRAND SEED. The spec's own derivation produces identical Segmented values for its default seed and for this system's `#0071bd` — the control is neutral by construction, and the only brand ink it can carry is the focus mark, which styles/focus-ring.css owns. So the ports below are ROLE references (the same neutrals this system already names), never copied hex. The disabled state is the ONE place this departs. The source recolours to a disabled ink and changes nothing else; this system disables every control with the one `--disabled-opacity` knob, and a single library-wide answer outranks a per-component one. The other thing NOT ported is the sliding thumb: it exists to animate between items, and the implementations that have one remove the `-item-selected` class while it runs, which means the selected state lives in two places at once. A static selected slab reads identically at rest and cannot desynchronise.",
    "name": "--segmented-count-font-size",
    "tier": "component",
    "value": "var(--button-count-font-size)"
  },
  {
    "description": "Segmented (one-of-N control) component tokens. EVERY VALUE BELOW IS A PORT OF AN ESTABLISHED SEGMENTED SPEC, NOT A CHOICE. The geometry and the role assignments come from the widely-implemented enterprise Segmented control, transcribed as ratios rather than as pixels: track padding: the bold line width → 2px track background: the page's recessed neutral item colour: the label ink · hover / selected colour: the body ink item hover fill: the lighter neutral · item active fill: the heavier neutral item selected fill: the elevated surface label height = control height − track padding × 2 → 32 − 4 = 28 label padding-inline = control padding-x − border width → 12 − 1 = 11 icon gap = the small margin step / 2 → 6 THE ROLE PORTS ARE THE ONES `Tabs` ALREADY MADE. TabsList is `bg-muted` and an active TabsTrigger is `bg-background` + `shadow-sm` — the same track-and-slab pair, so a Segmented and a default Tabs strip read as one control family in both themes rather than two near-misses. That matters more than reproducing the source dark ramp literally: that ramp's dark track is BLACK with a lighter slab on it, while this palette's dark `--muted` sits above `--background`, so a literal port would invert the pairing relative to every Tabs strip on the same page. NOT ONE OF THEM READS THE BRAND SEED. The spec's own derivation produces identical Segmented values for its default seed and for this system's `#0071bd` — the control is neutral by construction, and the only brand ink it can carry is the focus mark, which styles/focus-ring.css owns. So the ports below are ROLE references (the same neutrals this system already names), never copied hex. The disabled state is the ONE place this departs. The source recolours to a disabled ink and changes nothing else; this system disables every control with the one `--disabled-opacity` knob, and a single library-wide answer outranks a per-component one. The other thing NOT ported is the sliding thumb: it exists to animate between items, and the implementations that have one remove the `-item-selected` class while it runs, which means the selected state lives in two places at once. A static selected slab reads identically at rest and cannot desynchronise.",
    "name": "--segmented-count-radius",
    "tier": "component",
    "value": "var(--radius-pill)"
  },
  {
    "description": "Segmented (one-of-N control) component tokens. EVERY VALUE BELOW IS A PORT OF AN ESTABLISHED SEGMENTED SPEC, NOT A CHOICE. The geometry and the role assignments come from the widely-implemented enterprise Segmented control, transcribed as ratios rather than as pixels: track padding: the bold line width → 2px track background: the page's recessed neutral item colour: the label ink · hover / selected colour: the body ink item hover fill: the lighter neutral · item active fill: the heavier neutral item selected fill: the elevated surface label height = control height − track padding × 2 → 32 − 4 = 28 label padding-inline = control padding-x − border width → 12 − 1 = 11 icon gap = the small margin step / 2 → 6 THE ROLE PORTS ARE THE ONES `Tabs` ALREADY MADE. TabsList is `bg-muted` and an active TabsTrigger is `bg-background` + `shadow-sm` — the same track-and-slab pair, so a Segmented and a default Tabs strip read as one control family in both themes rather than two near-misses. That matters more than reproducing the source dark ramp literally: that ramp's dark track is BLACK with a lighter slab on it, while this palette's dark `--muted` sits above `--background`, so a literal port would invert the pairing relative to every Tabs strip on the same page. NOT ONE OF THEM READS THE BRAND SEED. The spec's own derivation produces identical Segmented values for its default seed and for this system's `#0071bd` — the control is neutral by construction, and the only brand ink it can carry is the focus mark, which styles/focus-ring.css owns. So the ports below are ROLE references (the same neutrals this system already names), never copied hex. The disabled state is the ONE place this departs. The source recolours to a disabled ink and changes nothing else; this system disables every control with the one `--disabled-opacity` knob, and a single library-wide answer outranks a per-component one. The other thing NOT ported is the sliding thumb: it exists to animate between items, and the implementations that have one remove the `-item-selected` class while it runs, which means the selected state lives in two places at once. A static selected slab reads identically at rest and cannot desynchronise.",
    "name": "--segmented-count-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "default = hsl(var(--background)) at the call site",
    "name": "--segmented-count-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted-foreground)) at the call site",
    "name": "--segmented-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--primary)) at the call site",
    "name": "--segmented-count-selected-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--segmented-count-selected-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--primary-foreground)) at the call site",
    "name": "--segmented-count-selected-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-hairline) at the call site",
    "name": "--segmented-count-forced-outline-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Rule weight, both orientations and both halves of a labelled rule. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--separator-rule-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Rule colour. Role-mirror knob → declared `initial` so the --border default re-resolves at the CALL SITE under a scoped [data-tenant] / .dark theme (docs/TOKENS.md — the :root freeze rule). Documented default = hsl(var(--border)).",
    "name": "--separator-rule-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Gap between the label and each rule half. `initial` so the default re-resolves at the call site: --space-* is density-scaled and re-declared inside a `.ui-density-*` subtree, so a :root binding would freeze the gap at the :root density. Documented default = var(--space-3).",
    "name": "--separator-label-gap",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Length of the SHORT rule half when labelAlign is `start` / `end` — the label's inset from the inline edge (the Slack/Mattermost stream convention). It is a grid track on the INLINE axis, so it flips with the writing direction under dir=\"rtl\" with no extra rule. `initial` for the same density reason as the gap. Documented default = var(--space-6).",
    "name": "--separator-label-inset",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Label type ramp (#46) — steps of the modular scale, never a literal. `xs` is the quiet stream/divider voice; --separator-label-line-height keeps ja/vi descenders and tone marks intact (cf. #254); --separator-label-font-weight lets a service raise an unread watermark without touching the day divider.",
    "name": "--separator-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-label-line-height",
    "tier": "component",
    "value": "var(--line-height-normal)"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-label-font-weight",
    "tier": "component",
    "value": "var(--font-weight-medium)"
  },
  {
    "description": "Label colour. Role-mirror → `initial`; documented default = hsl(var(--muted-foreground)).",
    "name": "--separator-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Per-tone rule + label colours. `tone` re-points BOTH the rule and the label — never the rule alone — so an attention rule such as an unread watermark is not colour-only (WCAG 1.4.1) and survives forced-colors. All role-mirror → `initial`; documented defaults are the matching semantic role. `muted` deliberately mirrors the quiet default so a service can still split the two voices later without a breaking change.",
    "name": "--separator-tone-muted-rule-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-muted-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-primary-rule-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-primary-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-success-rule-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-success-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-warning-rule-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-warning-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-destructive-rule-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-destructive-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-info-rule-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Separator component tokens (gh#308) — the tokenized rule AND the LABELLED rule that a `label` interrupts: a message stream's day divider, an unread \"new messages\" watermark, an auth conjunction. Before #308 the only labelled rule in the library was the auth-scoped AuthDivider, whose rule baked `height: 1px` into shell-layout.css and whose type ramp lived on the `--auth-shell-divider-*` layer — so a service that retuned its login divider silently retuned every day divider in its chat. These knobs are the generic layer; AuthDivider now re-points them. Chrome defaults to the QUIETEST state (rule #44): one hairline, a muted xs label, no surrounding padding. A service opts IN to a louder watermark from its theme, never by forking CSS.",
    "name": "--separator-tone-info-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Viewport width at and below which `SheetContent responsive=\"auto\"` renders the mobile bottom sheet instead of the desktop side panel. Read at runtime by useSheetResponsiveMode() (a CSS @media cannot resolve a custom property), so a service moves the drawer breakpoint from ONE knob for every overlay that opts into the responsive contract — Sheet and OrgSwitcher alike. 48rem = 768px mirrors the library's canonical mobile line (useIsMobile). Accepts px/rem/em.",
    "name": "--sheet-responsive-breakpoint-width",
    "tier": "component",
    "value": "48rem"
  },
  {
    "description": "Block size cap for the responsive BOTTOM presentation only (never for a plain `side=\"bottom\"` sheet, which stays content-sized). Keeps the sheet below the viewport so the SheetBody scrolls and the page behind it stays visible/dismissable.",
    "name": "--sheet-bottom-max-height",
    "tier": "component",
    "value": "85dvh"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--responsive-grid-column-width",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-section-label-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Section label case and tracking (gh#1305, ADR C12): default sentence case, no tracking — tiny letter-spaced capitals (11px, 0.08em) are the classic \"AI dashboard\" eyebrow. A theme that wants small caps back sets both.",
    "name": "--sidebar-section-label-letter-case",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-section-label-letter-spacing",
    "tier": "component",
    "value": "normal"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-product-tenant-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-badge-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Sidebar nav count pill colours — the pill had a font-size knob and NO colour knob, so a rail that needed to tell \"unread\" from \"mentions you\" had to nest a <Badge> inside `badge` and got two pills, one inside the other. `initial` so the role defaults re-resolve at the call site under a scoped theme (a :root binding to a role var freezes at :root). Defaults = hsl(var(--secondary)) fill · hsl(var(--muted-foreground)) text.",
    "name": "--sidebar-badge-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-badge-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The EMPHASIS pair, read only by `SidebarItemProp.badgeTone=\"destructive\"` (rule #44 — a neutral row never resolves them). Defaults = hsl(var(--destructive)) fill · hsl(var(--destructive-foreground)) text, the canonical AA-checked pair.",
    "name": "--sidebar-badge-destructive-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-badge-destructive-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Focus-ring alpha on the tinted shell grounds. It was 0.45, to stop the ring reading as a SELECTED item rather than a focused one — a real concern, but 0.45 composites to ≈1.90:1 against the page, so it answered it by making the indicator non-compliant with WCAG 2.2 SC 1.4.11 — colour IS the criterion for a focus indicator, so a translucent mark fails it whatever its area. The mark is opaque and the quieting comes from the halo outside it (`--focus-ring-glow-*`), which carries no criterion, and from the mark's light weight (one `lineWidth`, inset into the row). \"Focused\" is kept distinct from \"selected\" by the halo's shape, not by weakening the mark (styles/focus-ring.css).",
    "name": "--sidebar-user-focus-ring-alpha",
    "tier": "component",
    "value": "1"
  },
  {
    "description": "Topbar glyphs. Three separate sizes, all previously baked as literals in shell-layout.css. --topbar-chip-icon-size is off the SCALE but on the pixel GRID, and those are different findings. Read the rule it styles: `display: grid; place-items: center; font-weight: 700` — it is a letter MEDALLION, not a glyph, so the half-pixel-stroke argument that made the NavigationMenu chevron snap from 14.4px to 14px does not apply here. 18px is a whole pixel sitting between --icon-size-md (16) and -lg (20); snapping it would be a visible 2px box change bought for nothing. Declared, not silently tolerated. scale-exempt: 18px letter medallion, a whole pixel between two icon steps, not a glyph",
    "name": "--topbar-chip-icon-size",
    "tier": "component",
    "value": "1.125rem"
  },
  {
    "description": "Sidebar product-switcher caret — a real glyph, previously a bare 0.875rem.",
    "name": "--sidebar-product-caret-icon-size",
    "tier": "component",
    "value": "var(--icon-size-sm)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "The caret is the eighth literal-sized icon rule in this file. The ratchet missed it because its selector says `caret` while the pattern looked for `icon|glyph` — the guard has been taught the wider vocabulary.",
    "name": "--topbar-caret-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xs)"
  },
  {
    "description": "Opaque for the same reason as --sidebar-user-focus-ring-alpha above (SC 2.4.13).",
    "name": "--topbar-icon-focus-ring-alpha",
    "tier": "component",
    "value": "1"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-user-role-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--org-switcher-meta-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-nav-sub-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-flyout-title-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-chip-icon-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--kbd-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-logo-mark-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "The initial of the brand mark, whose FILL comes from the caller (`product.color`). No token can derive this ink — the library never sees that fill — and the literal it replaces measured 3.38:1 on the default `--attention` orange in all 15 theme x seed cells (gh#884). default = white at the call site",
    "name": "--sidebar-logo-mark-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-avatar-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-user-name-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Brand-chrome gradient hooks — opt-in, invisible by default. A service paints the sidebar/topbar surface by setting these to a gradient (no-op = none).",
    "name": "--sidebar-gradient",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-gradient",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "THE SIDEBAR'S OWN SURFACE (gh#880). `.app-sidebar` painted a bare `hsl(var(--card))`, so the one piece of shell chrome that is ALWAYS on screen was the one a theme could not retint — the Topbar beside it has had `--topbar-background-alpha` since gh#831. Role-mirror knob: `initial`, with `hsl(var(--card))` resolved at the call site so a scoped theme's `--card` arrives. default = hsl(var(--card)) at the call site",
    "name": "--sidebar-surface-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Its own opacity, defaulting to the card's (gh#901).",
    "name": "--sidebar-surface-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "GLASS — `initial`, so unset there is no blur and, more importantly, no backdrop root. The sidebar is a long-lived container full of other people's content; promoting it to a containing block for fixed descendants by default would be the worst possible place to do it. default = none — the sidebar blurs nothing",
    "name": "--sidebar-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE OTHER TWO SHELL ROWS, and they are here because leaving them out is the asymmetry this change exists to remove (gh#880). `.app-topbar` and `.app-nav-rail` are grid rows of `.app-root` — the chrome that is on screen for the whole session — and each painted a bare role with no knob while the sidebar beside them got one. THEY GET NO BLUR KNOB, deliberately. `.app-topbar` is a SIBLING of `.app-main`, not a child, so whatever vivid backdrop a theme paints inside the main region is not behind the bar and there is nothing there for a `backdrop-filter` to blur — it would be a knob that exists and does nothing, which is worse than an honest gap. The blur that IS wanted on the bar belongs to the `<Topbar>` COMPONENT inside it (`--topbar-backdrop-blur-size`, gh#831), whose backdrop is the row this knob paints. A theme that wants the whole bar to float over a gradient moves the gradient to `.app-root`; that is a theme decision, not a knob. default = hsl(var(--card)) at the call site",
    "name": "--app-shell-bar-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The bar ROW's own blur. `--topbar-backdrop-blur-size` is NOT this knob: it is on the `<Topbar>` COMPONENT, which sits inside this row inset by `--app-shell-bar-inset` on each side, so blurring there leaves the row's gutters unblurred. The sidebar beside it has had this since gh#880; the row had none, which is what forced a theme onto the inner element. default = none — the bar row blurs nothing",
    "name": "--app-shell-bar-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted)) at the call site",
    "name": "--app-shell-nav-rail-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "HOW MUCH OF THE VIEWPORT IS NOT THIS APPLICATION'S — 0 unless something says otherwise, which is every ordinary page. A platform bar docked to a viewport edge sets it to the band it took, and the shell sizes itself to what is left instead of overflowing the window by that much.",
    "name": "--app-shell-viewport-inset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-shell-bar-height",
    "tier": "component",
    "value": "var(--band-height-2xl)"
  },
  {
    "description": "Inline inset and slot gap of the AppShell top bar. ONE OWNER FOR THE HORIZONTAL PAGE-INSET AXIS (gh#330). The bar sits in the SAME grid track as `.app-main`, directly above the page, so its first control and the page title are on one vertical edge — or they are supposed to be. These two knobs used to name their own values (--space-4 / --space-3) while the page named --space-page-x / --space-page-compact-x, and nothing reconciled them: measured in Chromium on /isolate/layout-app-shell the topbar's content started at x=80 while the page header's started at x=88 (1512px), and because the two sides also stepped at DIFFERENT breakpoints (shell 900px, page 720px) the error was not even constant — 8px at 1512, 12px between 720 and 900, 4px below 720. A consumer cannot correct a drift that changes with the viewport. The page gutter WINS the axis, for three reasons: it is read by seven regions (page header, toolbar, body, footer, PageContainer.Inset, the DataTable full-bleed compensation, Banner) against this knob's one element; the bar is the region that must line up with the page, not the other way round (the rail is a different track with its own inset); and moving the bar moves exactly one element in one composition, while moving --space-page-x would move every page in every consumer app. The NAMES stay — a theme that already sets `--app-shell-bar-inset` keeps working, and a bar that genuinely wants to sit tighter than its page still has its own knob. Only the DEFAULTS now point at the owner. `-compact` applies below the PAGE's 720px step (not the shell's 900px restructure), so both sides tighten on the same line — see styles/shell-layout.css.",
    "name": "--app-shell-bar-inset",
    "tier": "component",
    "value": "var(--space-page-x)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-shell-bar-inset-compact",
    "tier": "component",
    "value": "var(--space-page-compact-x)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-shell-bar-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "HOW MUCH OF THE BAR THE BRAND MAY KEEP (gh#728). A wide bar is not the problem, so the cap is `none` there; below the `sm` step the brand keeps at most a square of the row it sits in, and everything past that is cropped from the inline-end — which is the half a lockup can lose, because a lockup leads with its mark in both directions. A theme that wants the wordmark to survive on a phone raises the compact cap; a theme with a very wide lockup lowers the other. Choosing WHAT the narrow bar shows, rather than how much of it, is `AppShell logoCompact`: `viewBox` is an attribute and no stylesheet can set one.",
    "name": "--app-shell-brand-max-inline-size",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-shell-brand-compact-max-inline-size",
    "tier": "component",
    "value": "var(--app-shell-bar-height)"
  },
  {
    "description": "Docked navigation TRACK widths — the SINGLE most-retuned shell constant (rule #45). A service that designs on a different grid sets `--app-shell-sidebar-width: 15.9375rem` (255px) once instead of forking `.app-root`. THREE WIDTHS, THREE DIFFERENT QUESTIONS — and two of them used to share the word \"rail\": - `--app-shell-sidebar-width` the sidebar track, expanded. - `--app-shell-sidebar-collapsed-width` the SAME track at `<AppShell sidebarCollapsed>`. - `--app-shell-nav-rail-width` a SECOND, separate track that only exists when the `navRail` slot is filled (the Slack/Teams shape). The middle one shipped as `--app-shell-rail-width` through 19.x, which read as \"the width of the rail\" and therefore collided head-on with the real rail added in 20.0.0 — two tokens, both 4rem, both spelled \"rail\", meaning entirely different things. Renamed with NO alias: an alias would resolve to a plausible width in either reading and break silently, which is precisely the failure class this package gates against everywhere else.",
    "name": "--app-shell-sidebar-width",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-shell-sidebar-collapsed-width",
    "tier": "component",
    "value": "4rem"
  },
  {
    "description": "3.5rem, not the 4rem the collapsed sidebar uses. Two reasons, and both are why the default moved: at 4rem the rail's 32px controls sat in 16px of air on each side and read as a wide column rather than a rail; and a rail that happened to be exactly as wide as the collapsed sidebar made the two adjacent nav tracks fuse into one 8rem block the moment the sidebar collapsed. 3rem (48px) still clears the coarse-pointer 44px tap target, with 2px either side of a 44px control. It is a token precisely so a service that wants Slack's wider rail sets this one line — never a forked `.app-nav-rail`.",
    "name": "--app-shell-nav-rail-width",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "The SIZE OF A RAIL CELL, and the reason the rail can be this narrow. The controls the rail hosts carry their own band token (`OrgSwitcher`'s collapsed trigger is a square of `--org-switcher-trigger-height`), so a narrower TRACK alone does not narrow them — it clips them, because the rail clips. The rail therefore sizes its own cells, exactly as the bar sizes a `TopbarItem` by stretching it to `--app-shell-bar-height`: chrome decides how big its cells are, the cell does not decide how big the chrome is. 2.25rem (36px) on a mouse — comfortably over the 24x24 of WCAG 2.2 SC 2.5.8 — and the coarse block below lifts it back to the 44px tap floor of rule #24, together with the track.",
    "name": "--app-shell-nav-rail-item-size",
    "tier": "component",
    "value": "var(--band-height-lg)"
  },
  {
    "description": "The SAME rail turned 90°: its thickness when `navRailPosition` is a block edge (top/bottom) and the column becomes a full-measure strip. A separate token rather than one \"size\", because a width read as a height is the kind of name that survives review and then confuses every later override. A strip is THINNER than the column, and 2.75rem is where thinner stops: `--band-height-xl` is 44px, the WCAG 2.2 AA touch floor this library states as rule #24 and enforces on every consumer, and it is also exactly `--org-switcher-trigger-height`. Below it the shell's own platform bar would be the one control on the page under the floor — and with the rail's `overflow: clip`, a control taller than the strip is clipped rather than shrunk. ONE THICKNESS, TWO AXES: it resolves to the width, so the rail is the same measure whichever edge it is docked to and a service retunes both with one line. It briefly carried a `+ 1px` for the strip's own separator — needed only while the cell was exactly as tall as the track; with `--app-shell-nav-rail-item-size` smaller than the track the border has room, and two different numbers for one rail is a worse defect than the pixel it bought.",
    "name": "--app-shell-nav-rail-height",
    "tier": "component",
    "value": "var(--app-shell-nav-rail-width)"
  },
  {
    "description": "Block inset of the rail's own content — the counterpart of the sidebar's `--sidebar-nav-scroll-padding`, so the two navigation columns start their content on the same line under `topbarSpan=\"full\"`. It is deliberately NOT applied to the top edge under `topbarSpan=\"content\"`: there the rail runs to y=0 and its first row IS the shell's top row, so it takes the bar's band instead and the three columns share one centre line.",
    "name": "--app-shell-nav-rail-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Optional shell-wide CONTENT cap (gh#672). Default `none`: inside AppShell the page is FLUID and spans the whole main column at every sidebar state (antd Pro Layout `contentWidth: \"Fluid\"`). It used to be 80rem on `.ui-page-container` as a whole, which left a 168px dead strip at a 1512px viewport once the sidebar was collapsed and cut a sticky footer short. A service that wants one bounded column sets it ONCE; it caps the page HEADER, TOOLBAR and BODY (the same bands `measure` caps) and NEVER the footer band, which is page chrome — only the footer's CONTENT follows it, ending on the body's end edge (gh#682). A page-level `measure` / `variant=\"narrow\"` overrides it on that page. Never a page-local max-width.",
    "name": "--app-shell-page-max-width",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Page ground behind `.app-main` (gh#399). Declared `initial` so the CALL SITE resolves the default — `var(--app-shell-main-background, var(--surface-recessed))` — against the LIVE theme: `--surface-recessed` is re-stated by the dark arm in tokens/semantic/layout.css, and a `:root` binding here would freeze it at the light value for any SCOPED dark subtree (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). It used to bind `hsl(var(--muted) / 0.4)` directly, which inverted the page/card elevation on dark (the page composited 1.015:1 LIGHTER than the cards standing on it) — see the --surface-recessed comment for the measurement. Light is byte-identical; dark now sits behind the card at 1.089:1. A service that wants its own ground still sets this token. Default = var(--surface-recessed).",
    "name": "--app-shell-main-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-shell-mobile-nav-width",
    "tier": "component",
    "value": "22.5rem"
  },
  {
    "description": "Mobile-drawer scrim — `initial` so the shared --overlay-background default re-resolves at the CALL SITE under a scoped [data-tenant]/.dark theme (a :root binding freezes at :root). Default = var(--app-shell-mobile-nav-alpha) of the global scrim, i.e. rgb(0 0 0 / 0.16) out of the box.",
    "name": "--app-shell-mobile-nav-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Share of the global --overlay-background this drawer's scrim uses. A slide-in drawer washes the page more lightly than a modal dialog; keeping it a RATIO means a service retints the whole system with one --overlay-background and every overlay keeps its calibrated depth. A SHARE, not the resulting alpha (gh#886): the base already carries `/0.4`, so the product is 0.16. 40% of rgb(0 0 0 / 0.4) = rgb(0 0 0 / 0.16)",
    "name": "--app-shell-mobile-nav-alpha",
    "tier": "component",
    "value": "40%"
  },
  {
    "description": "Inline inset of the mobile drawer's scrollable nav body. Near-zero by design: the drawer nav (the <Sidebar> node by default) owns its own inset via --sidebar-nav-scroll-padding, so the generic sheet chrome inset must NOT stack on top of it (gh#211). Set it to var(--space-6) for a custom mobileNav node that wants the full sheet chrome inset.",
    "name": "--app-shell-mobile-nav-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Hamburger glyph in the drawer trigger. Bigger ON PURPOSE than the trigger Button's own `size=\"sm\"` icon step (--control-icon-size-sm, 0.875rem) — it is the ONLY navigation affordance on a phone, so it reads at the 1.25rem step. A flat rem, not a density-scaled alias: it must not move with the density axis, or the one tap target that opens navigation shrinks on a compact page. Consumed as a `size-[var(...)]` utility so it outranks `.ui-button--sm svg` (see the comment at the call site in app-shell.tsx).",
    "name": "--app-shell-mobile-nav-icon-size",
    "tier": "component",
    "value": "var(--icon-size-lg)"
  },
  {
    "description": "ServiceRolePanel (gh#319). `.ui-service-role-panel` shipped as a bare hook — the class was on the root but no rule existed anywhere, so the role rail's rhythm lived entirely as Tailwind literals inside the component and no theme could reach it (#45). The panel is a thin composition over MasterDetail, which still owns ALL the two-track geometry; these knobs cover only the role LIST inside the master rail. Flat rems, not `--space-*`: the literals they replace read Tailwind's own `--spacing` grid, which this package never remaps and which does not follow the density axis. Aliasing them would start scaling the rail inside a `.ui-density-*` subtree — a visual change, not a refactor. between role rows (was `gap-1`)",
    "name": "--service-role-panel-list-gap",
    "tier": "component",
    "value": "0.25rem"
  },
  {
    "description": "select button ↔ delete button (was `gap-1`)",
    "name": "--service-role-panel-row-gap",
    "tier": "component",
    "value": "0.25rem"
  },
  {
    "description": "role name ↔ lock Badge (was `gap-1.5`)",
    "name": "--service-role-panel-item-title-gap",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "The role row is a MULTI-LINE button (name over a description/member-count line), so it opts out of the control height grid (`h-auto`) and sets its own block padding — that is what the `py-2` literal was doing. It needs the raised `.ui-service-role-panel` ancestor specificity (0,2,0) to beat `.ui-button--md { padding-block: var(--button-space-block) }` (0,1,0): layout.css is imported BEFORE control.css and both are `@layer components`, so an equal (0,1,0) rule here would silently lose.",
    "name": "--service-role-panel-item-padding-block",
    "tier": "component",
    "value": "0.5rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-brand-mark-size",
    "tier": "component",
    "value": "1.375rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-nav-item-height",
    "tier": "component",
    "value": "var(--band-height-md)"
  },
  {
    "description": "ON the type scale (gh#329). This was `0.8125rem` — 13px, which is not a step: the golden scale runs …/ratio² ≈ 11.1 · /ratio ≈ 12.5 · base 14…, so 13 sat BETWEEN two steps and every nav row in the rail read off the system's type rhythm. It had no mechanical anchor either — unlike the auth field label below, which is pinned to an artboard y-coordinate and keeps its literal with a declared `scale-exempt` — only the checked-in hi-fi source's number. GEOMETRY MOVES, by 0.53px: 13px → --font-size-xs (≈12.47px), the step the sub-row (--sidebar-nav-sub-font-size) and the flyout title already take. Nothing reflows — the row is a fixed 2rem with `align-items: center`, and 1.5 × 12.47 = 18.7px sits inside it with the same headroom 19.5px had. What is gained is that a service overriding --font-size-base now moves the rail's labels with the rest of its type, instead of leaving one constant behind.",
    "name": "--sidebar-nav-item-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Line box of the nav LABEL, not the row (gh#254): `.sb-label` clips, so its line box is its clip box, and the row's `line-height: 1` shears descenders and Vietnamese tone marks. Keep >= 1.2.",
    "name": "--sidebar-nav-item-line-height",
    "tier": "component",
    "value": "1.5"
  },
  {
    "description": "Same gh#254 trap, two more clipping boxes. `.ui-auth-account-email` and the truncating last child of `.ui-topbar-start` both clip (`overflow: hidden`/`clip` + `text-overflow: ellipsis`), so their line box IS their clip box — inheriting a tight value shears descenders and Vietnamese tone marks exactly as the sidebar label did. Keep >= 1.2.",
    "name": "--auth-account-summary-email-line-height",
    "tier": "component",
    "value": "1.5"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-start-truncate-line-height",
    "tier": "component",
    "value": "1.5"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-nav-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-nav-item-gap",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-nav-item-padding-x",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-nav-gap",
    "tier": "component",
    "value": "2px"
  },
  {
    "description": "`initial`, not the calc() literal — a :root binding to --radius freezes there too (gh#888); default resolves at the call site. Default = calc(var(--radius) - 1px).",
    "name": "--sidebar-nav-item-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-nav-scroll-padding",
    "tier": "component",
    "value": "var(--space-3) var(--space-2)"
  },
  {
    "description": "Sidebar `action` (gh#1185): the inline inset matches the nav's, so the button's edges line up with the rows; the block end is 0 because the nav's own top padding supplies the gap below.",
    "name": "--sidebar-action-padding",
    "tier": "component",
    "value": "var(--space-3) var(--space-2) 0"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-section-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-section-label-padding-x",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-section-label-padding-bottom",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The trigger's PREFERRED width, consumed as a flex BASIS — deliberately not a minimum. `.tb-search` is `width: 100%`, written for the `center` slot (flex: 1 1 0); in `start` (flex: 0 1 auto) that collapses to content width, so the trigger came out at 186px, narrower than the placeholder it holds. A hard `min-inline-size` fixed that and broke something worse: the bar's shrink contract. Measured at 1024 with a long account name, an unshrinkable trigger pushed the start cluster into the end cluster — the collision that contract exists to prevent. As a BASIS it holds this width where there is room and yields where there is not.",
    "name": "--topbar-search-width",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-search-max-width",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Standalone <Topbar> geometry (rule #45). Topbar is a pure slot bar, so its box is intentionally QUIET by default: `auto` height and no inline inset, i.e. exactly what it did before these knobs existed — inside AppShell the `.app-topbar` grid row still owns the height. A service that places Topbar directly on a page sets `--topbar-height: 3.5rem` / `--topbar-inset: var(--space-4)` once instead of writing an app-local class. `--topbar-gap` is the gap BETWEEN the start/center/end clusters and INSIDE each of them, so one knob re-rhythms the whole bar.",
    "name": "--topbar-height",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-inset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Shared-device identity gets a bounded share, not the primary controls' width.",
    "name": "--topbar-identity-max-inline-size",
    "tier": "component",
    "value": "40%"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-identity-min-text-inline-size",
    "tier": "component",
    "value": "3ch"
  },
  {
    "description": "THE GLASS BAR (gh#831) — the same two declarations two unrelated website showcases each hand-wrote on their own sticky header: a translucent page fill plus a backdrop blur. Both knobs are `initial`, i.e. QUIET by default in exactly the sense the paragraph above describes: a guaranteed-invalid value makes the whole declaration at the call site invalid-at-computed-value time, so `background-color` falls back to its own initial `transparent` and `backdrop-filter` to `none`. The shipped bar therefore paints nothing, creates no backdrop root, and is byte-identical to the pure slot bar it was. A service opts in with `--topbar-background-alpha: 85%` / `--topbar-backdrop-blur-size: 10px`. The TINT is NOT a knob: `.ui-topbar` reads `--background` directly at the call site, so a dark or tenant-scoped subtree re-tints the glass instead of inheriting :root's answer (docs/TOKENS.md · the `:root` freeze rule). Precedent for the blur name: --app-launcher-launchpad-backdrop-blur-size. default = none — the bar paints no fill",
    "name": "--topbar-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = none — the bar blurs nothing",
    "name": "--topbar-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "⚠ THIS KNOB DELETES CONTENT AT 1100px AND BELOW — read before you ship a center slot. At compact desktop/tablet widths the docked sidebar leaves too little inline room for three intrinsically-sized clusters, so the package hides the optional center slot before it can cover the breadcrumb/title or end utilities (gh#244). The default is `none`, which means a global search trigger placed in `center` is INVISIBLE from 1100px down — including on every phone — unless the consumer opts back in. That default arrived in 18.6.0 and removed the slot for consumers who never changed a line of their own code (gh#12); it stays because the overlap it prevents is a real defect and flipping a shipped default twice is worse than documenting it once, but it is a DECISION, not an accident: :root { --topbar-center-compact-display: flex; } ← restore the slot at every width Opt back in only once the center content has a compact presentation of its own (an icon-only search trigger, a collapsing field). A page-local media query is the anti-pattern this knob replaces.",
    "name": "--topbar-center-compact-display",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "TopbarSearch (ADR C02): the inline field's TEXT AREA never shrinks below this — measured after the icon and clear/shortcut padding, in the field's own font. Below its `collapseBelow` step the field folds to a search cell instead of shrinking. 8ch is a repo-chosen policy, not a standard.",
    "name": "--topbar-search-min-text-inline-size",
    "tier": "component",
    "value": "8ch"
  },
  {
    "description": "The inline field's preferred width from the step up; it shrinks toward the floor above.",
    "name": "--topbar-search-inline-size",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "TOPBAR BAR ITEM — the shape of an interactive cell IN the bar, as opposed to a control dropped into it. The bar's own chrome (Fluent's command bar, SLDS's global header, Atlassian's navigation, and the right-hand action slot of enterprise pro-layouts generally) draws a trigger as a full-height cell whose hover is the bar's surface; a `Button` in the same slot draws a --control-height pill with its own hover fill and its own ring, floating inside a taller strip. NO HEIGHT KNOB, DELIBERATELY. The cell's height IS the bar's, whatever the bar's is — `--app-shell-bar-height` inside AppShell, `--topbar-height` for a standalone Topbar, the coarse-pointer override on a touch device. A knob here would be a second answer that goes stale the moment either of those moves.",
    "name": "--topbar-item-padding-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "THE CELL'S PHONE-WIDTH INSET (godx-jp/id#639). A second value rather than a media query on the first, for the same reason `--app-shell-bar-inset-compact` is a second value: the compact number is its own design decision, and a theme has to be able to retune the two independently. Measured at 320px on a bar carrying the shipped shape (drawer trigger · logo · search trigger · four end cells): the cells alone spent 120px of a 320px viewport on padding, the bar overflowed by 44px, `.ui-topbar-start` collapsed to 0 and the search trigger was left painting 8px of itself from under the theme cell — a target axe scores at 8×28. At --space-2 the same bar fits with every cell whole.",
    "name": "--topbar-item-padding-inline-compact",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-min-width",
    "tier": "component",
    "value": "var(--control-height)"
  },
  {
    "description": "Square by default: a cell that meets both bar edges has no corner to round. A service that wants the softer read sets this to var(--radius).",
    "name": "--topbar-item-radius",
    "tier": "component",
    "value": "var(--radius-sharp)"
  },
  {
    "description": "default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--topbar-item-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The bar's own hover surface — the same pair `.tb-icon-btn` already uses for the shell's built-in bar chrome, so a consumer-supplied cell and the shell's own read identically. default = var(--accent), resolved at the call site (the freeze rule)",
    "name": "--topbar-item-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--topbar-item-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--accent-foreground), resolved at the call site",
    "name": "--topbar-item-hover-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-active-background",
    "tier": "component",
    "value": "var(--secondary)"
  },
  {
    "description": "How far a one-digit pill's top edge (block) and end edge (inline) sit OUTSIDE the glyph's. Fractions of the pill, not a flat length (gh#1341 — Material 3 badges / Apple HIG): half a pill inline centres it on the glyph's corner, three quarters block leaves a quarter of it on the glyph, so at most a quarter of the glyph is covered; a longer count stays inside the cell and grows back across the glyph, still covering at most a quarter of it. They used to be a flat 4px, which left a 16px pill covering 56% of a 16px bell. Declared `initial` with the default resolved at the call site, so a scoped --topbar-item-badge-size still moves them (the freeze rule). The ring is the surface colour drawn round the pill so it reads cut out of the glyph; role-mirror knob, default = hsl(var(--card)) (the bar) at the call site, and the nav rail sets it to its own surface. default = calc(var(--topbar-item-badge-size) * 3 / 4)",
    "name": "--topbar-item-badge-offset-block",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = calc(var(--topbar-item-badge-size) / 2)",
    "name": "--topbar-item-badge-offset-inline",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-size",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-ring-width",
    "tier": "component",
    "value": "var(--stroke-md)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-ring-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-padding-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-destructive-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--topbar-item-badge-destructive-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The mark is hosted INSIDE the cell. A full-bleed cell has no room outside itself — the bar family clips both axes (`overflow: clip` + `--focus-ring-clip-margin`) precisely because an outset ring on a flush control gets shaved — and an inset mark is also the lighter read, the same reasoning `a.ui-list-row` / `.sb-nav-item` already record in styles/focus-ring.css. The offset TRACKS the mark's own width, so the two cannot drift apart, and it multiplies by the `--focus-outline` switch through that width: switch off → width 0 → offset 0. NO GEOMETRY IS AUTHORED HERE; the cell only says where the mark sits.",
    "name": "--topbar-item-focus-ring-offset",
    "tier": "component",
    "value": "calc(-1 * var(--focus-ring-width))"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--org-switcher-trigger-height",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--org-switcher-trigger-padding-x",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "1.75rem was the literal; --control-height-sm IS 1.75rem and is the tier this mark belongs to, so a service that re-tiers its controls moves the mark with them instead of leaving it behind.",
    "name": "--org-switcher-avatar-size",
    "tier": "component",
    "value": "var(--control-height-sm)"
  },
  {
    "description": "The compact-picker inset, shared by the sheet heading and the list — see .ui-org-switcher-sheet.",
    "name": "--org-switcher-sheet-inset",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Where a row's LABEL starts — the same on every surface, so it lines up with the heading.",
    "name": "--org-switcher-list-inset",
    "tier": "component",
    "value": "var(--org-switcher-sheet-inset)"
  },
  {
    "description": "What the SURROUNDING SURFACE insets the list by, which a row cancels so its fill and its rule reach both edges. Zero by default: the popover publishes --popover-space-inset: 0, so there is nothing to cancel there, and cancelling anyway drags the row outside the panel and puts its text on the border. The sheet, which does inset its body, overrides this.",
    "name": "--org-switcher-list-offset",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "The keyboard legend under a modal picker — see `.ui-org-switcher-legend`.",
    "name": "--org-switcher-legend-space-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--org-switcher-legend-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--org-switcher-hint-space-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The dialog surface's measure. Wider than --org-switcher-menu-width because the whole reason to reach for the dialog is that a row carries more than a name; narrower than the generic --dialog-width-default because it is still a list of choices, not a form.",
    "name": "--org-switcher-dialog-width",
    "tier": "component",
    "value": "26rem"
  },
  {
    "description": "Breathing room above and below the search field. The INLINE side is deliberately not here: it depends on --org-switcher-list-offset, which each surface sets on itself, and a composite declared at `:root` substitutes its vars AT `:root` — it would bake in the default 0 and never see the dialog's or the sheet's value. That is the same trap --dialog-space-inset set, and it caught this rule too on the first attempt, so the inline half is computed in the rule.",
    "name": "--org-switcher-search-space-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--org-switcher-menu-width",
    "tier": "component",
    "value": "16rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--org-switcher-sheet-max-height",
    "tier": "component",
    "value": "75dvh"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--org-switcher-state-min-height",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "APP LAUNCHER — the nine-dot platform app grid in the topbar. NO TRIGGER GEOMETRY KNOB, deliberately, for exactly the reason `--topbar-item-*` declares no height: the trigger IS a `TopbarItem`, so the bar's own height and the bar's own hover surface are already its answer, and a second answer here would go stale the moment either moves. NO COLUMN-COUNT TOKEN EITHER, and that one is a GAP, not a choice: the component-token name vocabulary (scripts/check-token-tiers.mjs) has words for every length and colour and none for a count, so `--app-launcher-columns` cannot be spelled legally here. It is declared on `.ui-app-launcher-panel` in styles/shell-layout.css instead, which keeps it themeable but out of this tier. Give the vocabulary a `count` word and it moves here with the rest.",
    "name": "--app-launcher-panel-width",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-panel-max-height",
    "tier": "component",
    "value": "26rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-panel-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-sheet-max-height",
    "tier": "component",
    "value": "75dvh"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-grid-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-tile-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-tile-padding",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "The tap floor (rule #24, WCAG 2.2 AA 2.5.8) — a tile is a link on a phone before it is a tile on a desktop, and the comfortable control tier IS that floor.",
    "name": "--app-launcher-tile-min-height",
    "tier": "component",
    "value": "var(--control-height-comfortable)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--app-launcher-tile-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--foreground), resolved at the call site (gh#906)",
    "name": "--app-launcher-tile-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--accent), resolved at the call site (the freeze rule)",
    "name": "--app-launcher-tile-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site (gh#901)",
    "name": "--app-launcher-tile-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--accent-foreground), resolved at the call site",
    "name": "--app-launcher-tile-hover-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The app you are already in. `initial` so the role default re-resolves at the call site under a scoped theme, the same reason `--sidebar-item-active-*` does. Default = hsl(var(--secondary)).",
    "name": "--app-launcher-tile-current-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-mark-size",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--app-launcher-mark-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-mark-background",
    "tier": "component",
    "value": "var(--secondary)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-mark-foreground",
    "tier": "component",
    "value": "var(--secondary-foreground)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-mark-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-name-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-group-label-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--app-launcher-group-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-state-min-height",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "The secondary-link row under the grid (gh#1172): hairline above, small type, inline gap.",
    "name": "--app-launcher-footer-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-footer-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-footer-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Role-mirror knob: `initial` so a scoped theme's --background re-resolves at the call site (docs/TOKENS.md). Default = a veil of the theme's OWN background at the alpha below.",
    "name": "--app-launcher-launchpad-backdrop-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "16px — gh#837",
    "name": "--app-launcher-launchpad-backdrop-blur-size",
    "tier": "component",
    "value": "var(--blur-lg)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-backdrop-alpha",
    "tier": "component",
    "value": "55%"
  },
  {
    "description": "THE INGREDIENT THAT MAKES IT GLASS RATHER THAN FOG. Blur alone averages a page towards its mean, and the mean of any real screen is a mid grey — 28px of it turned a dashboard into a featureless haze with the tiles floating in nothing. Pushing chroma back up after the blur is what a physical frosted pane does: it scatters direction, not colour.",
    "name": "--app-launcher-launchpad-backdrop-color-saturate",
    "tier": "component",
    "value": "180%"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-space-inset",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "THE PART OF THE VIEWPORT THE HOST HAS ALREADY SPOKEN FOR — 0 by default, because a page that owns its whole viewport has nothing to declare. A host with fixed chrome of its own (a docked platform bar, a persistent player) sets it to a padding box, and the scrim insets by that much so neither the grid nor the dismiss lands underneath. Measured without it, with a 40px rail on the inline-start edge: the first tile and the title both began at x=32 and ran 8px under the bar. A length or a 2/3/4-value box, exactly like `padding`.",
    "name": "--app-launcher-launchpad-space-safe-area",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-panel-max-width",
    "tier": "component",
    "value": "60rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-panel-gap",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-grid-gap",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-tile-inline-size",
    "tier": "component",
    "value": "7.5rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-tile-padding",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--app-launcher-launchpad-tile-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-tile-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-tile-hover-background",
    "tier": "component",
    "value": "color-mix( in srgb, hsl(var(--foreground)) 10%, transparent )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-mark-size",
    "tier": "component",
    "value": "4rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--app-launcher-launchpad-mark-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The glass itself: a wash of the surface colour, not a colour of its own, so it inherits the theme and stays legible on a light page and a dark one.",
    "name": "--app-launcher-launchpad-mark-background",
    "tier": "component",
    "value": "color-mix(in srgb, hsl(var(--card)) 78%, transparent)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-mark-border-color",
    "tier": "component",
    "value": "color-mix( in srgb, hsl(var(--foreground)) 14%, transparent )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-mark-font-size",
    "tier": "component",
    "value": "var( --font-size-lg, calc(var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-mark-shadow",
    "tier": "component",
    "value": "var(--shadow-lg)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-name-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-title-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-title-letter-spacing",
    "tier": "component",
    "value": "0.08em"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-launcher-launchpad-close-space-padding",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "THE HOVER FILL, the pair to the active one below it (gh#909). `initial`, with `hsl(var(--accent))` resolved at the call site in shell-layout.css, so an unset knob paints exactly what shipped before and a scoped `--accent` re-tint still reaches it. It exists because a dark rail on a light app could theme every other role of the sidebar — surface, item ink, icon states, the active pair — and then hovered to the GLOBAL light `--accent`.",
    "name": "--sidebar-item-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--sidebar-item-active-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The open row's LABEL, at BOTH nav depths — one name since gh#651 (level 2 used to spell it `--sidebar-item-active-color`). Default = the primary ACTIVE tier, derived at the call site from the live `--primary` (gh#678). It was `--primary` itself, which clears AA on the tint only for our own seed: 4.25:1 for `204 100% 37%`, 4.00:1 for `173 80% 28%`, 4.15:1 for a dark `262 83% 70%`. The active tier steps AWAY from the ground, and measured over every seed that is legible as text on the ground at all it never lands under 4.5:1 (sidebar-active-contrast.test.ts).",
    "name": "--sidebar-item-active-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The level-2 dot marker (`.sb-nav-item--sub[data-active=\"true\"]::before`) — its own knob because it is a different PART, not a second name for the label. Default = hsl(var(--primary)).",
    "name": "--sidebar-item-active-tint",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE TINT STRENGTH, AND IT HAS A CEILING — rule #45, and the reason this is a knob at all. The fill is the brand at this alpha over whatever the nav sits on, so raising it walks the fill TOWARDS the label that rides on it and contrast falls monotonically. Measured on the package seed (GoDX violet #7a00ff light / #dcbcff dark, identity v2.3), with the label as the primary ACTIVE tier since gh#678 (#5400b0 light / #cd9fff dark), against the composited fill: alpha light on --card dark on --card dark on --background 0.12 8.26:1 5.89:1 6.51:1 ← shipped 0.16 7.65:1 5.32:1 5.88:1 ← the cap below 0.22 4.55:1 ← last step still AA, dark card 0.23 4.43:1 ← under SC 1.4.3 16% is a CAP WITH HEADROOM on our seed, not the cliff edge — and it is a cap on OUR seed only: over a dense grid of consumer seeds a handful of legible dark-theme seeds dip under 4.5:1 on `--card` at 16% (worst 4.27:1), while at the shipped 12% none does. A service raising the tint on its own seed owns that measurement. `sidebar-active-contrast.test.ts` fails if this rises past the cap, and names the consumer-seed exception rather than hiding it.",
    "name": "--sidebar-item-active-background-alpha",
    "tier": "component",
    "value": "12%"
  },
  {
    "description": "AuthShell — centred auth/login page shell. Comfortable control density (44px, WCAG touch floor) + a larger auth heading, scoped to the shell; a service re-tunes the auth card width, insets and heading size without forking.",
    "name": "--auth-shell-control-height",
    "tier": "component",
    "value": "var(--control-height-comfortable)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-heading-size",
    "tier": "component",
    "value": "var( --font-size-2xl, calc( var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio) ) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-card-max-width",
    "tier": "component",
    "value": "24rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-bar-padding",
    "tier": "component",
    "value": "var(--space-5) var(--space-6)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-main-padding",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-footer-padding",
    "tier": "component",
    "value": "var(--space-3) var(--space-6) var(--space-4)"
  },
  {
    "description": "Gap between the items of the brand bar: brand to a wrapped `actions` row, and between the page-level controls inside that row (locale · theme · help).",
    "name": "--auth-shell-bar-gap",
    "tier": "component",
    "value": "var(--space-inline-sm)"
  },
  {
    "description": "Content-slot measure for `measure=\"wide\"` — the SPLIT login (brand panel beside the auth card). Same width as the widest CenteredShell tier, so a product's login and its signed-in pages read at one page measure. Only `measure=\"wide\"` reads it; the default 24rem card is untouched.",
    "name": "--auth-shell-wide-card-max-width",
    "tier": "component",
    "value": "64rem"
  },
  {
    "description": "Canonical DXS auth preset. These are public theme knobs: consumers select the preset once on AuthShell and may retune the product theme here rather than overriding individual fields.",
    "name": "--auth-shell-canonical-control-height",
    "tier": "component",
    "value": "var(--band-height-lg)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-canonical-card-max-width",
    "tier": "component",
    "value": "22.5rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-canonical-heading-size",
    "tier": "component",
    "value": "var(--font-size-base)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-canonical-main-padding",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-canonical-main-padding-mobile",
    "tier": "component",
    "value": "0.9375rem"
  },
  {
    "description": "INLINE (start/end) inset of the compact auth card — the column the title, fields and actions align to. Independent of the block axis below (gh#232).",
    "name": "--auth-shell-compact-card-inset",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "BLOCK (top/bottom) padding of the compact auth card — the knob that tunes canonical Login card HEIGHT without narrowing the column. Bound to the card's --card-space-shell-y, so it really reaches CardContent's block edges (before gh#232 it was wired only to --card-space-body-y and the rendered body kept the inset on both block edges — the documented token did nothing). Declared `initial` so the default mirrors the LIVE --auth-shell-compact-card-inset resolved at the CALL SITE: the canonical card renders exactly as before (24px block = 24px inline), and a service that re-tunes the inset inside a scoped `[data-tenant]` still drags the block default with it (a :root binding would freeze at the :root inset — docs/TOKENS.md). default = var(--auth-shell-compact-card-inset)",
    "name": "--auth-shell-card-padding-block-compact",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Header↔body gap inside the compact auth card (the breathing room under the title before the first field). Its own knob since gh#232 — it used to ride on --auth-shell-card-padding-block-compact, which conflated the section gap with the card's block padding and made the block knob un-tunable. Default is the pre-gh#232 12px rhythm.",
    "name": "--auth-shell-card-body-gap-compact",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "IN-SLOT stack gap of the compact auth card (title ↕ description inside the header).",
    "name": "--auth-shell-card-gap-compact",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Main-axis alignment of the auth column. Default `center` = today's vertically-centred card; a flow whose intro + card + footnote stack is tall opts into `start` via this knob.",
    "name": "--auth-shell-main-align",
    "tier": "component",
    "value": "center"
  },
  {
    "description": "Gap between the direct sections of the auth column (intro · card · remember row). Default 0 (quiet, rule #44) so an existing single-card consumer is untouched; presets opt in.",
    "name": "--auth-shell-card-stack-gap",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Login preset (gh#237) — canonical SCR-001 anchors at 1440x900, 1024x900 and 390x844. The 112px identity slot is deliberately taller than a two-line real requester. Identity content aligns to the slot end, so missing/one-line/two-line requester data changes only the empty space above it, never the card or footer position. The flow starts at y=231 desktop and y=221 mobile: 231/221 + 112 + 20 gap = card y=363/353. Literal artboard lengths belong here, not in a consumer selector, and do not drift with --scaling.",
    "name": "--auth-shell-login-card-max-width",
    "tier": "component",
    "value": "22.5rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-login-flow-offset-block",
    "tier": "component",
    "value": "14.4375rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-login-flow-offset-block-mobile",
    "tier": "component",
    "value": "13.8125rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-login-main-padding-inline",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-login-main-padding-inline-mobile",
    "tier": "component",
    "value": "0.9375rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-login-main-padding-block-end",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-login-identity-slot-block-size",
    "tier": "component",
    "value": "7rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-login-card-stack-gap",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Canonical SCR-001 block inset is a FLAT 24px — the same measure as the inline inset. The card draws its own 1px border and a border-box rect already contains it, so the former `+ 2 x --control-border-width` double-counted the border and pushed the passkey CTA to y=390 instead of the canonical y=388 (gh#263).",
    "name": "--auth-shell-login-card-padding-block-compact",
    "tier": "component",
    "value": "var(--auth-shell-compact-card-inset)"
  },
  {
    "description": "Device-authorization preset — 380px card measure, 15px block · 5px inline mobile gutter (at a 390px viewport the card is x=5px, width=380px).",
    "name": "--auth-shell-device-card-max-width",
    "tier": "component",
    "value": "23.75rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-device-main-padding",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-device-main-padding-mobile",
    "tier": "component",
    "value": "0.9375rem 0.3125rem"
  },
  {
    "description": "CODE FIELD measure — the preset owns it (gh#12). A device grant is the one canonical flow whose PRIMARY control is the code field, so leaving it on the generic square --otp-slot-size made the preset own the page but not its own subject: two 4-slot `appearance=\"grouped\"` boxes rendered 146x38 (4 x the canonical 36px control tier + the 1px group border) against a 112x54 artboard. These are the per-slot boxes that ADD UP to that artboard group: inline 27.5px x 4 + 2 x 1px group border = 112px block 52px + 2 x 1px group border = 54px Literal artboard lengths, like every other preset measure here — they must not drift with --scaling. A service that groups its code differently overrides --otp-slot-inline-size / --otp-slot-block-size on its own field; the generic square knob is untouched everywhere else.",
    "name": "--auth-shell-device-otp-slot-inline-size",
    "tier": "component",
    "value": "1.71875rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-device-otp-slot-block-size",
    "tier": "component",
    "value": "3.25rem"
  },
  {
    "description": "Context-selection preset — 25rem card measure on desktop/tablet, edge-to-edge on mobile (0 inline gutter) with a 16px rhythm between the intro, the card and the remember row.",
    "name": "--auth-shell-context-card-max-width",
    "tier": "component",
    "value": "25rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-context-main-padding",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-context-main-padding-mobile",
    "tier": "component",
    "value": "var(--space-6) 0"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-context-card-stack-gap",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Account-recovery preset (gh#233) — the SCR-008 measure shared by the password-recovery panel (request · sent · new-password · expired) and the sign-in MFA challenge panel (OTP · recovery-code · passkey-failure). Both canonical desktop panels measure w=432 at 1440, so ONE preset owns them; the 360px canonical Login measure is untouched. The mobile gutter is a DECIDED contract, not a traced artboard: the supplied 390 reference is a desktop 2x2 composite that crops horizontally and cannot be measured. 15px inline at 390 ⇒ the panel is x=15, width=360 — the same page rhythm as the canonical Login flow, so a user moving from Login to Recovery on a phone never sees the surface jump.",
    "name": "--auth-shell-recovery-card-max-width",
    "tier": "component",
    "value": "27rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-recovery-main-padding",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-recovery-main-padding-mobile",
    "tier": "component",
    "value": "0.9375rem"
  },
  {
    "description": "Registration preset (gh#256) — the canonical sign-up measure. Two things make it structurally different from every preset above, and both are the reason it could not be expressed by re-using `login`: 1. LONG-FORM SCROLLING. A registration card is the tallest surface in the hosted-identity set (name · email · password · confirm · strength meter · consent · submit · provider row), and a vertically CENTRED tall card clips its own top on a short viewport — the top overflows above the scroll origin and becomes unreachable. So the column is start-aligned and the block-start inset becomes ordinary page padding the user can scroll past. 2. FOOTER CLEARANCE. The legal/consent footer must never be flush against the submit button at the end of a long scroll, so the block-end inset is a knob of its own rather than mirroring the block-start one. The 360px form measure and the 15px mobile inline gutter match the canonical Login flow exactly (22.5rem card, x=15 at 390 ⇒ width=360), so a user moving sign-in → sign-up on a phone never sees the surface jump.",
    "name": "--auth-shell-registration-card-max-width",
    "tier": "component",
    "value": "22.5rem"
  },
  {
    "description": "Block-start PAGE GUTTER — the floor the column keeps against the viewport edge once the auto margins in shell-layout.css have placed it. It is deliberately NOT the artboard offset any more. It used to be 9.5rem / 8.875rem, derived from the canonical SCR-002 anchor (card y=284 at 1440x900 and y=274 at 390x844, each the offset plus the 112px identity slot plus the 20px stack gap). Held as unconditional padding, that constant manufactured a scrollbar out of nothing: at 1440x900 the column measured 152px of EMPTY SPACE + 793px of content + 48px, i.e. 993px in a 900px viewport, so the page scrolled 93px and the scrolled region was blank. A sign-up form whose first field sits below the fold because of decoration is a worse failure than a lost artboard anchor, so the anchor yields. Both values are still public knobs: a product that wants the literal artboard back sets this to 9.5rem and accepts the overflow on a short viewport.",
    "name": "--auth-shell-registration-main-padding-block-start",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-registration-main-padding-block-start-mobile",
    "tier": "component",
    "value": "0.9375rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-registration-main-padding-inline",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-registration-main-padding-inline-mobile",
    "tier": "component",
    "value": "0.9375rem"
  },
  {
    "description": "Footer clearance — the gap the legal footer keeps below the end of a long form.",
    "name": "--auth-shell-registration-main-padding-block-end",
    "tier": "component",
    "value": "3rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-registration-main-padding-block-end-mobile",
    "tier": "component",
    "value": "2rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-registration-card-stack-gap",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Fixed identity track, the same 112px `login` proved (gh#237). Without it the card anchor moves with the title/requester line count, so the canonical y above would hold for exactly one copy length and drift for every other. The slot absorbs absent / one-line / two-line identity content instead.",
    "name": "--auth-shell-registration-identity-slot-block-size",
    "tier": "component",
    "value": "7rem"
  },
  {
    "description": "Labelled auth divider geometry. The canonical SCR-001 divider row is 19px tall at an 11px label (the artboard label inherits the page's line-height instead of collapsing to a 1.0 line box). 19/11 is that RATIO, not a pin: it holds the row proportional when the label's step moves, which is exactly what gh#329 did to it. The previous hardcoded `line-height: 1` rendered an 11px row, sitting the whole lower half of the Login card 8px high (gh#263). ON the type scale (gh#329): the label was the literal `0.6875rem` (11px) and is now --font-size-2xs, the scale's ratio⁻² step ≈ 11.107px — the same step the sidebar section label, the kbd cap and the chrome page subtitle already take. GEOMETRY MOVES by 0.11px on the label and 0.19px on the row (19 → 19.19px), i.e. a fifth of a pixel, and in exchange the auth micro-scale finally rides the service's --font-size-base like everything else. 11 was never a step; it was 2xs rounded to the nearest whole pixel and then written down as if it were.",
    "name": "--auth-shell-divider-gap",
    "tier": "component",
    "value": "0.625rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-divider-label-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-divider-label-line-height",
    "tier": "component",
    "value": "calc(19 / 11)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-divider-rule-color",
    "tier": "component",
    "value": "var(--border)"
  },
  {
    "description": "default = var(--muted-foreground), resolved at the call site (gh#906)",
    "name": "--auth-shell-divider-label-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-identity-gap",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-requester-gap",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-requester-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-requester-glyph-size",
    "tier": "component",
    "value": "var(--icon-size-2xs)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-account-summary-min-height",
    "tier": "component",
    "value": "var(--control-height-comfortable)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-account-summary-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-account-summary-padding",
    "tier": "component",
    "value": "var(--space-1) var(--space-2)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-account-summary-identity-min-width",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-account-summary-avatar-size",
    "tier": "component",
    "value": "var(--control-height-sm)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-account-summary-avatar-glyph-size",
    "tier": "component",
    "value": "var(--control-icon-size-sm)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-account-summary-email-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-footer-content-gap",
    "tier": "component",
    "value": "0.375rem"
  },
  {
    "description": "The same 11px → 2xs snap as the divider label above (gh#329); this one carried no artboard anchor at all, only the literal. GEOMETRY MOVES by 0.11px.",
    "name": "--auth-footer-text-font-size",
    "tier": "component",
    "value": "var( --font-size-2xs, calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio)) )"
  },
  {
    "description": "The legal links sit at --font-size-2xs, so their line box alone is ~19px and every auth page failed WCAG 2.2 SC 2.5.8 on Terms / Privacy / the locale trigger. The floor is applied to the link BOX rather than a ::after hit area: the target a user (and an audit) measures is the element itself, and an invisible overlay that still reports 19px is not a fix. Text metrics are untouched — only the box grows.",
    "name": "--auth-footer-target-min-size",
    "tier": "component",
    "value": "var(--touch-target-min)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-stack-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-field-label-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "scale-exempt: SCR-001 pins the email input at y=489; --font-size-xs (12.47px) drifts the 18px label box to 18.7px (gh#263)",
    "name": "--auth-shell-field-label-font-size",
    "tier": "component",
    "value": "0.75rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--auth-shell-field-label-line-height",
    "tier": "component",
    "value": "1.5"
  },
  {
    "description": "CenteredShell — authenticated, no-sidebar, centred-column page shell (hosted-ID \"My Page\", account, standalone settings). The bar mirrors AppShell's `.app-topbar`: the same fixed height, and now the same HORIZONTAL PAGE-INSET AXIS (gh#330) — bar, main and footer all read the page gutter and all step to the compact gutter on the page's own `(max-width: 720px)` line, so the bar's content and the column beneath it share one content edge at every width. The comment here used to claim the bar mirrored `.app-topbar`'s inline padding. It did not, and had not since gh#330 moved that side onto --space-page-x: the bar was left hard-coding --space-4 (16px) while main and footer used --space-6 (24px). Measured in Chromium on /isolate/layout-centered-shell BEFORE this fix, the bar's content sat at x=16 and the column at x=24 — a constant 8px misalignment at every width from 784px down to 390px. 784 is not arbitrary: it is the md tier (46rem) plus the two 24px main gutters, the width below which the column stops being centred and pins to the gutter, which is what makes the error visible. AFTER: 24/24 at 784 and 760, 16/16 at 700 and 390. The column max-width has three tiers, all wider than the 24rem auth card. A service retunes the inset, block padding and each width tier without forking CSS.",
    "name": "--centered-shell-bar-height",
    "tier": "component",
    "value": "var(--app-shell-bar-height)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-bar-padding-x",
    "tier": "component",
    "value": "var(--space-page-x)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-bar-padding-x-compact",
    "tier": "component",
    "value": "var(--space-page-compact-x)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-main-padding",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Inline-only compact steps. They exist as their own knobs rather than as a redefinition of the shorthands above, so `--centered-shell-main-padding` keeps meaning all four sides and a service that already sets it is not broken by this fix.",
    "name": "--centered-shell-main-padding-inline-compact",
    "tier": "component",
    "value": "var(--space-page-compact-x)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-footer-padding",
    "tier": "component",
    "value": "var(--space-3) var(--space-6) var(--space-4)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-footer-padding-inline-compact",
    "tier": "component",
    "value": "var(--space-page-compact-x)"
  },
  {
    "description": "Block offset of the centred column inside the 100dvh shell. `0` (default, the quietest state — rule #44) keeps the top-aligned flowing page; `auto` centres the column in the viewport, which is what CenteredShell `align=\"center\"` sets for a SYSTEM-level standalone surface (500/503 error page, maintenance notice). Auto block offsets collapse to 0 when the content is taller than the viewport, so a long localized message scrolls from the top instead of clipping.",
    "name": "--centered-shell-column-offset-block",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-width-sm",
    "tier": "component",
    "value": "32rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-width-md",
    "tier": "component",
    "value": "46rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-width-lg",
    "tier": "component",
    "value": "64rem"
  },
  {
    "description": "CenteredShell · public-landing preset (gh#252) — the token-owned geometry of a PUBLIC marketing / product landing page: one content measure shared by header, main column and footer, the section rhythm between page sections, the flat (chrome-quiet) card presentation and the hero heading tier. Every value is a service-themeable knob (rule #45): a landing composition is a COMPOSITION of real primitives (docs/COMPOSITION-VS-COMPONENT.md — Hero/Navbar/Footer FAIL the Framework-Component Test), so the consumer must never own geometry or a media query. These knobs are read ONLY under `.ui-centered-shell[data-preset=\"public-landing\"]`, so the default shell — which emits no `data-preset` at all — is byte-identical to before. 1080px — header/main/footer share ONE measure",
    "name": "--centered-shell-landing-max-width",
    "tier": "component",
    "value": "67.5rem"
  },
  {
    "description": "24px page gutter ≥ 40rem",
    "name": "--centered-shell-landing-inset-inline",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "16px page gutter < 40rem",
    "name": "--centered-shell-landing-inset-inline-compact",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "40px",
    "name": "--centered-shell-landing-main-padding-block",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "24px",
    "name": "--centered-shell-landing-main-padding-block-compact",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "rhythm BETWEEN page sections",
    "name": "--centered-shell-landing-section-gap",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-landing-section-gap-compact",
    "tier": "component",
    "value": "var(--space-6)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-landing-footer-padding-block",
    "tier": "component",
    "value": "var(--space-8)"
  },
  {
    "description": "Chrome is a token, default quiet (rule #44): a landing surface is FLAT — no card elevation — so a service opts back IN with `--centered-shell-landing-card-shadow: var(--card-shadow)`.",
    "name": "--centered-shell-landing-card-shadow",
    "tier": "component",
    "value": "none"
  },
  {
    "description": "Hero heading tier. The preset re-points `--heading-h1` (same mechanism as `.ui-auth-shell` → `--auth-shell-heading-size`), so a hero title is a real `Heading level={1}` and never a consumer font-size.",
    "name": "--centered-shell-landing-heading-size",
    "tier": "component",
    "value": "var(--font-size-display)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--centered-shell-landing-heading-size-compact",
    "tier": "component",
    "value": "var( --font-size-3xl, calc(var(--font-size-display) / var(--font-size-display-ratio) / var(--font-size-display-ratio)) )"
  },
  {
    "description": "Role-mirror knob — MUST stay `initial`, with the role default at the CALL SITE (`var(--centered-shell-landing-background, var(--background))`), so a scoped `[data-tenant]` / `.dark` override of `--background` still reaches it (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Documented default = hsl(var(--background)) — a public page is the plain page canvas, not the app's `--muted` chrome.",
    "name": "--centered-shell-landing-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Rule #24 companion (gh#291): on coarse pointers --control-height grows to 2.75rem (44px tap floor), and the shell bar sits flush with the viewport top — a 3rem bar leaves the control's 3px focus ring painting ABOVE y=0, off-screen, which no overflow setting can recover. 3.5rem gives 6px of breathing per side.",
    "name": "--app-shell-bar-height",
    "tier": "component",
    "value": "var(--band-height-3xl)"
  },
  {
    "description": "Same rule #24 companion for the second navigation track: a finger gets the 44px floor back, and the track widens with the cell so the cell is not clipped by the rail it sits in.",
    "name": "--app-shell-nav-rail-width",
    "tier": "component",
    "value": "3rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--app-shell-nav-rail-item-size",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "And for the Sidebar's own rows (gh#1138): measured 32px under a finger while the Tree rows and SearchInput beside them had already grown to 44 with the control ladder.",
    "name": "--sidebar-nav-item-height",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "MobileShell (gh#354 §6) — the handheld app shell: a status band, an app bar, ONE scroll region, a sticky action bar and a bottom tab bar. Two facts here cannot be reached by composition, which is why they belong to the shell and not to the page: 1. The shell is the only scroll container. The root is exactly one viewport tall (`--mobile-shell-block-size`), so the document itself never scrolls and the chrome bands never leave the screen — the reason a composed `Card` + `overflow-y-auto` stack drifts on a real phone, where the URL bar collapses under the page. 2. Every band absorbs the device safe-area insets, so a notch never covers the app bar and the home indicator never covers the primary verb. The safe-area knobs are `env()` values and are therefore ZERO on every surface with no insets (desktop, jsdom, the docs frames) — the geometry below is unchanged there. The INLINE knob takes `max()` of BOTH physical insets on purpose: `env(safe-area-inset-left)` is physical, so binding it to the inline START would be wrong under `dir=\"rtl\"`. A symmetric inset is correct in both writing directions and costs at most a few px on the non-notch side in landscape. A service retunes the page gutter, the three band heights and the block padding from its theme; nothing here is reachable only through a consumer selector.",
    "name": "--mobile-shell-block-size",
    "tier": "component",
    "value": "100dvh"
  },
  {
    "description": "430px — the widest logical width the current handheld class reports (iPhone Pro Max / Pixel Pro XL). It is a CAP, so it has to sit at or above every real device width the shell is meant to be read at; below that, `width=\"phone\"` would squeeze the very screens it exists to serve. Only `width=\"phone\"` reads it; the default `fill` never does.",
    "name": "--mobile-shell-max-inline-size",
    "tier": "component",
    "value": "26.875rem"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-safe-inset-block-start",
    "tier": "component",
    "value": "env(safe-area-inset-top)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-safe-inset-block-end",
    "tier": "component",
    "value": "env(safe-area-inset-bottom)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-safe-inset-inline",
    "tier": "component",
    "value": "max(env(safe-area-inset-left), env(safe-area-inset-right))"
  },
  {
    "description": "Page gutter shared by every band AND by the scroll region, so the app-bar title, the list rows and the sticky action bar sit on ONE content edge — the axis gh#330 had to repair for CenteredShell after the bar and the column drifted 8px apart.",
    "name": "--mobile-shell-inset-inline",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Touch tier for the WHOLE shell subtree, the same technique `.ui-auth-shell` uses. Rule #24's 44px floor is already reached on a coarse pointer through --control-height, but a handheld app is touch-first BY DEFINITION — it must not render 32px targets merely because it is being previewed with a mouse, or because a service ships it in an Electron/desktop wrapper.",
    "name": "--mobile-shell-control-height",
    "tier": "component",
    "value": "var(--control-height-comfortable)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-region-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-status-bar-height",
    "tier": "component",
    "value": "var(--band-height-lg)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-header-bar-height",
    "tier": "component",
    "value": "var(--band-height-3xl)"
  },
  {
    "description": "4rem. A tab bar is an icon stacked over a label, so it is one step TALLER than the app bar; there is no 64px band step, so it derives from the 3.5rem one (tier 2a).",
    "name": "--mobile-shell-tab-bar-height",
    "tier": "component",
    "value": "calc(var(--band-height-3xl) + var(--space-2))"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-main-padding-block",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Shell (sidebar / topbar / kbd) component tokens — small-by-design text knobs (rule #45/#46). A service re-tunes chrome text without moving the global scale.",
    "name": "--mobile-shell-actions-padding-block",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Resting nav row + label (also the resting sub-row). Default = hsl(var(--muted-foreground)).",
    "name": "--sidebar-nav-item-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Hovered nav row + label. Default = hsl(var(--foreground)).",
    "name": "--sidebar-nav-item-hover-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`aria-disabled` nav row + label. Default = the resting row colour.",
    "name": "--sidebar-nav-item-disabled-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Nav ICON (`.sb-icon`, incl. the collapsed rail and group triggers). Default = currentColor, i.e. the row colour — the pre-gh#228 look. Set this alone to get canonical dark icons next to muted labels.",
    "name": "--sidebar-nav-icon-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Icon on a hovered / active / disabled row. Each falls back to --sidebar-nav-icon-foreground, then to currentColor, so setting the base icon knob alone themes every state.",
    "name": "--sidebar-nav-icon-hover-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Sidebar nav-row COLOUR knobs (gh#228). The row/label and its icon are separately themeable: before this, `.sb-nav-item` painted one `--muted-foreground` that the Lucide SVG inherited, so a service could only darken its 16px nav icons by writing page-local CSS or by re-tinting every muted text globally. Geometry knobs (--sidebar-nav-icon-size, --sidebar-nav-item-height/-gap/ -padding-x) live in components/shell.css and are untouched by these. ROLE-MIRROR KNOBS — declared `initial` here with the role default at the CALL SITE (`var(--knob, hsl(var(--role)))`), so a scoped `[data-tenant]` / `.dark` role override re-resolves live instead of freezing at :root (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Every default is byte-identical to the pre-gh#228 rendering. The ACTIVE row's own background/foreground keep their existing knobs (--sidebar-item-active-background / --sidebar-item-active-foreground, components/shell.css); only the active ICON gets a new one.",
    "name": "--sidebar-nav-icon-active-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Sidebar nav-row COLOUR knobs (gh#228). The row/label and its icon are separately themeable: before this, `.sb-nav-item` painted one `--muted-foreground` that the Lucide SVG inherited, so a service could only darken its 16px nav icons by writing page-local CSS or by re-tinting every muted text globally. Geometry knobs (--sidebar-nav-icon-size, --sidebar-nav-item-height/-gap/ -padding-x) live in components/shell.css and are untouched by these. ROLE-MIRROR KNOBS — declared `initial` here with the role default at the CALL SITE (`var(--knob, hsl(var(--role)))`), so a scoped `[data-tenant]` / `.dark` role override re-resolves live instead of freezing at :root (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). Every default is byte-identical to the pre-gh#228 rendering. The ACTIVE row's own background/foreground keep their existing knobs (--sidebar-item-active-background / --sidebar-item-active-foreground, components/shell.css); only the active ICON gets a new one.",
    "name": "--sidebar-nav-icon-disabled-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-row-height-compact",
    "tier": "component",
    "value": "var(--band-height-sm)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-row-height-default",
    "tier": "component",
    "value": "var(--band-height-lg)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-row-height-comfortable",
    "tier": "component",
    "value": "var(--band-height-xl)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-row-height",
    "tier": "component",
    "value": "calc(var(--table-row-height-default) * var(--scaling))"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-cell-padding-y",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "THE CELL'S INLINE INSET — and it is the CARD'S inset, not the control's (gh#849). Measured on /showcase/table-pagination at 1440px, gap from the card's inner edge: card header (title / count) 17px table th/td (column text) 13px <- the odd one out pagination footer 17px One card, three horizontal bands, two optical axes. The table read the CONTROL step (--control-padding-x, 12px) while the card read the SECTION step (--card-space-inset -> --space-section-active, 16px), and a table is the flush body of a card more often than it is anything else — so the two steps meet at the same edge on the most common composition this library ships, and the table sits 4px inboard of the header above it and the footer below it, on BOTH edges. It cannot be settled in the footer: --table-pagination-padding-x defaults to THIS token so the \"rows per page\" label lands on the first column's text axis, so the footer follows the columns by design. Either the cells move to the card's inset or the card's own chrome disagrees with its content forever. IBM Carbon — this repo's spacing authority (docs/DESIGN-AUTHORITY.md) — gives DataTable and Tile the same 16px inline inset for exactly this reason. Both 12 and 16 are legal Carbon steps; the RELATIONSHIP is what was wrong, not the number. `initial`, not `var(--space-section-active)`, per docs/TOKENS.md - \"Role-mirror knobs MUST be `initial`\". The old binding was a :root var() and it FROZE: probed in Chromium, setting --control-padding-x on the card left the cell padding at 12px, and on a subtree with --scaling .92 the control step resolved to 11.04px while the cell still used the root's unscaled 12px. A token that claims to track another and silently does not is worse than one that never claimed it. default = var(--space-section-active)",
    "name": "--table-cell-space-x",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Hierarchy indent step for `<TableCell indent={depth}>` (gh#354). The cell's inset is `--table-cell-space-x + depth × this step`, so level 0 sits exactly on the column's own text axis and every further level is one step in. Owned here rather than as a magic expression in JSX (the trap `--tree-select-depth-space-step` was pulled out of), so a denser service dials the step down — or to `0` for a flat table — without touching a call site.",
    "name": "--table-cell-indent-space-step",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Cell-grid rule colour for `<Table bordered>` (gh#274) — the outer frame and the vertical rules between columns. Declared `initial` so the default re-resolves to the LIVE --border role at the call site (a :root binding to hsl(var(--border)) freezes at the :root value and a scoped [data-tenant] override of --border would never reach it — docs/TOKENS.md). Default = hsl(var(--border)).",
    "name": "--table-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-pagination-padding-y",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-pagination-padding-x",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "DataTable surface — narrow-viewport legibility FLOOR (gh#253). Below the `sm` viewport step a multi-column admin grid whose columns are `white-space: nowrap` would otherwise be crushed, so the bordered surface keeps a minimum inline size and `.ui-data-table-scroll` scrolls instead. This shipped as a hard-coded `min-w-[640px]` utility on the surface element, which left a service that wants a narrower (or no) floor with no route but forking the component (#45). Default = the previous literal, in px so the floor releases at EXACTLY the same width as the px-based `sm` media query that clears it (a rem value would drift under a non-16px root and re-introduce the scroll between the two thresholds). Set `0` to opt out entirely — which is what `preset=\"action-collection\"` does, because there the priority measures own the width.",
    "name": "--table-surface-min-inline-size",
    "tier": "component",
    "value": "640px"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-head-font-size",
    "tier": "component",
    "value": "var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)))"
  },
  {
    "description": "Header WEIGHT (gh#410). Was the literal `var(--font-weight-medium)` in table-layout.css, which left a service that wants a quiet header row writing `font-normal` on every `<TableHead>` — 18 of them in the app that reported this. Default is byte-identical; a quiet header is now one declaration (`--table-head-font-weight: var(--font-weight-normal)`).",
    "name": "--table-head-font-weight",
    "tier": "component",
    "value": "var(--font-weight-medium)"
  },
  {
    "description": "Header band — its OWN bg + fg knobs (decoupled from --secondary). Declared `initial` so the default re-resolves to the LIVE --muted / --muted-foreground roles at the call site: a :root binding to a role var freezes at the :root value and a scoped [data-tenant] role override never reaches it. A brand sets both header tokens together to keep band/text contrast. Defaults = hsl(var(--muted)) band · hsl(var(--muted-foreground)) text.",
    "name": "--table-header-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--table-header-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-header-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "THE DATATABLE FRAME ITSELF (gh#880). Every band, row state and header inside the table has had a knob for some time; the box that draws the frame around them had none and painted no fill at all, so a themed page could retint the contents of a table and not the table. Unset, the declaration is invalid-at-computed-value-time and `background-color` keeps its own initial `transparent` — which is exactly what the surface painted before, so nothing moves. default = transparent, i.e. what the frame already had",
    "name": "--table-surface-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`initial` keeps the shipped contract: with no fill asked for, the whole declaration is invalid-at-computed-value-time and the surface stays transparent.",
    "name": "--table-surface-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "GLASS — `initial`, no blur and no backdrop root. A DataTable holds sticky/pinned columns; a backdrop root here would change what `position: fixed` inside the frame resolves against. default = none — the frame blurs nothing",
    "name": "--table-surface-backdrop-blur-size",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Inline-end shadow that lifts a pinned (sticky) action column off the body it scrolls over.",
    "name": "--table-pin-shadow",
    "tier": "component",
    "value": "-6px 0 6px -5px hsl(var(--foreground) / 0.12)"
  },
  {
    "description": "The same lift for a column frozen to the inline START (antd `fixed: \"start\"`), pointing the other way. `box-shadow` has no logical offset, so the writing direction needs its own value — the RTL companion is a token rather than a literal in the stylesheet so a service that retunes one edge cannot leave the other behind.",
    "name": "--table-fixed-shadow-start",
    "tier": "component",
    "value": "6px 0 6px -5px hsl(var(--foreground) / 0.12)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-fixed-shadow-start-rtl",
    "tier": "component",
    "value": "-6px 0 6px -5px hsl(var(--foreground) / 0.12)"
  },
  {
    "description": "Leading column that carries the expand affordance (antd `expandable`). Sized like the selection column beside it so the two leading columns read as one gutter.",
    "name": "--table-expand-column-width",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "Footer totals row (antd `summary`). `initial` so the --muted default re-resolves under a scoped theme, exactly like the row-state washes above. Default = hsl(var(--muted)).",
    "name": "--table-summary-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--table-summary-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Wash behind an expanded detail row, so the panel reads as belonging to the row above it. Default = hsl(var(--muted) / 0.3), the same weight as the selected-row tint. It fades out as --table-row-striped-alpha comes in: on a striped table the stripe ties the panel to its row.",
    "name": "--table-row-expanded-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Inset of the expanded detail cell (gh#1083). `initial` so the default — the cell's own padding, var(--table-cell-padding-y) var(--table-cell-space-x), which follows density — re-resolves at the call site. `expandable.flush` drops it.",
    "name": "--table-row-expanded-padding",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Gap between the header checkbox and the `selections` dropdown trigger beside it.",
    "name": "--table-selection-menu-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Row-state tint washes — translucent muted over the opaque base. `initial` so the --muted default re-resolves under a scoped theme; a service retints by reading another role (e.g. --primary). Defaults = hsl(var(--muted) / 0.8) striped · hsl(var(--accent) / 0.7) hover · hsl(var(--muted) / 0.3) selected. The stripe was --muted / 0.4 until gh#700 measured it: 1.02:1 against the plain row in light, i.e. not a stripe. 0.8 is the strongest --muted step that keeps every text role on it at AA with the control boundary still at 3:1 (muted-foreground 5.29 light / 5.71 dark, --input 3.24 / 3.31) and leaves the --accent hover a visible step beyond it in both themes — src/tokens/__tests__/table-stripe-contrast.test.ts recomputes all of it.",
    "name": "--table-row-striped-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Zebra SWITCH (gh#700) — how much of --table-row-striped-background every EVEN logical body row paints: `0%` = no stripe (the default, byte-identical to an unstriped table), `100%` = the full stripe. It is the percentage a `color-mix(… , transparent)` reads at the row, so it is a ratio and not a flag: a theme may also dial a lighter stripe (`60%`). It is a SHARE OF the stripe colour rather than the resulting alpha (gh#886) — the base default `hsl(var(--muted) / 0.8)` already carries an alpha, so `100%` composites to 0.8 and `60%` to 0.48. THE SERVICE-WIDE DEFAULT IS THIS ONE LINE: `:root { --table-row-striped-alpha: 100%; }` stripes every Table and DataTable. The `striped` prop is the per-instance override on top of it — `striped` sets `100%` on that table, `striped={false}` sets `0%`, and leaving the prop out inherits whatever the theme chose. A plain length is not a role mirror, so it lives on :root without the freeze rule (docs/TOKENS.md).",
    "name": "--table-row-striped-alpha",
    "tier": "component",
    "value": "0%"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-row-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 0.7 at the call site",
    "name": "--table-row-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-row-selected-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 0.3 at the call site",
    "name": "--table-row-selected-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Table · action-collection preset (gh#253) — the canonical dense approval / action queue. Column PRIORITY measures replace the desktop intrinsic widths (a nowrap free-text column is what makes a five-column queue wider than its card and forces a horizontal scroll). Nothing here is read unless `preset=\"action-collection\"` is set, so every existing table is untouched. Percentages so the ratio holds at any card width; the action affordance is an absolute measure because it must never be squeezed below its touch target. requester / subject",
    "name": "--table-action-collection-primary-width",
    "tier": "component",
    "value": "18%"
  },
  {
    "description": "target / resource",
    "name": "--table-action-collection-secondary-width",
    "tier": "component",
    "value": "22%"
  },
  {
    "description": "timestamps, ids — lowest priority",
    "name": "--table-action-collection-meta-width",
    "tier": "component",
    "value": "12%"
  },
  {
    "description": "row-action affordance: a FLOOR, not a cap — Table grows the column to a wider actions cell content (a text button + `…` menu), gh#1067",
    "name": "--table-action-collection-actions-width",
    "tier": "component",
    "value": "3.5rem"
  },
  {
    "description": "Compact tier, applied below the collapse step (the 390px acceptance frame). Percentages, like the desktop tier: while the priority ratios FIT (the canonical queues up to the six-column budget below), they keep the table filling its container edge-to-edge with no horizontal scroll — the gh#253 acceptance.",
    "name": "--table-action-collection-primary-width-compact",
    "tier": "component",
    "value": "24%"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-secondary-width-compact",
    "tier": "component",
    "value": "22%"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-meta-width-compact",
    "tier": "component",
    "value": "20%"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-actions-width-compact",
    "tier": "component",
    "value": "2.75rem"
  },
  {
    "description": "Wide-collection FLOORS — the compact measures wherever the priority budget is OVER-SUBSCRIBED (gh#262, gh#844). Percentage measures stop working once a queue carries enough columns for the shares to sum past 100%: `table-layout: fixed` NORMALIZES them back into the table's specified width, so at ~10 columns on a 390px frame a \"24%\" column really renders at a tenth of the frame, every column drops below one CJK glyph, and JA headers shred into a vertical one-character-per-line column (the failure mode WCAG 2.2 SC 1.4.10 Reflow exists to prevent). Cell `min-inline-size` is inert in the fixed algorithm, `max(%, length)` resolves to neither operand (below), and the intrinsic (max-content) size of a fixed-layout table is degenerate — all in Chromium — so a LENGTH is the only floor an engine respects: length columns are never squeezed, and when their sum outgrows the container the table's used width grows past its specified 100% (CSS 2.1 §17.5.2.1) into the keyboard-reachable overflow-x wrapper, which scrolls. ONE-dimensional scrolling of a data table is explicitly permitted by SC 1.4.10; one-character-per-line is not readable at all. The stylesheet switches tiers on the BUDGET, not on width. The budget is one column per priority tier plus one free-text column; the floors engage wherever a queue asks for more than that, and a queue that fits it keeps its scroll-free percent tier byte-for-byte. Two ways to ask for more, and gh#262 only saw the first: SEVEN COLUMNS. With five distinct column kinds, seven columns must repeat something, so the shares are guaranteed to over-sum (gh#262 expectation 3). A REPEATED TIER, at ANY column count (gh#844). The compact measures are per-column percentages, NOT shares of a sum: a `primary` column is 24% of the table whether the table has three columns or six. So the column count does not predict readability at all — what over-subscribes the budget is repeating a tier, and the surplus comes out of the `auto` free-text column. Measured at 390 with a 340px card content box, a FIVE-column JA queue carrying two `meta` columns left its free-text column 47.6px wide: 15 glyphs over 8 line boxes, 1.9 characters per line — the same shred gh#262 fixed at ten columns, three columns below the ceiling that was supposed to make it impossible. The same queue on the floors is 4.75 characters per line and scrolls, which is the trade SC 1.4.10 already sanctions above. `max(%, length)` is not an alternative to the switch. It is not merely ignored: in the fixed algorithm Chromium resolves `max(24%, 6rem)` on a 340px table to 113px — neither the 81.6px percentage nor the 96px floor — so it cannot express \"this column, floored\". Units are rem, not ch: `ch` tracks the \"0\" glyph (~half a CJK em), so a ch-denominated floor would silently halve for the JA copy these floors exist to protect. At the compact type tier (font-size-xs = 0.75rem, space-2 inline padding each side) the 5rem meta floor keeps a ~4rem text measure = 5 full-width glyphs per line — a JA header wraps to two readable lines, never a character column.",
    "name": "--table-action-collection-primary-width-floor",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-secondary-width-floor",
    "tier": "component",
    "value": "5.5rem"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-meta-width-floor",
    "tier": "component",
    "value": "5rem"
  },
  {
    "description": "Floor for a column with NO `priority` (the free-text column, `auto` up to the budget). It cannot stay `auto` past the budget: once the marked columns over-constrain the table, the fixed algorithm hands an auto column exactly 0px (verified in Chromium) — the same shredding, moved to the free-text column. The actions floor is simply `--table-action-collection-actions-width-compact`, already an absolute measure.",
    "name": "--table-action-collection-flex-width-floor",
    "tier": "component",
    "value": "5rem"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-font-size-compact",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-cell-space-x-compact",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-cell-padding-y-compact",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-action-collection-row-height-compact",
    "tier": "component",
    "value": "var(--table-row-height-compact)"
  },
  {
    "description": "Compact-tier LEGIBILITY FLOOR — the measure below which the preset stops fitting the table to its container and lets the scroll region it already owns take over. The percentage budget above is sized for ONE column per priority tier plus one free-text column. A queue that repeats a tier — two `secondary` columns, three `meta` columns, or an unmarked column beside them — asks for more than 100%, and under `table-layout: fixed` the surplus is taken out of the columns rather than out of the table: measured on a seven-column Japanese admin queue at 390, every column landed at 44–59px and CJK labels wrapped at ONE to TWO characters per line (dxs-platform/platform#680). That is a WCAG 2.2 SC 1.4.10 Reflow (AA) failure, and it is the failure mode this floor removes. Scrolling is the correct escape, not a concession: SC 1.4.10 exempts \"parts of the content which require two-dimensional layout for usage or meaning\", and its own note names data tables as the example. A table that scrolls horizontally inside its card conforms; a table whose cells are one character wide does not. Default `0` so nothing changes for any existing consumer: a queue that fits its priority budget keeps fitting. A consumer whose queue carries more columns than the budget sets this to the measure at which its narrowest column is still readable (roughly 5rem per column for Japanese at the compact type tier) and the table scrolls instead of crushing. A LENGTH (`0px`, not `0`): the stylesheet adds a measured actions width to it (gh#1207), and `calc(0 + 34px)` is invalid.",
    "name": "--table-action-collection-min-inline-size-compact",
    "tier": "component",
    "value": "0px"
  },
  {
    "description": "Table · stacked-record-collection preset (gh#293 restore — SCR-215) — the canonical WIDE, heterogeneous record collection. Below the collapse step every `<tr>` becomes a bordered key-value card; these tokens own the card's own geometry (unlike action-collection, there is no column-priority measure to retune — the whole row becomes one block).",
    "name": "--table-stacked-collection-card-padding-y",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-stacked-collection-card-padding-x",
    "tier": "component",
    "value": "var(--space-inline-md)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-stacked-collection-card-gap",
    "tier": "component",
    "value": "var(--space-stack-sm)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-stacked-collection-cell-padding-y",
    "tier": "component",
    "value": "var(--space-stack-xs)"
  },
  {
    "description": "Inline inset of a folded cell inside its card (gh#1102). 0: the card's own --table-stacked-collection-card-padding-x is the inset, so a value line gets the card's full content width instead of losing the table's cell padding on both sides.",
    "name": "--table-stacked-collection-cell-padding-x",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-stacked-collection-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "DATA TABLE odds and ends that were still literal on the component (#319). The table's cell rhythm, widths and action-collection tiers were already tokenized; these are the pieces around them — the select column, sort glyphs, sticky header layer and skeleton shapes.",
    "name": "--table-select-column-width",
    "tier": "component",
    "value": "2.5rem"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-sort-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xs)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-toolbar-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-pagination-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-pagination-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Skeleton placeholders mimic the real content they stand in for: a checkbox square and a text line at the row's cap height. Retune with --table-cell-padding-y to keep the loading state the same height as the loaded one.",
    "name": "--table-skeleton-check-size",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "The skeleton bar's BLOCK SIZE. `--table-skeleton-line-height` was a length on the line-height axis, whose scale is unitless ratios (gh#324) — a mis-named height, and the only raw value on that axis, which is what kept the axis ungated. Renamed rather than left, with the old name kept as a DEPRECATED ALIAS: it is a published token a consumer theme may already override, and styles/table-layout.css still reads the old name, so an override of either spelling keeps working. Prefer the new name; the alias may be removed in a future major.",
    "name": "--table-skeleton-line-block-size",
    "tier": "component",
    "value": "1rem"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-skeleton-line-height",
    "tier": "component",
    "value": "var(--table-skeleton-line-block-size)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--table-skeleton-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The table's own base type step (gh#319). Was a `text-sm` utility on the <table>; the theme remaps `--text-sm` to `--font-size-sm`, so this default is byte-identical.",
    "name": "--table-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "MANDATORY companion to --table-font-size — the gh#260 trap, again. `text-sm` also set line-height from Tailwind's `--text-sm--line-height`, and styles/base.css remaps `--text-sm` but NOT that companion. Without this the table would silently inherit ambient page leading the moment the font-size moved into CSS. Same unitless ratio Tailwind ships.",
    "name": "--table-line-height",
    "tier": "component",
    "value": "calc(1.25 / 0.875)"
  },
  {
    "description": "Horizontal row rule (chrome, #44) — the divider between body rows AND under the header row. Owned here rather than as TableRow's `border-b` utility so the \"last row draws no rule\" rule in `@layer components` can actually zero it; a utility would outrank it by layer. Colour is deliberately NOT set: it inherits the global `* { border-color: hsl(var(--border)) }` so a scoped [data-tenant]/.dark override of --border still reaches every row. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--table-row-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Flush divider (chrome, #44/#45) — the ONE edge a full-bleed table keeps when it sits inside `<CardContent flush>`: the line between a plain CardHeader and the first row. The other three edges coincide with the card's own frame and are erased (gh#305); this one has nothing behind it, so without it the header band floats (gh#306). Scoped by construction to the case that needs it — a BANDED header, a CardBar or a headerless card already draw their own line there and never reach this token — so a service tunes only the plain-header divider: `0` for a borderless full-bleed table, heavier for a stronger band. Colour and style are NOT set here: only the width is restored, so the surface's own border declaration still owns them and a scoped [data-tenant]/.dark override of --border reaches it. Default = the same hairline the table's other rules draw.",
    "name": "--table-flush-divider-width",
    "tier": "component",
    "value": "var(--table-row-border-width, var(--stroke-hairline))"
  },
  {
    "description": "Row TONE (`rowTone`) — the leading-edge rail plus the wash behind a row in a named state. The rail measure is `--card-accent-rail-width`'s own step so a toned row and a toned Card read as the same mark at the same weight; it is spelled out rather than referenced because a service that thins its card rails should not silently thin its table rails too. The wash is deliberately weak: it must stay under the selected-row fill (which is a stronger statement about the same row) and must not carry meaning on its own — that is what the rail and the row's own status cell are for. default = var(--stroke-2xl), resolved at the call site (gh#906)",
    "name": "--table-row-tone-rail-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Table component tokens: row height, cell padding.",
    "name": "--table-row-tone-wash-alpha",
    "tier": "component",
    "value": "0.06"
  },
  {
    "description": "Distance from the text baseline to the underline. In `em` on purpose: the rule has to stay proportional across the seven type steps, and a px value that reads right at `lg` crowds the descenders at `2xs`. GoDX v2.3 guideline: `.gx a { text-underline-offset: .18em }`",
    "name": "--text-link-underline-offset",
    "tier": "component",
    "value": "0.18em"
  },
  {
    "description": "`auto` lets the face decide; a theme that wants a heavier rule names a length.",
    "name": "--text-link-underline-width",
    "tier": "component",
    "value": "auto"
  },
  {
    "description": "THE LINK IS UNDERLINED AT REST, and the default is a measurement, not a taste (gh#664). It was `none` with the rule added only on hover/focus, so a link inside a sentence differed from the words around it by hue alone — and that hue is 1.87:1 against body ink in light, 1.54:1 in dark. WCAG 1.4.1 lets colour carry a link on its own only at 3:1 (technique G183), so the old default failed it everywhere a link sat in running text. The consumer met it for real: \"97 người đang dùng\" read as plain copy and nobody clicked it (godx-jp/id#1419). The v2.3 guideline agrees: `.gx a` never removes the UA underline, and its prose says \"Chữ link có gạch chân\". `none` is still a legal value, because a link in a nav row or a card title carries its affordance some other way. It is NOT a style knob for running text: at the shipped colours it re-opens the 1.4.1 failure this default closes.",
    "name": "--text-link-decoration-line",
    "tier": "component",
    "value": "underline"
  },
  {
    "description": "Gap between the text and the operation cluster, and between the operations.",
    "name": "--text-action-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The operation reads as a link, because that is what it is — an affordance inside running text, not a control box. Same reasoning as `Text`'s own `link` prop. default = hsl(var(--primary)), resolved at the call site",
    "name": "--text-action-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = the live primary hover, resolved at the call site — a `:root` binding would freeze on the root's primary and ignore a scoped re-theme (docs/TOKENS.md, the freeze rule; gh#678)",
    "name": "--text-action-color-hover",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The icon box tracks the run it sits in: `em`, so a copy button beside `size=\"2xs\"` shrinks with it instead of towering over the text.",
    "name": "--text-action-size",
    "tier": "component",
    "value": "1em"
  },
  {
    "description": "`<mark>` is a FILL plus the label measured against it — `--warning` / `--warning-foreground` are exactly that pair. NOT `--text-warning`, which is the AA-safe INK tier and would paint a dark yellow highlight with dark text on it.",
    "name": "--text-mark-background",
    "tier": "component",
    "value": "hsl(var(--warning))"
  },
  {
    "description": "TEXT — knobs for the typographic primitive's link affordance. Size, weight and tone are NOT here: they are the foundation's own `--font-size-*`, `--font-weight-*` and the semantic foreground roles, read directly by `styles/text-layout.css`. A link adds two things those tiers do not describe — how far the rule sits from the baseline, and how heavy it is.",
    "name": "--text-mark-foreground",
    "tier": "component",
    "value": "hsl(var(--warning-foreground))"
  },
  {
    "description": "Gap between two steps, and between the glyph column and the body.",
    "name": "--thought-chain-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-node-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Gap between the header, the body and the footer of ONE step.",
    "name": "--thought-chain-body-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The glyph column. A square, so an ordinal, an icon and a status mark share one track and the connector below stays centred under all three. It reads the BAND height, not an icon step, so the circle matches the title band it sits beside; 24px and 36px are the nearest steps and both would break that alignment to buy nothing. scale-exempt: 28px ordinal medallion sized to the title band, not a glyph",
    "name": "--thought-chain-icon-size",
    "tier": "component",
    "value": "var(--band-height-sm)"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-icon-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-icon-radius",
    "tier": "component",
    "value": "var(--radius-pill)"
  },
  {
    "description": "Role-mirror knobs (docs/TOKENS.md): `initial`, so each documented default resolves at the CALL SITE and a scoped `[data-tenant]` / `.dark` override still reaches it. Default ground = hsl(var(--muted)) · default ink = hsl(var(--muted-foreground))",
    "name": "--thought-chain-icon-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-icon-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Status tints. Same three roles the rest of the library uses for the same three meanings.",
    "name": "--thought-chain-icon-success-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-icon-error-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The connector. Its inline position tracks HALF the glyph column so it stays centred whatever the column's size becomes — never a literal offset. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--thought-chain-line-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--border))",
    "name": "--thought-chain-line-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The collapsed body and its chevron.",
    "name": "--thought-chain-chevron-size",
    "tier": "component",
    "value": "var(--icon-size-sm)"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-content-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "A STANDALONE step (ThoughtChainItem) — the chip an assistant drops inline.",
    "name": "--thought-chain-item-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-item-padding-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "ThoughtChain component tokens — the assistant's reasoning, step by step (Ant Design X `ThoughtChain`). Ant retunes this through `styles={{ root, item, itemHeader, itemIcon, itemContent, itemFooter }}`. This file is the answer instead (rules #44/#45). The chain deliberately reads the SAME steps as `Timeline`'s rail, because the two are the same vertical object seen twice — one for events that happened, one for a run in progress — and two rails on one screen that disagree by two pixels is the complaint gh#559 opens with.",
    "name": "--thought-chain-item-padding-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--thought-chain-item-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hsl(var(--muted))",
    "name": "--thought-chain-item-solid-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = hairline solid hsl(var(--border))",
    "name": "--thought-chain-item-outlined-border",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── Counter pill · geometry. One knob per component (rule #45, and the repo's existing shape: --button-count-*, --tag-input-chip-font-size, --toggle-sm-font-size are all independent knobs off the same primitive scale). The VALUES are byte-identical to Button's counter pill and read the same primitive tokens, so the two pills render the same size and a Toggle count set beside a Button count is indistinguishable — asserted by src/styles/__tests__/toggle-count-token-parity.test.ts so it cannot drift silently. (They are concrete here rather than `initial` + a call-site `var(--toggle-…, var(--button-…))` fallback because check:typography requires a bare `var(--token)` for every font-size, and a split shape across the five geometry knobs would be worse than a consistent one.)",
    "name": "--toggle-count-min-width",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-count-space-inline",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-count-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-count-radius",
    "tier": "component",
    "value": "var(--radius-pill)"
  },
  {
    "description": "Quiet default (#44) — the toggle's own flex gap already separates label from pill; this knob ADDS to it for a service whose design grid wants the counter pushed further out.",
    "name": "--toggle-count-gap",
    "tier": "component",
    "value": "0"
  },
  {
    "description": "── Counter pill · unpressed colours. Defaults = hsl(var(--muted)) fill (quiet: 1.09:1 against the chip's own surface, so at rest the count reads as text, #44) and hsl(var(--foreground)) text (14.25:1 on that fill). Opaque on purpose — a translucent fill would take its contrast from whatever surface the chip currently has, and lose ~0.7 on hover.",
    "name": "--toggle-count-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── `soft` · the REST surface (gh#734). Defaults = hsl(var(--secondary)) fill with hsl(var(--secondary-foreground)) text — the pair `Badge variant=\"secondary\"` and `.ui-button--secondary` already paint, so a chip, a badge and a button on one row are one family and a service that re-themes `--secondary` moves all three at once. The hover step is the OPAQUE `--secondary-hover`, not a translucent tint, because a chip row sits on the page and inside a Card and a translucent hover would read differently on each. Role-mirror knobs — `initial` here with the role at the call site (docs/TOKENS.md).",
    "name": "--toggle-soft-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-soft-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-soft-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The `soft` chip's own counter pill. Defaults = hsl(var(--background)) fill, hsl(var(--foreground)) text. It cannot inherit the generic `--muted` fill above: `--muted` and `--secondary` are the same value in the shipped theme, so that pill would measure 1.00:1 on a soft chip and vanish.",
    "name": "--toggle-soft-count-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-soft-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── Counter pill · PRESSED colours. Defaults = hsl(var(--primary-foreground)) fill, hsl(var(--primary)) text — the pressed chip's OWN pair, swapped. Not `--primary` on `--primary`: the pressed chip is already filled with --primary, so a --primary pill would be invisible on it. The swap also flips the pill from near-invisible to solid, which is one of the encodings that keeps the pressed state off colour alone (WCAG 1.4.1).",
    "name": "--toggle-pressed-count-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--toggle-pressed-count-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TOGGLE — counter-pill + pressed-state knobs (gh#312). Toggle owns the pressed state; Button owns the counter-pill vocabulary (`count` / `overflowCount` / `showZero`). A counted pressed chip (a faceted filter chip \"Unread 12\", a reaction chip) needs both, so Toggle grew the same vocabulary — and these knobs exist so it grows it WITHOUT growing a second, drifting set of constants (cardinal rule #45). SHARE vs SPLIT — the rule this file follows, and why each half falls where it does: • GEOMETRY is genuinely the same pill — min-width, inline padding, type step, corner. Toggle keeps its OWN knob for each (rule #45) but sets it to Button's exact value off the same primitive scale token, and a test asserts the two stay equal — so a Toggle count set beside a Button count is indistinguishable and cannot drift unnoticed, while a service can still move one without the other. • COLOUR is genuinely different, and MEASURED so. Button's pill sits on a static variant surface and tints itself with a translucent foreground (`bg-primary-foreground/15`, `bg-foreground/8`). Toggle's pill sits on a surface that INVERTS when pressed, and a translucent tint over it cannot clear WCAG 1.4.3 AA at the xs step: with the shipped roles, `--primary-foreground` over `--primary-foreground/0.16` over `--primary` measures 3.82:1 in light (4.39:1 even at 0.08 — the ceiling is the chip label's own 5.04:1, and any tint can only lower it), and `--muted-foreground` over `--foreground/0.08` measures 4.32:1, dropping to 3.64:1 once the chip hovers to `--accent`. Forcing a shared colour token here would ship a known #299-class failure. So Toggle's pill uses OPAQUE role fills, which makes its contrast independent of the chip's variant and hover surface, and inverts them with the state: unpressed --foreground on --muted → 14.25:1 light · 12.40:1 dark pressed --primary on --primary-foreground → 5.04:1 light · 7.07:1 dark The pressed pair is the chip label's own pair, swapped — the pill is exactly as legible as the label it sits next to, never worse, under any theme that keeps that pair legible. Every colour knob is a ROLE-MIRROR knob: `initial` at :root with the role default at the call site (docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\"). A `:root` binding to `var(--primary)` would freeze at the :root value and a scoped `[data-tenant]`/`.dark` override of the role would never reach it.",
    "name": "--toggle-pressed-count-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "── Pressed chrome. Default = hsl(var(--primary)), i.e. the pressed fill itself, so out of the box this border is quiet (#44) and the pressed state is carried by the fill inversion + the pill inversion + the forced-colors rule below. A service whose pressed fill is a PALE tint (where those inversions get weak) opts into a visible outline by overriding this.",
    "name": "--toggle-pressed-border-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--toggle-pressed-border-color-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Under forced-colors every fill is flattened to a system colour, so neither inversion encodes anything any more. This outline is the state's structural fallback there — drawn on the PRESSED pill only, and as `outline` (not `border`) so it costs no layout. default = var(--stroke-hairline), resolved at the call site (gh#906)",
    "name": "--toggle-count-forced-outline-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Row box height. MIRRORS THE `--control-height` TIER — the row is a control-sized hit target, and the tier is density-aware, so the height is never a literal and never an ad-hoc `calc(var(--control-height) ± …)` (that re-derives a tier and drifts out of step with the controls beside it). `size` picks a NAMED step (`--control-height-{xs,sm,lg}`) at the call site; the tier is re-scoped by the auth shells, hence `initial` here. Documented default: --tree-node-height = var(--control-height).",
    "name": "--tree-node-height",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Indent per level. Drives `padding-inline-start` on the row — a LOGICAL property, so the outline flips under `dir=\"rtl\"` with no second rule.",
    "name": "--tree-indent-width",
    "tier": "component",
    "value": "var(--space-5)"
  },
  {
    "description": "Inline padding inside a row, the gap between switcher / checkbox / icon / label, and the row's corner. Pure geometry — no role to freeze, so these bind directly.",
    "name": "--tree-node-padding-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "TREE — the standalone, on-page WAI-ARIA \"Tree View\" (`src/components/data-display/tree.tsx`). Every value the tree paints is a knob (cardinal rule #45), and the defaults are the QUIETEST reading (#44): no rails, a muted disclosure glyph, a selected band that tints rather than inverts. A service retunes the whole outline in one place instead of forking a row. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE. A knob whose default is a role token or a RE-SCOPED tier may not be bound at `:root` — CSS substitutes the `var()` where it is DECLARED, so the value would freeze at `:root` and a scoped `[data-tenant]` / `.dark` / a shell that re-scopes `--control-height` would never reach it. @see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\".",
    "name": "--tree-node-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio))",
    "name": "--tree-node-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TREE — the standalone, on-page WAI-ARIA \"Tree View\" (`src/components/data-display/tree.tsx`). Every value the tree paints is a knob (cardinal rule #45), and the defaults are the QUIETEST reading (#44): no rails, a muted disclosure glyph, a selected band that tints rather than inverts. A service retunes the whole outline in one place instead of forking a row. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE. A knob whose default is a role token or a RE-SCOPED tier may not be bound at `:root` — CSS substitutes the `var()` where it is DECLARED, so the value would freeze at `:root` and a scoped `[data-tenant]` / `.dark` / a shell that re-scopes `--control-height` would never reach it. @see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\".",
    "name": "--tree-node-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "The disclosure triangle (NameThatUI: \"disclosure triangle\"; an indented tree that expands is an \"Outline View\"). Its box is what makes the switcher a real 24px-class target inside the row, so it is a knob, not a hardcoded icon size.",
    "name": "--tree-switcher-size",
    "tier": "component",
    "value": "1.25rem"
  },
  {
    "description": "Documented default: --tree-switcher-color = hsl(var(--muted-foreground)).",
    "name": "--tree-switcher-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Node glyph (`showIcon`, and the folder/file pair of `variant=\"directory\"`).",
    "name": "--tree-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "Documented default: --tree-line-color = hsl(var(--border)).",
    "name": "--tree-line-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Documented default: --tree-divider-color = hsl(var(--border)).",
    "name": "--tree-divider-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Row states. Both mirror roles, so both are `initial` with the role read at the call site. Documented defaults: --tree-node-hover-background = hsl(var(--accent)); --tree-node-selected-background = hsl(var(--accent)); --tree-node-selected-foreground = hsl(var(--accent-foreground)).",
    "name": "--tree-node-hover-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--tree-node-hover-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TREE — the standalone, on-page WAI-ARIA \"Tree View\" (`src/components/data-display/tree.tsx`). Every value the tree paints is a knob (cardinal rule #45), and the defaults are the QUIETEST reading (#44): no rails, a muted disclosure glyph, a selected band that tints rather than inverts. A service retunes the whole outline in one place instead of forking a row. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE. A knob whose default is a role token or a RE-SCOPED tier may not be bound at `:root` — CSS substitutes the `var()` where it is DECLARED, so the value would freeze at `:root` and a scoped `[data-tenant]` / `.dark` / a shell that re-scopes `--control-height` would never reach it. @see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\".",
    "name": "--tree-node-selected-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = 100% at the call site",
    "name": "--tree-node-selected-background-alpha",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TREE — the standalone, on-page WAI-ARIA \"Tree View\" (`src/components/data-display/tree.tsx`). Every value the tree paints is a knob (cardinal rule #45), and the defaults are the QUIETEST reading (#44): no rails, a muted disclosure glyph, a selected band that tints rather than inverts. A service retunes the whole outline in one place instead of forking a row. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE. A knob whose default is a role token or a RE-SCOPED tier may not be bound at `:root` — CSS substitutes the `var()` where it is DECLARED, so the value would freeze at `:root` and a scoped `[data-tenant]` / `.dark` / a shell that re-scopes `--control-height` would never reach it. @see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\".",
    "name": "--tree-node-selected-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Label of a node `filterTreeNode` matched (antd `.filter-node` title: primary colour, strong weight). A role mirror, so `initial` with the role at the call site. Documented default: --tree-node-filter-foreground = hsl(var(--text-brand, var(--primary))).",
    "name": "--tree-node-filter-foreground",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Drop indicator of a `draggable` tree (gh#1093): the gap line / inside frame. A role mirror, so `initial` with the role at the call site. Documented defaults: --tree-drop-indicator-color = hsl(var(--primary)); --tree-drop-indicator-width = var(--stroke-md).",
    "name": "--tree-drop-indicator-color",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "TREE — the standalone, on-page WAI-ARIA \"Tree View\" (`src/components/data-display/tree.tsx`). Every value the tree paints is a knob (cardinal rule #45), and the defaults are the QUIETEST reading (#44): no rails, a muted disclosure glyph, a selected band that tints rather than inverts. A service retunes the whole outline in one place instead of forking a row. ROLE-MIRROR KNOBS ARE `initial`, WITH THE DEFAULT AT THE CALL SITE. A knob whose default is a role token or a RE-SCOPED tier may not be bound at `:root` — CSS substitutes the `var()` where it is DECLARED, so the value would freeze at `:root` and a scoped `[data-tenant]` / `.dark` / a shell that re-scopes `--control-height` would never reach it. @see docs/TOKENS.md · \"Role-mirror knobs MUST be `initial`\".",
    "name": "--tree-drop-indicator-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Width of the indeterminate bar shown while `loadData` resolves a branch. A fraction, not a length: it has to read as \"part of a row\" at every row width and every density.",
    "name": "--tree-loading-bar-inline-size",
    "tier": "component",
    "value": "40%"
  },
  {
    "description": "DROPZONE — the large drag target. Its inset is deliberately generous; a dense service dials it back with one override instead of forking the variant.",
    "name": "--upload-dropzone-space-inset",
    "tier": "component",
    "value": "var(--space-10)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--upload-dropzone-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--upload-dropzone-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-dropzone-icon-size",
    "tier": "component",
    "value": "var(--icon-size-3xl)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-dropzone-hint-space-block-start",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-dropzone-hint-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-dropzone-meta-space-block-start",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-dropzone-meta-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "TILE — the 96px square shared by picture-card thumbnails and the \"add image\" button. One knob resizes the whole gallery; picture-card grids are the most common thing a service re-grids to match its own column rhythm.",
    "name": "--upload-tile-size",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--upload-tile-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-tile-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-tile-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xl)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-tile-label-space-block-start",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-tile-label-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-tile-overlay-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "Busy scrim over a tile/frame — role-mirror knob, `initial` so --background re-resolves at the CALL SITE under a scoped [data-tenant]/.dark theme. Default = hsl(var(--background) / 0.7).",
    "name": "--upload-overlay-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-overlay-alpha",
    "tier": "component",
    "value": "70%"
  },
  {
    "description": "REMOVE affordance — the ✕ / trash chip pinned to a tile or avatar.",
    "name": "--upload-remove-space-inset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-remove-offset",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-remove-icon-size",
    "tier": "component",
    "value": "var(--icon-size-sm)"
  },
  {
    "description": "PICTURE — the single wide preview variant.",
    "name": "--upload-picture-max-width",
    "tier": "component",
    "value": "20rem"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--upload-picture-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-preview-max-height",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-empty-height",
    "tier": "component",
    "value": "8rem"
  },
  {
    "description": "The empty-state mark. It was `controlIconClass` — a CONTROL height (32px) leaking into a media placeholder, and 32 is not a step of the icon scale at all. The 128px-tall empty box sits between the 96px tile (24) and the 185px dropzone (40), so its mark does too.",
    "name": "--upload-picture-icon-size",
    "tier": "component",
    "value": "var(--icon-size-2xl)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-empty-label-space-block-start",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-empty-label-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-overlay-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "\"Pending replace\" chip. The radius previously came from a bare `rounded`, which resolves to a flat .25rem and so ignored the radius scale entirely — the exact shape of a rule #44 miss. It now follows the tile radius like every other chip in the component. gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--upload-picture-badge-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-badge-offset",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-badge-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-badge-space-block",
    "tier": "component",
    "value": "0.125rem"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-picture-badge-font-size",
    "tier": "component",
    "value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
  },
  {
    "description": "AVATAR — the round single-image variant.",
    "name": "--upload-avatar-size",
    "tier": "component",
    "value": "6rem"
  },
  {
    "description": "The camera mark inside the empty avatar. Same step as --upload-tile-icon-size on purpose: the avatar and the picture-card tile are the SAME 96px box, and they were drawing 32 and 24.",
    "name": "--upload-avatar-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xl)"
  },
  {
    "description": "default = var(--stroke-md), resolved at the call site (gh#906)",
    "name": "--upload-avatar-border-width",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-avatar-change-space-block",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "The \"change\" strip sits ON the photo, so its scrim is intentionally a fixed dark wash rather than a surface role — it must stay legible over an arbitrary user image in either theme.",
    "name": "--upload-avatar-change-background",
    "tier": "component",
    "value": "rgb(0 0 0 / 0.7)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-avatar-change-foreground",
    "tier": "component",
    "value": "#fff"
  },
  {
    "description": "Alpha of an image the user has marked for deletion but not yet committed.",
    "name": "--upload-avatar-pending-delete-alpha",
    "tier": "component",
    "value": "0.4"
  },
  {
    "description": "DRAFT BAR — the undo strip shown after a pending remove/replace.",
    "name": "--upload-draft-space-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-draft-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-draft-space-gap",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--upload-draft-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-draft-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-draft-icon-size",
    "tier": "component",
    "value": "var(--icon-size-sm)"
  },
  {
    "description": "FILE ROW — the list rendered under the dropzone/button variants.",
    "name": "--upload-row-space-inline",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-row-space-block",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-row-space-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = calc(var(--radius) / var(--radius-ratio))",
    "name": "--upload-row-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-row-font-size",
    "tier": "component",
    "value": "var(--font-size-sm, var(--font-size-base))"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-row-icon-size",
    "tier": "component",
    "value": "var(--icon-size-md)"
  },
  {
    "description": "CROP DIALOG — the 1:1 avatar cropper (`UploadCropDialog`). The 66-literal upload pass above never reached this file, so the whole cropper was still baked on the component: the dialog was pinned to `max-w-sm`, the round preview to `size-48`, the zoom row to `px-2`. An avatar is one of the most service-specific sizes there is (a 96px tile service wants a smaller crop stage than a 200px one), and the crop stage must stay in proportion with --upload-avatar-size — which is exactly the pair rule #45 exists to keep tunable together. The dialog width intentionally stays a knob of its own rather than reading --dialog-width-default: the cropper is deliberately NARROWER than a normal dialog so the round stage reads as the subject, not as a small element in a wide box.",
    "name": "--upload-crop-dialog-max-width",
    "tier": "component",
    "value": "24rem"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-crop-preview-size",
    "tier": "component",
    "value": "12rem"
  },
  {
    "description": "Upload primitive tokens — dropzone, picture tile, avatar, draft bar, file row. Upload carried 66 hard-coded geometry/chrome literals, the single worst file in the library (#319). It renders five variants (dropzone · button · picture · picture-card · avatar), and EVERY one of them baked its box straight onto the component: a service could not resize the avatar, retune the dropzone's generous 40px inset, or align the file row to its own grid without forking. That is precisely the gap cardinal rule #45 exists to close. Radius defaults mirror the utilities they replace, verified against the built CSS: rounded-lg = var(--radius) → --radius-lg rounded-md = calc(var(--radius) / var(--radius-ratio)) → --radius-md rounded-full → --radius-pill",
    "name": "--upload-crop-preview-radius",
    "tier": "component",
    "value": "var(--radius-pill)"
  },
  {
    "description": "Zoom row inset — the slider is inset from the dialog edge so its thumb's focus ring is never flush against the dialog padding.",
    "name": "--upload-crop-zoom-space-inline",
    "tier": "component",
    "value": "var(--space-2)"
  },
  {
    "description": "Gap between the glyph column and the text column.",
    "name": "--welcome-gap",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Gap between the title row and the description.",
    "name": "--welcome-content-gap",
    "tier": "component",
    "value": "var(--space-1)"
  },
  {
    "description": "Gap between the title and the `extra` slot on the title row.",
    "name": "--welcome-title-gap",
    "tier": "component",
    "value": "var(--space-3)"
  },
  {
    "description": "Inset of the `filled` form. `borderless` drops it to zero.",
    "name": "--welcome-padding-block",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "Welcome component tokens — the greeting block at the head of an empty conversation (Ant Design X `Welcome`). Ant X retunes this block through `styles={{ root, icon, title, description, extra }}`. This file is the answer instead (rules #44/#45): a service sets the knob once in its theme.css and every Welcome on every surface follows.",
    "name": "--welcome-padding-inline",
    "tier": "component",
    "value": "var(--space-4)"
  },
  {
    "description": "gh#888 — φ tier freezes at :root; default = var(--radius)",
    "name": "--welcome-radius",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "The glyph column. A square, so an image icon and an SVG icon occupy the same track.",
    "name": "--welcome-icon-size",
    "tier": "component",
    "value": "var(--icon-size-xl)"
  },
  {
    "description": "`filled` chrome. Role-mirror knobs (docs/TOKENS.md): `initial` so the documented default resolves at the CALL SITE and a scoped `[data-tenant]` / `.dark` override still reaches it. Default ground = hsl(var(--muted))",
    "name": "--welcome-filled-background",
    "tier": "component",
    "value": "initial"
  },
  {
    "description": "`outlined` is not an Ant X variant; the hairline below belongs to `filled` only.",
    "name": "--welcome-filled-border",
    "tier": "component",
    "value": "initial"
  }
]
