# xmesh design tokens — Material Design 3 reference

The role tier is **canonical Material Design 3**. Components reference `--md-sys-*`
(canonical MD3 system tokens) and `--xm-*` (xmesh extensions for non-MD3 concepts).
Primitives (`--x-*`) are not part of this contract — they exist as the source of
truth (`_primitives.css`) and feed the MD3 layer below.

Theme switches via `<html data-theme="dark|light">` (default: dark). Primitives
flip per theme; the MD3 role tokens stay constant.

---

## `--md-sys-color-*` — Material Design 3 color (`md3/_color.css`)

### Surface family — the "desk"

| Token | Role |
| --- | --- |
| `--md-sys-color-background` | Top-level page background. |
| `--md-sys-color-surface` | Default surface — chat shell, sidebar, top bar. |
| `--md-sys-color-on-surface` | Primary text/icon on `surface*`. |
| `--md-sys-color-on-surface-variant` | Secondary text/icon on `surface*`. |
| `--md-sys-color-surface-variant` | Lower-emphasis surface variant. |
| `--md-sys-color-surface-dim` | Recessed area behind cards. |
| `--md-sys-color-surface-bright` | Most-elevated reading surface. |
| `--md-sys-color-surface-container-lowest` | Trough (sidebar hover, user bubble recess). |
| `--md-sys-color-surface-container-low` | Slight raise (composer rest, bot bubble). |
| `--md-sys-color-surface-container` | Default container tier. |
| `--md-sys-color-surface-container-high` | Composer field, drawer chrome, snackbar bg. |
| `--md-sys-color-surface-container-highest` | Hover/active raised tier. |

### Inverse surface — the "card stack"

| Token | Role |
| --- | --- |
| `--md-sys-color-inverse-surface` | The card / drawer / popover / composer tier. |
| `--md-sys-color-inverse-on-surface` | Text/icon on `inverse-surface`. |
| `--md-sys-color-inverse-primary` | Primary action sitting on `inverse-surface`. |

### Outline

| Token | Role |
| --- | --- |
| `--md-sys-color-outline-variant` | Default 1px hairline. |
| `--md-sys-color-outline` | Hover / emphasized borders. |

### Primary (the coral accent)

| Token | Role |
| --- | --- |
| `--md-sys-color-primary` | Coral CTA / focus border source. |
| `--md-sys-color-on-primary` | Text/icon on `primary` (white). |
| `--md-sys-color-primary-container` | Tinted accent — focus halo, selected pill. |
| `--md-sys-color-on-primary-container` | Text/icon on `primary-container`. |

### Secondary (defined, unused in components)

| Token | Role |
| --- | --- |
| `--md-sys-color-secondary*` | Deep olive — kept for canonical MD3 compliance. |

### Tertiary

Alias of secondary; reserved for future categorical accent. Components must not
reference unless adding a documented categorical role.

### Error (defined, FORBIDDEN in components)

| Token | Role |
| --- | --- |
| `--md-sys-color-error*` | Red severity stack. **POLICIES.md rule 3a** forbids component references — severity is icon + copy. |

### Utility

| Token | Role |
| --- | --- |
| `--md-sys-color-scrim` | Modal backdrop. Apply alpha at use site. |
| `--md-sys-color-shadow` | Shadow base color. |

---

## `--xm-*` — xmesh extensions (`_xmesh-extensions.css`)

Non-MD3 concepts kept under their own namespace so canonicality is preserved.

### Surface / on-surface auxiliary tiers

| Token | Role |
| --- | --- |
| `--xm-color-on-surface-soft` | Fourth on-surface tier — meta text. (MD3 ships only two.) |
| `--xm-color-inverse-on-surface-muted` | Third inverse-on-surface tier. |
| `--xm-color-primary-pressed` | Pressed primary fill (MD3 has no "strong" tier). |
| `--xm-color-bubble-outline` | Slightly stronger user-bubble hairline. |
| `--xm-color-paper` | Warm cream artboard for design previews. |

### Categorical badges (category, not severity)

