# xmesh Design System

A design system extracted from the **xmesh chat** product — a desktop AI-chat
shell with smart routing, agent traces, and a settings drawer for editing
agent definitions. The system is built around a **warm dark canvas with white
card surfaces** and a **coral accent** (`#cc785c`, ~40°), theme-flippable to a cream-light
mode.

Strict editing rules live in **[POLICIES.md](./POLICIES.md)**. The visual
target — palette, type, surface ramp, voice, anti-patterns — is documented
in this file (sections **CONTENT FUNDAMENTALS**, **VISUAL FOUNDATIONS**,
**ICONOGRAPHY** below); the token catalogue with one-line roles per token is
in **[`styles/README.md`](styles/README.md)**.

## Sources

This system was built from the following materials:

| Source | Path / link | Notes |
| --- | --- | --- |
| Source codebase | `sergeytkachenko/langgraph_smart_routing` (GitHub) | LangGraph-based smart-routing agent platform |
| Existing docs / system | `docs/desing-system/` (in repo, in the original tree — note the typo `desing`) | Tokens, themes, components, preview canvas |
| Chat composition components | `packages/shared/components/chat/latest/` | Live composer / sidebar / message list |
| Reference screenshot | `docs/desing-system/uploads/chat_desired_styles.jpg` | Canonical composer styling |

The original `docs/desing-system/` folder (with its typo) lives in the source
repo only — it is **not** carried into this repo. This design-system folder is
the **published + cleaned** version, now migrated to **canonical Material
Design 3** at the role tier (`--md-sys-color-*`, `--md-sys-typescale-*`,
`--md-sys-shape-corner-*`, `--md-sys-elevation-level*`, `--md-sys-motion-*`).
xmesh-specific concepts that have no MD3 home (mono typescale, categorical
badges, paper artboard, snackbar scrim, drawer shadow, focus ring) live
under the `--xm-*` namespace. Spacing stays as the xmesh `--s-N` 4px
primitive scale (MD3 has no spacing scale). The legacy `--c-*` / `--t-*` /
`--r-*` / `--e-*` / `--m-*` namespaces survive in `styles/_semantic.css`
etc. as transitional aliases that delete in the lockdown phase. Primitives
(`--x-*`) feed the MD3 layer once and are not referenced from components.

## Index

| File / folder | Purpose |
| --- | --- |
| `styles/` | The real token system, split by responsibility (`_primitives.css`, `_semantic.css`, `_type.css`, `_space.css`, `_elevation.css`, `_fonts.css`, `_scroll.css`), wired by `styles/index.css`. Token catalogue in `styles/README.md`. |
| `colors_and_type.css` | Back-compat shim — only does `@import "./styles/index.css"`. Kept so older HTML keeps working. |
| `assets/` | Brand mark + lockups (SVG only). |
| `fonts/` | Intentionally empty — Inter and JetBrains Mono pull from Google Fonts via `_fonts.css`. |
| `lit/components/` | One folder per component, each with `index.css` + `index.ts`: `artifact`, `brand-mark`, `bubble`, `button`, `chat`, `composer`, `primitives`, `sidebar-item`, `snackbar`, `validation`. TS is the canonical source. Each component exposes a custom element named `xm-<name>`. `lit/components/types/` holds shared `.d.ts` shims (Lit-from-esm.sh re-export). |
| `lit/preview/` | Cards rendered on the **Design System** tab (one concept each). Loads `card.css` for the page scaffold, `_shell.{css,js}` for the page chrome and `xmesh.mount()` helper, and `theme-toggle.js` for dark/light persistence. |
| `lit/build/` | Compiled `.js`, mirrors `lit/components/`. Git-ignored — produced by `tsc`. Previews `<script type="module">`-load from here. |
| `scripts/` | Lint/check scripts (`check-tokens.sh`, `check-structure.sh`, `check-slots.sh`, `check-previews.sh`, `check-bem.sh`, and the rest — `check.sh` is the run-everything wrapper) and `screenshot.mjs` (Playwright). |
| `package.json` | npm scripts: `serve` (tsc-watch + http-server), `build:lit` / `watch:lit`, `screenshot` / `shoot-all`, `check[:tokens\|:structure\|:slots\|:previews\|:bem]`. Runtime devDeps: `typescript`, `npm-run-all`, `lit` (types only), `playwright`, `http-server`. |
| `SKILL.md` | Agent-skill manifest, makes this package usable as a Claude Code skill. |

