# ASK — Design Tokens & Handoff

Single source of truth for the ASK brand. Powers Figma, Tailwind/shadcn, Storybook, and any downstream tooling that consumes design tokens.

## What's in this folder

```
design-tokens/
├── README.md                        ← you are here
├── tokens.json                      ← W3C DTCG master (the source of truth)
├── figma/
│   └── tokens-studio.json           ← Tokens Studio for Figma import
├── shadcn/
│   ├── globals.css                  ← CSS variables, drop into app/globals.css
│   └── tailwind.preset.ts           ← Tailwind config preset
└── storybook/
    └── theme.ts                     ← Storybook brand theme
```

Logo files live one level up at `../logo/` — drag the SVGs into Figma frames as-is (they're outlined paths, no font needed).

---

## Workflow per tool

### Figma (single source of truth)

**Setup once:**

1. Install [**Tokens Studio for Figma**](https://tokens.studio/) (free plugin).
2. Open the plugin in a fresh Figma file.
3. **Tools → Load from file → JSON** → upload `figma/tokens-studio.json`.
4. Click **Import** → choose **Create styles & variables**. Tokens Studio creates Figma Variables for every color, font, radius, and spacing token, and named text styles (`display-xl`, `heading-1`, `body`, etc.).
5. Drag the SVGs from `../logo/` directly onto the canvas to create a Logo component set.

**Keeping it in sync:**

- `tokens.json` (DTCG) is the source. If you change a value there, regenerate `tokens-studio.json` and re-import in Tokens Studio (it diffs and updates the existing variables in place).
- Conversely, if a designer changes a Figma Variable, export from Tokens Studio back to JSON and PR the change.

**Alternative — Figma Variables import (no plugin):**

Newer Figma supports DTCG natively via the [**Design Tokens**](https://www.figma.com/community/plugin/888356646278934516/design-tokens) plugin. Use `tokens.json` directly.

### shadcn / ui

1. Copy `shadcn/globals.css` → `app/globals.css` (Next.js) or `src/index.css` (Vite).
2. Copy `shadcn/tailwind.preset.ts` into your repo and reference from `tailwind.config.ts`:

   ```ts
   import askPreset from './design-tokens/shadcn/tailwind.preset';
   export default {
     presets: [askPreset],
     content: ['./src/**/*.{ts,tsx}'],
   };
   ```

3. Run `npx shadcn-ui@latest init` (skip color prompt — your tokens override the defaults).
4. Add shadcn components. They will pick up `--primary`, `--background`, etc. automatically.

The CSS variables follow shadcn's HSL-channel convention: `--primary: 354 78% 52%;` — consume as `hsl(var(--primary))`.

### Storybook

1. `yarn add -D @storybook/theming`
2. `.storybook/manager.ts`:

   ```ts
   import { addons } from '@storybook/manager-api';
   import askTheme from '../design-tokens/storybook/theme';
   addons.setConfig({ theme: askTheme });
   ```

3. `.storybook/preview.ts` (for the Docs addon):

   ```ts
   import askTheme from '../design-tokens/storybook/theme';
   import '../app/globals.css'; // load Ask CSS variables into stories

   export default {
     parameters: {
       docs: { theme: askTheme },
       backgrounds: {
         default: 'paper',
         values: [
           { name: 'paper', value: '#F7F6F4' },
           { name: 'white', value: '#FFFFFF' },
           { name: 'ink', value: '#0A0A0A' },
         ],
       },
     },
   };
   ```

4. Copy `../logo/ask-logo.svg` into Storybook's `public/` so the brand image resolves.

### Chromatic

Chromatic consumes Storybook's build — no extra config needed beyond what's above. The fact that all tokens flow through CSS variables makes visual diffs deterministic across themes.

Two recommendations:

- **Test both themes** by parameterizing stories with the dark/light decorator. shadcn's `.dark` class is already wired in `globals.css`.
- **Capture the brand sheet** as a story: add `BrandSheet.stories.tsx` that renders the relevant sections — that way Chromatic catches regressions in the foundations, not just components.

---

## Token reference

### Brand colors

| Token | HEX | HSL | Role |
|---|---|---|---|
| `ask.red`        | `#E42438` | `354 78% 52%` | Primary signal |
| `ask.red-hover`  | `#C81B2E` | `353 76% 45%` | Pressed state |
| `ask.red-soft`   | `#FCE6E9` | `352 79% 95%` | Soft wash |

### Neutrals

| Token | HEX | HSL | Role |
|---|---|---|---|
| `ask.ink`        | `#0A0A0A` | `0 0% 4%`     | Text anchor |
| `ask.graphite`   | `#2A2A2D` | `240 3% 17%`  | Body text |
| `ask.steel`      | `#6E6E76` | `240 4% 45%`  | Meta / captions |
| `ask.mist`       | `#E8E8EA` | `240 5% 91%`  | Dividers |
| `ask.paper`      | `#F7F6F4` | `40 16% 96%`  | Default canvas |
| `ask.rule`       | `#D8D6D2` | `40 7% 84%`   | Borders |

### State intents

| Token | HEX | HSL | Role |
|---|---|---|---|
| `state.success`      | `#1F8A5B` | `152 63% 33%` | Positive outcome |
| `state.success-soft` | `#E7F5EE` | `146 39% 93%` | Success wash |
| `state.warning`      | `#B7791F` | `38 72% 41%`  | Guardrail block, throttle |
| `state.warning-soft` | `#FBF1DD` | `42 72% 92%`  | Warning wash |
| `state.danger`       | `#C81B2E` | `353 76% 45%` | Destructive / error |
| `state.danger-soft`  | `#FCE6E9` | `352 79% 95%` | Danger wash |
| `state.info`         | `#2A6FDB` | `215 71% 51%` | Guardrail active, info |
| `state.info-soft`    | `#E3EDFB` | `215 71% 94%` | Info wash |

### Type

| Role | Family | Weight | Size | Letter-spacing |
|---|---|---|---|---|
| display-xl | Archivo Black | 900 | 96 | -0.02em |
| display-lg | Archivo Black | 900 | 64 | -0.02em |
| heading-1  | Archivo | 700 | 44 | -0.015em |
| heading-2  | Archivo | 700 | 32 | -0.015em |
| heading-3  | Archivo | 700 | 24 | -0.015em |
| body       | Archivo | 400 | 15 | 0 |
| caption    | Archivo | 500 | 12 | 0.14em (UPPER) |

### Spacing

`0, 2, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96` (px)

### Radius

`0, 2, 4, 8, 12, 16, 9999` (px) — note ASK's aesthetic is **sharp**. The shadcn `--radius` default is 4 px, not 8 px.

### Motion

| Token | Value | Use |
|---|---|---|
| `duration.fast`    | `120ms` | Hovers, micro-interactions |
| `duration.base`    | `200ms` | Default UI transitions |
| `duration.slow`    | `320ms` | Overlays, dialogs |
| `easing.standard`   | `cubic-bezier(0.2, 0, 0, 1)`     | Default — enter and exit |
| `easing.accelerate` | `cubic-bezier(0.3, 0, 1, 1)`     | Exit / dismiss |
| `easing.decelerate` | `cubic-bezier(0, 0, 0.2, 1)`     | Enter / appear |
| `easing.spring`     | `cubic-bezier(0.5, -0.2, 0.5, 1.4)` | Playful — toasts, badges |

### Elevation (z-index)

| Token | Value | Role |
|---|---|---|
| `z-content` | `10`   | Sticky in-page elements |
| `z-sticky`  | `100`  | Sticky headers, sidebars |
| `z-overlay` | `1000` | Tooltip, popover, dropdown |
| `z-modal`   | `1100` | Dialog, sheet |
| `z-toast`   | `1200` | Toast — above modal |

---

## Versioning

- `tokens.json` carries the implicit version of this folder.
- Any change to a token is a **minor** version bump.
- Any rename or removal is a **major** version bump (downstream tools break otherwise).
- Tag the design-tokens folder with semver as `ask-tokens@1.0.0` when you check it into git.