`--xm-method-{get,post,put,delete,patch}-{bg,ink}` — HTTP method badges.
`--xm-ext-{yml,json}-{bg,ink}` — file-extension badges.

### Snackbar scrim (the single intentional gradient)

`--xm-snackbar-scrim*` — three-stop neutral backdrop behind snackbars.

### Photo overlay

`--xm-photo-overlay` / `-ink` — image artifact backdrop.

### Mono typescale

`--xm-typescale-mono-{font,size,line-height,tracking,weight}` — JetBrains Mono.
MD3 has no mono concept.

### Data density tier (ADR 0040)

`--xm-typescale-grid-{cell,mono,header,totals,band,control}-*` — the reading ramp
of a **data surface**: 14/22 body, 13.5/22 mono, 13/18 headers, 13/20 totals,
10/30 band, 11/1 dense controls. `--xm-shape-corner-{hairline,dense-xs,dense-sm,
dense-md,dense-lg}` (1–5 px) is its corner ramp — the MD3 shape scale jumps
straight from `none` to `extra-small` (6 px), which is too coarse for a 17 px
twisty or a 20 px toolbar button.

A data surface is a table you *work* — scan, sort, compare, reconfigure — not a
table you read past in prose. Every `<xm-data-table>` and `<xm-data-grid>` is one
and gets this tier automatically (`.data-table--dense`). `<xm-table>` is a content
table and stays on `--md-sys-typescale-body-medium`; that asymmetry is the point of
the tier, not an oversight.

Referenced only by `xm-data-table` and `xm-data-grid`. A third dense surface
should reference these tokens rather than copy the values; anything outside a data
surface belongs on the MD3 typescale.

### Wordmark

`--xm-typescale-wordmark-*` — display family at button size, weight 500, lh 1.

### xmesh-specific elevations

| Token | Role |
| --- | --- |
| `--xm-elevation-drawer` | Directional shadow for slide-in drawers. |
| `--xm-elevation-snackbar` | Composite snackbar shadow + rim. |
| `--xm-elevation-pressed` / `-soft` | Inset shadow for the button :active feel. |

### Focus ring

`--xm-state-focus-ring` — 1px halo of `--md-sys-color-primary-container`.

### Switch (`xm-switch`)

MD3 ships no switch role tokens, so the off-track fill + thumb shadow live as
extensions. On-track is the coral `--md-sys-color-primary`; the thumb uses MD3
roles directly (`--md-sys-color-outline` when off, `--md-sys-color-on-primary`
when on).

| Token | Role |
| --- | --- |
| `--xm-switch-track-off` | Off-track fill — muted neutral on the inverse-surface card. |
| `--xm-switch-thumb-shadow` | Thumb drop shadow so it reads above either track. |

### Slider (`xm-slider`)

MD3 ships no slider role tokens. The active fill + thumb are the coral
`--md-sys-color-primary`; these are the sub-values with no MD3 home.

| Token | Role |
| --- | --- |
| `--xm-slider-track-inactive` | Unfilled track color — muted neutral on the inverse-surface card. |
| `--xm-slider-track-height` | Track thickness (4px). |
| `--xm-slider-thumb-size` | Thumb diameter (16px). |
| `--xm-slider-thumb-shadow` | Thumb drop shadow so it reads above the track. |

### Overlay stacking tier

`--xm-overlay-z-tooltip` (1000) `<` `--xm-overlay-z-menu` (1100) `<`
`--xm-overlay-z-dialog` (1200) — the fixed stacking order for `xm-overlay`
non-modal popovers (AD-5a): a menu always sits above a tooltip. Modal
`<dialog>`s ride the native top layer above every popover by spec, so they
need no z-index. An escape-hatch Floating-UI-positioned overlay must reuse
these values, never invent its own z-index.

---

## `--xm-*` layout tokens (`_layout.css`)

The layout tier — breakpoints, the content reading width, and grid gutters.
Consumed by `xm-grid` / `xm-stack` and available to any component. Gutters
alias the `--s-N` ladder (no new px); layout is theme-invariant (no light
override).