> **Earlier React port removed.** Until recently this repo also shipped a React port at `components/` + `preview/` (JSX-as-canonical-source, no build step). Commits `91da854` (split into `react/` + `lit/`), `6f68d05` (move React side to `legacy-react/`), and `4b2d9ba` (delete `legacy-react/`) retired it. References below to JSX components are historical context only — the live tree is `lit/`.

---

## Use this in another site

Two ways to consume, depending on what you need: the **tokens only** (any
site), or the **tokens + Lit components** as the npm package
`@xmesh/system-design` (bundler-based projects).

### Tokens only (any site)

The public entry point is **`styles/index.css`**. It pulls in fonts,
primitives, semantic tokens, type, spacing, elevation, and the legacy
shim — everything a consuming site needs.

```css
/* in your site's global CSS */
@import "path/to/xmesh-system-design/styles/index.css";

:root { /* default = dark theme */ }
:root[data-theme="light"] { /* set on <html> to flip */ }
```

Reference only the documented tiers:

| Tier | Prefix | What it is |
| --- | --- | --- |
| Color (MD3) | `--md-sys-color-*` | Surface ramp, on-* roles, primary/secondary/error, outline. Canonical Material Design 3. |
| Color (xmesh ext) | `--xm-color-*`, `--xm-method-*`, `--xm-ext-*` | Categorical badges, paper, on-surface third tier, primary-pressed. Non-MD3 concepts. |
| Type | `--md-sys-typescale-*` | 15 MD3 type roles × 5 sub-tokens. Composite shorthands `--t-*` for legacy callsites. |
| Radius | `--md-sys-shape-corner-*` | `extra-small`, `small`, `button`, `medium`, `large`, `extra-large`, `full` |
| Spacing | `--s-1` … `--s-12` | 4px-base scale (xmesh primitive — MD3 has no spacing scale). |
| Elevation | `--md-sys-elevation-level0..5` | Shadows. xmesh-specific drawer/snackbar/focus-ring under `--xm-*`. |
| Motion | `--md-sys-motion-duration-*` / `-easing-*` | MD3 duration scale + 7 easing curves. |

**Never reference `--x-*`** — those are primitives, used by `_semantic.css`
internally. Components and consuming sites use the semantic tier.

The full token catalogue with one-line roles is in **[`styles/README.md`](styles/README.md)**.

### Tokens + Lit components (npm package)

To consume the actual `<xm-*>` components in a **bundler-based** project
(Vite / webpack 5), install the published package and the `lit` peer:

```bash
npm install @xmesh/system-design lit
```

The package ships the prebuilt ESM bundle (`dist/lit/`, co-located CSS, and
`.d.ts`) — it's built at publish time, so there's nothing to compile on
install. Then, once at app root:

```ts
import "@xmesh/system-design/styles";   // tokens → :root (required, once, before first paint)
import "@xmesh/system-design/lit";      // registers every <xm-*> element
document.documentElement.dataset.theme = "dark"; // or "light"
// or tree-shaken: import "@xmesh/system-design/lit/button";
```

```html
<xm-button variant="primary">Send</xm-button>
```

The full consumer guide (subpath imports, TypeScript types, version pinning,
and using the web components inside React/Vue/Angular) is in
**[`lit/README.md`](lit/README.md)**; the
rationale and the build/distribution decisions are in
**[ADR 0004](docs/adr/0004-bundler-consumable-component-library.md)** (now
superseded by **[ADR 0007](docs/adr/0007-distribute-via-npm-package.md)**).

