# ADR-004: DTCG Tokens, CSS-First

## Status
Accepted

## Context
Design tokens extracted from Penpot need to be consumed by both Astro and Next.js surfaces. The tokens must:

- Represent design decisions (colors, typography, spacing, shadows, etc.)
- Be maintainable as a single source of truth
- Work across multiple frameworks (React, Astro, future additions)
- Support design-to-code workflow (Penpot → tokens → components)
- Be simple to build and update without heavy tooling

Common token formats and approaches:
- **Style Dictionary**: JSON → multiple outputs, but adds Node.js build dependency
- **Tailwind config**: TypeScript/JS-based, framework-specific
- **CSS custom properties**: Universal, no build step to consume
- **TypeScript constants**: Type-safe but JS-only
- **DTCG spec**: W3C Community Group standard for token interchange

## Decision
Use W3C Design Token Community Group (DTCG) format as the source of truth, with CSS custom properties as the primary output format.

### Token Pipeline
1. **Source**: `packages/tokens/src/tokens.json` (DTCG format)
2. **Build**: Python script `packages/tokens/build.py` transforms to outputs
3. **Primary output**: `packages/tokens/dist/tokens.css` (CSS custom properties)
4. **Secondary output**: `packages/tokens/dist/tokens.json` (flat JSON for programmatic access)
5. **Consumption**: Both apps import `@cms/tokens/dist/tokens.css`

### CSS-First Philosophy
- No Tailwind token integration required
- No TypeScript token projection required
- Frameworks consume via standard CSS import
- Custom properties work in any CSS context (vanilla, CSS modules, styled-components, etc.)
- Build script is Python (no Node.js tooling dependency)

### Current Token Inventory
- **171 tokens** across 10+ categories
- Categories: colors, typography, spacing, shadows, borders, radii, opacity, z-index, layout, effects
- Growth: 94 → 109 → 121 → 133 → 145 → 158 → 171 tokens

## Consequences

### Positive
- **Universal**: CSS custom properties work in any framework
- **Simple**: Single Python script, no complex build toolchain
- **Standard**: DTCG format is W3C spec, future-proof
- **Fast**: Build script runs in <100ms
- **Clear workflow**: Edit tokens.json → run build.py → commit dist/ → import in apps
- **Design tool agnostic**: Can add Figma, Stitch, or other sources later

### Negative
- **No type safety**: CSS custom properties are strings at runtime
- **No autocomplete**: IDEs don't suggest token names (unless using CSS variable plugins)
- **Manual validation**: No compile-time check if token reference is valid
- **Python dependency**: Build requires Python 3.6+ (not Node.js)

### Neutral
- **Build command**: `cd packages/tokens && python build.py`
- **Commit both**: Source (tokens.json) and output (tokens.css) are both committed
- **Flat JSON fallback**: For tools that need programmatic access to token metadata
- **No token aliases yet**: All tokens are concrete values (could add $ref support later)

### Future Enhancements
- Add TypeScript definitions generator for better DX
- Implement token validation (detect unused, missing, or malformed tokens)
- Add Tailwind config generator as optional output
- Support DTCG $ref aliases for token relationships
- Automate token extraction from Penpot exports via MCP

### Trade-offs Accepted
- Chose simplicity and universality over type safety and IDE autocomplete
- Chose Python for build to keep token pipeline independent of Node.js
- Chose committing dist/ over gitignoring (makes tokens immediately usable without build step)