### Breakpoints

| Token | Value | Formalizes |
| --- | --- | --- |
| `--xm-breakpoint-sm` | `520px` | alert compact row |
| `--xm-breakpoint-md` | `640px` | snackbar / condensed layouts |

> **Caveat — `@media` cannot read these.** A CSS `@media` (or `@container`)
> condition does not resolve `var()`, so `@media (max-width: var(--xm-breakpoint-sm))`
> is invalid and silently fails. These tokens are the documented **source of
> truth**; each `@media` block repeats the literal with a comment citing the
> token (see `alert/index.css`, `snackbar/index.css`, `grid/index.css`). They
> ARE usable wherever `var()` works — `max-width`, `width`, JS
> `getComputedStyle`. See `docs/adr/0001`.

### Container

| Token | Value | Role |
| --- | --- | --- |
| `--xm-container-max` | `720px` | Comfortable reading column (chat thread + bubbles). Usable directly in `max-width`. |

### Grid gutters (alias `--s-N`)

| Token | Aliases | Value |
| --- | --- | --- |
| `--xm-gutter-none` | — | `0` |
| `--xm-gutter-xs` | `--s-1` | `4px` |
| `--xm-gutter-sm` | `--s-2` | `8px` |
| `--xm-gutter-md` | `--s-4` | `16px` (default grid / stack gap) |
| `--xm-gutter-lg` | `--s-6` | `24px` |
| `--xm-gutter-xl` | `--s-8` | `32px` |

---

## `--md-sys-typescale-*` — Material Design 3 type (`md3/_type.css`)

15 roles × 5 sub-tokens. Each role exposes `-font`, `-size`, `-line-height`,
`-tracking`, `-weight`. Compose into `font:` shorthand or reference sub-tokens
directly. The xmesh chat overrides several MD3 sizes for chat density (see
plan + inline comments in `md3/_type.css`).

### Roles

| Role | Family | Size (px) | Use |
| --- | --- | --- | --- |
| `display-large` | Source Serif 4 | 57 | Hero (unused in chat). |
| `display-medium` | Source Serif 4 | 45 | Hero (unused in chat). |
| `display-small` | Source Serif 4 | 36 | xmesh H1 (rounded up from 34). |
| `headline-large` | Source Serif 4 | 32 | xmesh H2. |
| `headline-medium` | Source Serif 4 | 22 | xmesh H3 (override of MD3 28). |
| `headline-small` | Source Serif 4 | 18 | xmesh H4 (override of MD3 24). |
| `title-large` | Source Serif 4 | 18 | xmesh title-large (override of MD3 sans). |
| `title-medium` | Inter | 15 | Card titles. |
| `title-small` | Inter | 14 | List-item titles. |
| `body-large` | Inter | 15 | xmesh prose baseline (override of MD3 16). |
| `body-medium` | Inter | 13 | UI rows. |
| `body-small` | Inter | 12 | Captions. |
| `label-large` | Inter | 15 | xmesh button text (override of MD3 14). |
| `label-medium` | Inter | 12 | Inline labels. |
| `label-small` | Inter | 11 | xmesh eyebrow (uppercase via helper class). |

### Composite shorthands (`styles/_type.css`)

`--t-h1` (display-small) · `--t-h2` (headline-large) · `--t-h3` (headline-medium) ·
`--t-h4` (title-large) · `--t-display` (headline-medium) · `--t-wordmark` ·
`--t-body` (body-large) · `--t-body-strong` · `--t-small` (body-small) ·
`--t-button` (label-large) · `--t-eyebrow` (label-small) · `--t-mono` (xmesh ext).

### Helper classes

`.x-h1` … `.x-h4`, `.x-display`, `.x-wordmark`, `.x-body`, `.x-small`,
`.x-eyebrow`, `.x-mono` — apply role shorthand + correct text color.

### Family primitives