### Customization via slots

This is a **public, customizable system** — consumers are expected to put
their own content inside the components, and **slots are the primary seam**
for doing it. Attributes/properties configure a component; slots let you
*compose* it: your icons, your action buttons, your headers and empty
states, your markup inside the default slot.

```html
<xm-button variant="primary">
  <xm-send-icon slot="icon-left"></xm-send-icon>
  Send
</xm-button>

<xm-alert severity="warning">
  Draft not saved
  <xm-button slot="action" variant="ghost">Retry</xm-button>
  <xm-button slot="action" variant="ghost">Discard</xm-button>
</xm-alert>
```

Because slots are public API, their names are a **fixed, machine-enforced
vocabulary** ([ADR 0018](docs/adr/0018-slot-vocabulary-and-singular-action.md),
`npm run check:slots`) — the same name means the same thing on every
component, and shipped slot names don't churn under consumers:

| Slot | Role |
| --- | --- |
| *(default)* | Primary content |
| `icon-left` / `icon-right` | Inline icons |
| `header` / `footer` / `leading` / `trailing` | Structural regions |
| `action` | Trailing actions — **singular** name, multiple children allowed (`slot="actions"` does not exist; content addressed to it falls silently into the default slot) |
| `trigger` | Overlay anchor (`xm-menu` / `xm-popover` / `xm-tooltip`) |
| `empty` / `empty-action` / `detail` | `xm-data-table` empty region and row drill-in |
| `prefix` / `suffix` / `secondary` / `icon` / `tab` / `control` / `search` | Per-component seams (`xm-text-field`, `xm-list-item`, `xm-empty-state`, `xm-tabs`, `XmField` subclasses, `xm-multi-select`) |

Slots ship with sensible fallback content where it exists (e.g.
`xm-multi-select`'s `search` slot falls back to its built-in
`xm-text-field`, [ADR 0024](docs/adr/0024-multi-select-customization-seams.md)) —
slot something only when you need to replace the default. A few families
deliberately expose **no** author-facing slots and are customized through
properties instead: the data-only components
([ADR 0008](docs/adr/0008-xm-table-data-only-no-slot.md)) and the light-DOM
snapshot trio `artifact` / `chat` / `bubble`.

The normative rules (registry, breaking-change discipline, when a new slot
name is allowed) are POLICIES.md rules 6b–6d; the authoring-side summary is
in [AGENTS.md](AGENTS.md) "Canonical slot names".

### Visual feedback for Claude Code

`npm run screenshot <preview.html>` renders any preview in dark + light
themes via Playwright and writes PNGs to `screenshots/`. Claude Code's
`Read` tool can open those PNGs directly. Use `npm run shoot-all` to
regenerate every preview's screenshot set.

`npm run check` runs every deterministic guard under `scripts/check-*.sh`
in sequence (thirteen today — see `scripts/check.sh` for the full roster).
The ones you'll hit first:

- **`check:tokens`** — `lit/components/*/index.css` for raw hex / `oklch()` /
  `rgb()` / `hsl()` literals, `--x-*` primitive references that bypass the
  semantic tier, and the deleted legacy `--p-*` / `--s-{surface,…}-*`
  aliases.
- **`check:structure`** — every component is `lit/components/<name>/index.{css,ts}`,
  no other `.css` / `.ts` siblings in the same folder, with
  `lit/components/types/` exempt for the shared Lit-CDN `.d.ts` shim.
- **`check:slots`** — slot names in `lit/components/*/index.{ts,css}` and
  `lit/preview/*.html` stay inside the sanctioned ADR 0018 registry, and
  the plural `actions` slot never reappears (POLICIES.md rules 6b–6c).
- **`check:previews`** — every `lit/preview/*.html` imports `card.css` and
  `theme-toggle.js`, and no `<link>` / `<script>` URL uses `?v=*`
  cache-busting (POLICIES.md rule 12a).
