## @archetypeai/ds-lib-tokens

**Tailwind v4 theme** for the Archetype AI Design System. Provides semantic design tokens, color palettes, and base styles for use with the design system component flavors.

---

## Install

```bash
npm install @archetypeai/ds-lib-tokens tailwindcss
```

---

## Usage

Import the theme before Tailwind in your global CSS:

```css
@import '@archetypeai/ds-lib-tokens/fonts.css'; /* optional → PP Neue Montreal (requires font files in static/fonts/) */
@import '@archetypeai/ds-lib-tokens/theme.css';
@import 'tailwindcss';
```

```svelte
<div class="bg-background text-foreground p-md border-border rounded-lg">
  Hello world
</div>
```

---

## What's Included

| Feature | Details |
|---------|---------|
| **Semantic Tokens** | OKLCH CSS variables (shadcn-style): `background`, `foreground`, `card`, `popover`, `primary`, `secondary`, `muted`, `accent`, `destructive`, `border`, `input`, `ring`, `chart-1`–`5`, `sidebar`, `atai-neutral`, `atai-good`, `atai-warning`, `atai-critical`, `atai-always-black`, `atai-always-white` |
| **Brand Tokens** | 8 OKLCH palettes with shades 50–950: `atai-tangerine`, `atai-sunshine-yellow` (amber-leaning scale), `atai-lime`, `atai-screen-green`, `atai-fire-red`, `atai-energy-pink`, `atai-cool-purple`, `atai-baby-blue` |
| **Spacing scale** | `--spacing-xs` (0.25rem) → `--spacing-xl` (1.5rem), used as `p-md`, `gap-lg`, … |
| **Radius scale** | `--radius-xs` → `--radius-xl`, `--radius-full`, plus `--atai-radius-interactive` (radius for interactive elements, `rounded-interactive`) |
| **Icon stroke widths** | `--stroke-width-icon-{default,interactive,status,emphasis}` (1 / 1.25 / 1.5 / 2) for Lucide icons |
| **Width scale guard** | `--max-width-*`/`--min-width-*` alias Tailwind's `--container-*` scale, so `max-w-md` resolves to container sizes instead of the t-shirt spacing tokens |
| **Dark mode** | `.dark` class via `@custom-variant dark (&:where(.dark, .dark *))` |
| **Typography** | Font-family stacks with system fallbacks and semantic HTML base styles |

Brand tokens are defined in `colors.css` and loaded automatically via `theme.css`.

### Semantic HTML base layer

`theme.css` styles bare HTML elements so plain markup is on-brand without utility classes: `body`, `h1`–`h6`, `p`, `small`, `span`, `strong`, `em`, `label`, `a`, `code`, `blockquote`. All elements default to `border-border` and `outline-ring/50`.

---

## Fonts

`fonts.css` is included in this package with two kinds of `@font-face` declarations: **15 binary faces** of PP Neue Montreal Sans + Mono (`font-display: swap`) pointing to `/fonts/`, plus **15 metric-matched fallback faces** (per-OS base × per weight). The font binaries themselves are **not** part of the npm package - the CLI (`ds create` / `ds init` / `ds add --fonts <path>`) copies them into your project's `static/fonts/`.

**When the binaries are absent**, the fallback faces take over: each re-shapes a *local* system font to PP Neue Montreal's own metrics — x-height, average character width, and line box — via `size-adjust` + `ascent`/`descent`/`line-gap-override`, so an un-provisioned project still renders at the brand font's proportions and lays out identically. **When the binaries are present**, the same faces make the fallback→brand-font swap shift-free (no layout shift / CLS).

The fallback bases are chosen **per operating system** (the stacks in `theme.css` order them so each platform resolves its closest native font, all confirmed `local()`-reachable):

| | Apple | Windows | Android |
|---|---|---|---|
| **Sans** | Helvetica Neue | Arial | Roboto |
| **Mono** | Menlo | Consolas / Cascadia Mono | Roboto Mono |

SF Mono is intentionally not used — it is not reachable via `local()`. Override numbers are generated with `@capsizecss` from the Regular weights (regenerate if the brand font's metrics change).

Weights are declared **per instance**: `local('Helvetica Neue')` always resolves to the *Regular* cut regardless of the `font-weight` descriptor, so a single face would silently render Medium as Regular and *faux-bold* 700. Each weight therefore names its real cut (`local('HelveticaNeue-Medium')` / `-Bold`, etc.). Bases without a true Medium (Arial, Menlo, Cascadia) omit 500, so it matches down to Regular.