`--t-family-display` (Source Serif 4 — display/headline), `--t-family-ui`
(Inter — title/body/label), `--t-family-mono` (JetBrains Mono — non-MD3, used
via `--xm-typescale-mono-font`).

---

## `--md-sys-shape-corner-*` — Material Design 3 shape (`md3/_shape.css`)

| Token | Value | Use |
| --- | --- | --- |
| `extra-small` | 6px | Square icon backplates (override of MD3 4). |
| `small` | 8px | Token chips, swatches. |
| `button` | 10px | Buttons, inputs (xmesh extension). |
| `medium` | 14px | Cards, drawers, modals (override of MD3 12). |
| `large` | 18px | Chat bubbles (override of MD3 16). |
| `extra-large` | 20px | Composer card (override of MD3 28). |
| `full` | 9999px | Pills, dots, scrollbar thumbs. |

---

## `--s-N` — spacing (`_space.css`)

4px base scale (xmesh primitive — MD3 has no spacing scale): `--s-1` 4px,
`--s-2` 8px, `--s-3` 12px, `--s-4` 16px, `--s-5` 20px, `--s-6` 24px,
`--s-8` 32px, `--s-10` 40px, `--s-12` 48px.

---

## `--md-sys-elevation-level0..5` — Material Design 3 elevation (`md3/_elevation.css`)

| Token | dp | Use |
| --- | --- | --- |
| `level0` | 0 | Flat — default buttons, idle composer. |
| `level1` | 1 | Inline chips, file rows. |
| `level2` | 3 | Default card lift. |
| `level3` | 6 | Menus, popovers. |
| `level4` | 8 | Drawers (composes with `--xm-elevation-drawer`). |
| `level5` | 12 | Top-most popovers. |

Pressed states use `--xm-elevation-pressed` (inset). Focus rings use
`--xm-state-focus-ring`. Snackbar uses `--xm-elevation-snackbar` for the
composite rim shadow.

---

## `--md-sys-motion-*` — Material Design 3 motion (`md3/_motion.css`)

### Durations

`short1` (50) · `short2` (100) · `short3` (150) · `short4` (200) · `medium1`
(250) · `medium2` (300) · `medium3` (350) · `medium4` (400) · `long1..4`
(450/500/550/600) · `extra-long1..4` (700/800/900/1000).

### Easing

`linear` · `standard` · `standard-accelerate` · `standard-decelerate` ·
`emphasized` · `emphasized-accelerate` · `emphasized-decelerate`.

Default for hover/focus is `standard` at `short3` (150ms). Slide-ins use
`emphasized-decelerate`.

### Legacy aliases (`styles/_space.css`)

`--m-fast` → `short3`, `--m-base` → `short4`, `--m-slow` → `medium1`,
`--m-ease` → `easing-standard`, `--m-ease-out` → `easing-emphasized-decelerate`.
These delete in the lockdown phase.

---

## `--md-sys-state-*` — state-layer opacities (`md3/_state.css`)

| Token | Value | Use |
| --- | --- | --- |
| `--md-sys-state-hover-state-layer-opacity` | 8% | Hover overlay. |
| `--md-sys-state-focus-state-layer-opacity` | 10% | Focus overlay. |
| `--md-sys-state-pressed-state-layer-opacity` | 10% | Pressed overlay. |
| `--md-sys-state-dragged-state-layer-opacity` | 16% | Drag overlay. |

Compose into a `color-mix()` recipe over the resting background:

```css
background-color: color-mix(
  in oklab,
  var(--md-sys-color-on-surface) var(--md-sys-state-hover-state-layer-opacity),
  var(--md-sys-color-surface)
);
```

---

## What you don't reference from a consuming site

- **`--x-*`** primitives — the palette source. They swap under `data-theme`;
  downstream code should not pin to these.
- **`--md-sys-color-error*`** — defined for canonical compliance, forbidden in
  components. Severity stays icon + copy.

If a role you need doesn't exist at `--md-sys-*`, check `--xm-*` first; if
neither has it, add it to `_xmesh-extensions.css` (don't pretend it's MD3) or
open a discussion.