- **`check:bem`** — strict BEM in `lit/components/*/index.css`: `block`,
  `block__element`, `block--modifier`; state classes (`.is-*`, `.has-*`)
  must combine with a block; no bare tag selectors; no cross-block
  descendant chains except those allow-listed in `scripts/check-bem.sh`.

Each sub-check is also runnable individually:
`npm run check:tokens` / `:structure` / `:slots` / `:previews` / `:bem`.
Run `npm run check` before committing.

The strict rules enforced by these checks (and the manual ones that
aren't) are documented in **[POLICIES.md](./POLICIES.md)**.

---

## Brand at a glance

xmesh is a **single-product desktop chat** for an AI agent platform. It feels
like a sturdy, opinionated tool: a craftsman's terminal more than a SaaS
landing page. The mood is **warm, not cool** (coral accent, oklch hues
biased toward 40–80°), **dense, not airy** (small type, tight gutters, lots of
hairline borders), and **functional, not decorative** (no gradients, no
illustrations, almost no emoji).

Two themes ship: **dark** (default — warm desaturated near-black canvas with
lifted dark cards) and **light** (cream canvas with white cards and dark ink).
The card stack follows the theme rather than staying white in both ([ADR 0006](./docs/adr/0006-theme-aware-card-stack-surface.md)).
A `black` theme is referenced in the source for AMOLED contexts.

---

## CONTENT FUNDAMENTALS

### Voice

- **Direct and operational.** Copy describes what the surface does or what
  state it is in, not how the user should feel.  Examples from the source:
  - File picker hint: `"Choose file or drop here"` / `"YAML or JSON · up to
    200 KB"`
  - Composer footer: `"Enter to send · Shift+Enter for new line"`
  - Counter: `"4127 / 5000"` (raw numbers, no "characters used:")
  - Processing state: `"Routing query through Planning Path…"`
  - Stop hint: `"Click ▢ to cancel current request"`

- **System-as-narrator, not assistant.** Status strings describe the system in
  third person — `"Routing query through Planning Path…"`, not _"I'll route
  this for you."_

- **Validation titles are blunt nouns.** From `lit/components/validation/index.ts`
  (the `VALIDATION_TITLE` export): `"File too large"`, `"Wrong file type"`,
  `"Couldn't parse file"`, `"Unexpected structure"`, `"Empty file"`,
  `"Read error"`.  No exclamation marks, no apologies, no "Oops!".

### Casing

- **Sentence case** for everything. UI labels, buttons, headings, drawer
  titles — all sentence case.  `"New chat"`, `"Cancel current request"`,
  `"Routing query through Planning Path…"`.  Title Case is reserved for
  proper nouns (`"Planning Path"`, `"REST"`, `"GraphQL"`).

- **Caps for tech identifiers**: `YAML`, `JSON`, `REST`, `GraphQL`, `KB`.

- **No ALL-CAPS as styling.** The eyebrow type ramp uses uppercase + tracked
  letter-spacing, but the underlying string in source is sentence case.

### Pronouns

- **Imperative, no I/you** in inline copy. _"Choose file or drop here"_, not
  _"You can choose…"_.  The product never says "I".
- **Second-person ("you") only in long help/empty-state body copy** — kept
  rare.

### Typography of copy

- **Numbers + units side by side**: `"412 KB"`, `"200 KB"`, `"4127 / 5000"`.
  Use a normal space between number and unit.
- **Keyboard hints**: `Enter`, `Shift+Enter`, `⌘K` — rendered as small kbd
  pills, not bracketed.
- **Middots (`·`) separate inline metadata**: `"Enter to send · Shift+Enter
  for new line"`, `"8.4 KB · 4 agents, 12 tools"`.  Em-dashes (`—`) join
  clauses inside a single string.
- **Ellipsis is a single character** (`…`), not three dots. Used at the end
  of pending state strings.

### Emoji & emotional tone

- **No emoji in product UI.** The brand mark is geometric. The composer's
  send button is an arrow glyph; the stop button is a filled square. Status
  uses small dot indicators, not emoji.
- **Tone is matter-of-fact.** Errors describe the failure with the data
  (`"File is 412 KB. Maximum allowed size is 200 KB."`) instead of softening
  it. No "oops" / "uh-oh" / smiley — but also no scolding.

### Vibe summary

If xmesh copy were a person it would be a **senior infra engineer leaving a
helpful comment in a PR**: short, technical, no fluff, occasionally dry, never
cute.

---

## VISUAL FOUNDATIONS

### Color

- **Two surface families** — the **`surface`** desk (`--md-sys-color-surface`,
  warm near-black `oklch(0.21 0.003 60)` in dark, cream in light) and the
  **`inverse-surface`** card stack. The card stack is theme-following
  ([ADR 0006](./docs/adr/0006-theme-aware-card-stack-surface.md)): a lifted dark
  surface in dark theme, white in light. Every component sits on exactly one.
  Sidebar + chat list ride `surface`; cards, drawers, popovers, composer field
  ride `inverse-surface`. Container tiers
  (`surface-container-{lowest,low,…,highest}`) step the desk up for hover,
  raised chrome, dialog elevation.
- **Single accent: coral**, hue ~40°, `#cc785c` (oklch `0.62 0.110 40`),
  exposed as `--md-sys-color-primary`. Used for primary buttons, focus
  rings, the brand mark, the character counter when near limit, and the
  user-message bubble in light theme. Never used for decoration; always
  functional.
- **No saturated brand color.** No blues, no purples, no neon greens. The
  only saturated hues are the **categorical badge sets** — HTTP-method
  pills (`GET` ~220°, `POST` ~145°, `PUT` ~70°, `DELETE` ~25°,
  `PATCH` ~290°) and file-extension pills (`YAML` ~70°, `JSON` ~145°).
  These signal *category*, not *severity*. There is no status-pastel
  family any more: severity (errors / warnings / info / success) is
  communicated by icon shape + label, not by color.
- **Hue discipline.** Almost everything sits between `45°–80°` (warm) or
  exact neutrals. Cool hues only appear in the categorical badge sets
  noted above.

### Type

- **Inter** for UI, with `font-feature-settings: "ss01", "cv11"` enabled (the
  alternate-1 and stylistic-set 1 keep numbers and capital `i` distinguishable
  in dense lists).
- **JetBrains Mono** for code, file paths, JSON pointers, error rules, char
  counters when shown as raw values.
- **Three weights only**: 400 (body), 500 (medium — labels, chips), 600
  (semibold — titles and button text). 700 used sparingly; never italic.
- **Tight scale**: body is 14px, small is 12px, eyebrow is 11px. Display only
  goes up to ~34px (`h1`); the chat product itself rarely uses anything over
  18px. Letter-spacing is **negative** above 18px (`-0.01em` to `-0.02em`)
  and zero below.

### Spacing & layout

- **4px base grid** (`--s-1` through `--s-12`). Most chrome lives at 12–24px;
  card padding is `22px 24px 14px` for headers, `14px 24px 18px` for footers.
- **Three-column shell**: 280px sidebar, 1fr chat, optional drawer slides
  over the right edge of the chat pane (absolute-positioned overlay, not a
  third grid column).
- **Compact mode** collapses sidebar to a 60px icon rail. **Drawer-in-narrow**
  hides the sidebar entirely (used for the trace-drawer demo).
- **Hairline borders** (1px, low-saturation) do most of the separation work.
  Cards rely on subtle inner-line shadow + tiny outer drop, not heavy
  elevation.

### Backgrounds

- **No imagery, no full-bleed photos, no patterns.** The canvas is a flat
  warm-near-black; the surface is flat white. The only "texture" is the
  optional dot-grid on the design-canvas wrapper (`--s-dc-grid`), which sits
  outside the chat product itself.
- **No gradients in product UI.** A single intentional gradient appears in
  the snackbar overlay (`--c-snk-overlay` / `-strong` / `-soft` three-stop
  vertical fade) because GPU blur was rejected.

### Animation & easing

- **Fast, restrained, almost-no-bounce.** The base timing is **120–160ms**
  with `ease`. Hover transitions on chrome are 120ms; theme-swap fade is
  220ms. There are no spring/bounce easings, no scale-up reveals, no
  attention-grabbing motion.
- **Reduced motion**: `*::-webkit-scrollbar-thumb { transition: none; }`
  under `prefers-reduced-motion` — the source explicitly cuts thumb
  transitions for that audience.
- **Status indicators** use a slow pulsing dot (the `…` in the
  thinking-status row), not spinners.

### Hover & press states

- **Hover**: warm up the surface by one step.  Sidebar items go from
  `--c-sidebar` to `--c-sidebar-hover`. Buttons darken from `--c-accent` to
  `--c-accent-strong`. Borders gain `--c-border-strong` on hover. **No
  brightness/filter tricks**, always real token swaps.
- **Press / pressed**: inset shadow `--e-pressed` (very subtle inner top
  line), no scale change. The "active" sidebar chat item also picks up
  `inset 0 0 0 1px var(--c-border-canvas)` to read as pinned.
- **Focus**: `box-shadow: var(--e-focus-ring)` — a 1px halo of
  `--c-accent-soft`. Outlines are removed in favor of this.

### Borders, radii, corners

- **Radii**: `8px` chip / `10px` field+button / `14px` card / `999px` pill.
  No 0-radius hard corners, no 20px+ pillowy radii. Buttons and inputs share
  `10px` so they snap together.
- **Borders are 1px, hairline.** The focus ring is also a 1px halo. 2px
  borders only appear in the drag-active state of artboards on the
  design-canvas chrome (`--s-dc-shadow-card-drag` adds a 2px accent ring).

### Shadow / elevation system

Six layers, semantic names:

| Token | Used for |
| --- | --- |
| `--e-subtle` | Inline chips, file rows |
| `--e-subtle-md` | Slightly raised badges |
| `--e-card` | The composer / drawers (combo: 1px brightening top edge + soft 24px drop) |
| `--e-popover` | Menus, tooltips |
| `--e-popover-strong` | Modals |
| `--e-snackbar` | Snackbar card (top inner highlight + 18px + 4px stack) |
| `--e-drawer` | Right-side slide-in trace drawer (left-cast shadow `-16px 0 40px`) |
| `--e-pressed` / `--e-pressed-soft` | Inset top line for pressed/active rows |
| `--e-focus-ring` | 1px halo of `--c-accent-soft` |

**Inner shadows** are reserved for pressed states and the card top edge
(brightening line). **No shadows on the canvas itself**; the canvas is the
ground.

### Transparency & blur

- **Blur is avoided.** The snackbar overlay explicitly chose a vertical
  gradient over `backdrop-filter` for performance; this is documented in the
  source comment.
- **Transparency** appears in: focus rings (1px alpha halo), scrollbar thumbs
  (alpha-on-canvas), shadow stacks. Solid surfaces are otherwise solid.

### Imagery

- **There is no imagery.** No photos, no illustrations, no animated
  avatars. The only visuals are: the brand glyph, monochrome line icons, and
  flat color fills.

### Card anatomy

A typical card (composer, drawer, modal) uses:

- `background: var(--c-card)` (the theme-following card-stack surface)
- `border: 1px solid var(--c-border-subtle)` (hairline)
- `border-radius: var(--r-card)` (14px)
- `box-shadow: var(--e-card)` (combo top-line + soft drop)
- `padding: 22px 24px 14px` (header) / `14px 24px 18px` (footer)
- Header / footer are separated by `1px solid var(--c-border-subtle)` rather
  than padding alone.

---

## ICONOGRAPHY

### Approach

xmesh draws all icons as **inline SVG at 16–24px** with `currentColor` and
inline sizing. There are two idioms (see ADR 0017):

- **Legacy Lucide-style line icons** — `stroke-width` `1.8`–`2.4`,
  `currentColor` strokes, rounded line caps, no fills. Defined inline inside
  the Lit primitives module (`lit/components/primitives/index.ts` exports the
  named `xm-*-icon` elements; per-component icon sets — e.g. validation's
  status glyphs — live alongside their owning component).
- **Google Material Symbols (Outlined)** — fill-based glyphs rendered by name
  via `<xm-icon name="…">` (`lit/components/icon/index.ts`). The glyph path
  data is **bundled** in that module keyed by Material Symbol name, so there is
  **no icon font, no sprite sheet, no runtime fetch**. New glyphs come from this
  set.

Either way there is **no external icon library bundled with the product** and
no CDN dependency at runtime. The visual character of the line set matches the
**Lucide / Feather** family; the Material Symbols Outlined weight is chosen to
sit close to it. _The Lucide-via-unpkg substitution below applies to the UI kit
preview only; the production app ships each icon's geometry inline._

### Specific patterns observed in source

- **`<xm-icon size="..." stroke-width="1.8">`** is the canonical wrapper.
  Children are `<path>` / `<circle>` / `<rect>` with the
  `stroke="currentColor" fill="none"` defaults applied by the wrapper.
- **Common icons**: alert (circle + ! line), close (X), copy (stacked
  rectangles), upload (arrow + tray), check (single polyline), chevrons,
  search, plus, settings gear.
- **No emoji**. Anywhere. Not in chat-list dot indicators, not in error
  states, not in empty states.
- **Unicode glyphs are used sparingly** as inline marks: `…` (ellipsis at end
  of progress strings), `·` (middot in inline metadata), `→` and `↑` for
  send arrows when geometry is simple. The send button in the reference
  screenshot is a real `↑` arrow.

### Logo & brand mark

The **brand mark** in the sidebar is a 32×32 rounded-square chip with a
geometric glyph stroked in `--c-accent-ink`, sitting on a soft
`--c-accent-soft` fill. The wordmark is `Inter 600` at `16px`,
`letter-spacing: -0.01em`. We have an SVG of this in `assets/brand-mark.svg`;
treat it as the canonical lockup.

### File-format badges

A small set of branded uppercase chips appears next to file names:

| Token pair | Use |
| --- | --- |
| `--c-ext-yml-bg` / `--c-ext-yml-ink` | `YML` / `YAML` files |
| `--c-ext-json-bg` / `--c-ext-json-ink` | `JSON` files |

These are used by `<xm-file-validation-block>` and any list of
agent-definition files. Add new ones by following the same `_bg` / `_ink`
pattern (warm hue, low chroma in dark, pastel-on-white in light).

### HTTP method badges

Pre-themed pill backgrounds for `GET` / `POST` / `PUT` / `PATCH` / `DELETE`
exist (`--c-method-*-bg` / `-ink`); used in trace-drawer rows for tool calls
that hit external APIs.

---

## CAVEATS

- **Font files**: the source repo references Inter and JetBrains Mono as
  `font-family` strings only — there are no `.woff2` files committed. The
  design system pulls them from **Google Fonts** at runtime. If you need an
  offline build, drop the `.woff2` files into `/fonts/` and replace the
  `@import` in `styles/_fonts.css` with `@font-face` blocks.
- **Iconography**: the production app inlines its own SVGs. References to a
  Lucide CDN substitution apply to the source repo's UI kit only — this repo
  ships no UI kit and no CDN icon dependency. Inline SVG line icons (Lucide
  style) when adding new components.
- **No imagery / illustrations** were found in the source — none have been
  invented.
- **`docs/desing-system` (sic)**: the original folder name has a typo and
  exists only in the source repo (`sergeytkachenko/langgraph_smart_routing`).
  It is **not** present in this repo; references to it here are for
  provenance only.
- **No `ui_kits/` or `slides/` here.** The source repo had a wired chat UI
  kit; this published system intentionally ships only tokens, components,
  and previews. If you need a full-app shell, fork from the source repo.

---

## License

[Apache License 2.0](./LICENSE) © xmesh
