# Madhav Nair: design language

A small, headless design system. It runs madhavnair.in, and you're free to use it.
Source of truth: `/css/tokens.css` (primitives + semantic), `/css/themes.css` (themes as token overrides), `/css/components.css` (recipes), `/design/tokens.json` (W3C Design Tokens), `/design/components.json` (component specs), `/design/llms.txt` (rules for agents).

## Principles
1. **Trust before commitment.** Show the work, state the facts, let people decide. No dark patterns, no fake urgency, no invented numbers.
2. **Restrained.** One accent, used for the thing that matters. Quiet surfaces, real images, generous space.
3. **Lime is the signal.** `--accent` (lime by default) marks the current item, the primary action chip and small status tags. Never body text, never large fills, never glow.
4. **Geist Pixel, sparingly.** Tiny labels, the Now tag, numbers, the footer, an easter egg. Never headings or paragraphs.
5. **Solid over clever.** Sticky chrome is opaque. Images are clipped to their plates. Nothing depends on hover.

## Voice
Candid, specific, first person, British English. Short sentences. Say what I did and what happened; leave out what I can't show. No hype words ("revolutionary", "seamless", "cutting-edge"). Name real products, roles and dates only.

## Colour and themes
- Modes: `html[data-mode="light"|"dark"]`. Themes: `html[data-theme="lime"|"hairline"|"layered"|"signal"|"custom"]`. Themes change tokens only. See THEMES.md.
- Use semantic tokens in new CSS: `--bg-page`, `--bg-raised`, `--bg-sunken`, `--fg`, `--fg-2`, `--fg-muted`, `--accent`, `--on-accent`, `--chrome`, `--line`, `--line-2`, `--focus-ring`.
- Contrast: body text ≥ 4.5:1, text on accent ≥ 4.5:1, focus ring and accent chip ≥ 3:1 against their background, in both modes.
- Dark mode main button: a dark pill (`--pill`) with an accent chip.

## Type
Inter (self-hosted variable, 400–700). Scale `--t-xs` 12 → `--t-3xl` fluid display. Headings weight 500 with tight tracking (`--track-tight`); body 16px, `--lh-body`. Geist Pixel via `--pixel` for labels only.

## Spacing and layout
4-based scale `--s-1` (4) … `--s-9` (96). Page gutter `--gutter`: 16 / 24 / 32px. Max container 1200px. Breakpoints: phone ≤ 640, tablet ≤ 900, desktop ≥ 901, wide ≥ 1440. Cards stack below 900px; no fixed min-heights on stacked cards.

## Radii
Four only: `--r-sm` 8, `--r` 12, `--r-lg` 24, `--r-pill` 999. Nested radius = outer minus padding.

## Components (`components.css`, prefix `c-`)
| class | use | modifiers |
|---|---|---|
| `c-card` | default container | `--lead` (accent edge, the one current thing), `--media` (clipped media + `c-card__body`), `--quiet` |
| `c-btn` | actions | `--accent`, `--ghost`; `c-btn__chip` holds the icon |
| `c-pill` | non-interactive label | `c-pill__dot` |
| `c-chip` | filters, tabs | state via `aria-pressed` / `aria-selected` |
| `c-tag` | small status | `--pixel` |
| `c-section` | page section | `--tight`, `c-section__head` |
| `c-sticky` | solid bar under the header |: |
| `c-plate` | figure with a 6px mat |: |
Legacy page classes (`.feature-card`, `.pill`, `.btn`, `.note-fig`) predate these and map to card, pill, button and plate.

## Motion
`--d-fast` .15s, `--d-base` .3s, `--d-slow` .6s; `--ease` (soft spring) and `--ease-out`. Motion confirms, never decorates. All durations go to 0 under `prefers-reduced-motion`. No parallax, no autoplaying loops.

## Imagery
Real product screenshots and my real portrait. WebP/AVIF with width, height and alt; lazy below the fold. Media sits on a plate or in a clipped card. No generated imagery, no stock, no mock-device glamour shots.

## Accessibility
Skip link, visible focus everywhere, 44px tap targets on touch, keyboard-operable dialogs (focus trap, Esc), reflow at 320px and 200% zoom, no hover-only content, respects reduced motion and forced colours.

## Do / don't
Do: one accent; solid chrome; real content; clipped media; tokens only; test before shipping.
Don't (rejected styles): neon-yellow overload, orange/clay, ice-blue, violet-on-black, aubergine, Swiss black-and-white, glow, gradient text, HUD looks, heavy gradients, nested double frames, translucent sticky bars, invented metrics.

## Add a component
1. Write semantic HTML first. 2. Add a `c-name` block to components.css using tokens only (the test suite lints for raw colours and radii). 3. Add its spec to `/design/components.json` (anatomy, variants, tokens, a11y). 4. Show it on `/design/`. 5. Run `node tests/run.mjs`.

## Add a page
Copy the head and footer from index.html (or use a generator in /build), keep the inline theme script first in `<head>`, one `<h1>`, a description, canonical and OG tags. One-off page CSS is fine if it uses tokens. Add it to `PAGES` in tests/run.mjs and to sitemap.xml.
