# Design system

How the app looks the way it looks: tokens, block colours, terrain themes,
entity art and skins. The authority for styling lives in two places:
`styles/theme.css` (the shared palette, breakpoints, typography, radii,
shadows and the `v-*` height variants) and `src/style.css` (Tailwind entry,
app-specific tokens, entity art, `[data-*]` selectors, browser quirks).
`styles/global.css` holds the base element styles; everything lives inside
this app, there is no separate design package. The `.agent/` folder's
`color-sweep.md` keeps the same information for contributors.

## The token system

Tailwind v4 `@theme` declares semantic tokens; components use semantic
classes, never raw palette colours:

| Group    | Tokens                                                              |
| -------- | ------------------------------------------------------------------- |
| Accent   | `primary`, `primary-hover/-active`, `primary-light`, `primary-dark` |
| Surfaces | `surface`, `surface-raised` (+ `-hover`/`-active`)                  |
| Content  | `content`, `content-raised`, `content-masked`                       |
| Borders  | `border`, `border-masked`                                           |
| Status   | `success`, `warning`, `error`, `info`                               |

App-specific additions in `src/style.css`:

- **Blocks**: `block-sky`, `block-emerald`, `block-yellow`, `block-green`,
  `block-red`, `block-orange`, `block-gray` (the locked/default scheme), each
  with `-hover`, `-active`, `-border`, plus `-washed` variants for container
  bodies and `-washed-hover` for the drag-over state.
- **Terrain themes** (paired ground/wall): `default` (ground/orange wall),
  `amber`, `forest` (`-terrain`), `frost`, `icy-blue` (`blue-ice`),
  `legend`, `boss`, `stone`, plus `ice`.
- **Entities**: `player` (equals `primary`), `target` (cheese yellow),
  `stop` (the Stop button), `success-strong` (completed-level dot, because
  the shared `success` is too pale on the picker).
- **Code export**: `syntax-keyword`, `syntax-call`, `syntax-number` and the
  brand badges `logo-c`, `logo-python` (+accent), `logo-javascript`.

## Block chrome

`BlockShell` (see [Blocks](./07-blocks.md)) is the single source of block
chrome: the clipart body, the top notch and bottom nub, the variant map and
the drag-over colour swap. Block colours are solid 80% or washed 60% opacity
with a 4 px backdrop blur; 70/50 was tried first and looked muddy when
containers nested, so the values are what they are on purpose. `--block-height`
is the shared height so every block, including the Start head, aligns.

## Terrain themes

A level names a theme per block kind through `looks`; the theme is an
identifier, never a class. `src/terrain.css` maps each `data-terrain` +
`data-kind` pair to a colour token and a procedural texture, with the rule
that **ground and wall of a theme are different images** (different
frequency, seed, scale or offset), never the same image. The art direction:

- `default` - large smooth rock/sand grain.
- `amber` - coarse sand.
- `forest` - grass ground with directional needles; the wall is a dense,
  overlapping, upright evergreen canopy of varied size and tone that covers
  the whole tile (no ground shows between trees).
- `frost` - soft snow drifts.
- `icy-blue` - ice with large stripes.
- `legend` (deep ice) - large smooth depth patches, no lines.
- `boss` (purple) - hazy sharp polygons.
- `stone` - dry gravel (ground) and darker wet gravel (wall).
- `ice` - icy surface with stripes; the block kind `ice` always uses it.

Textures are tileable (`stitchTiles` noise or `<pattern>` shapes), large
(72-160 px), and every cell paints from the same origin, so tiles stay
perfectly square and aligned. The `--tex-block` grain is shared by the block
bodies and the cheese so entities read as part of the same world.

## Entity art rules

Flat art only: filled shapes, no strokes, outlines or gradients. Friendly
and non-violent by design (a game for all ages). The mouse, cheese, lava and
hole are described in detail on [The playground](./12-playground.md).

## Skins

`data-player-skin='blue' | 'pink'` overrides `--color-player`, so it works
on `<html>` (the live game, set by `lib/skin.ts`) and on any element (the
picker options render a preview mouse in each skin). The choice persists in
`localStorage` under `bunplate:player-skin`.

## Responsive scale

Sizing scales with the viewport instead of breakpoint jumps: `clamp()` for
block padding and text, the `v-*` custom variants (`v-xs` through `v-3xl`)
for spacing, a fixed `clamp()` height for the palette (it must not grow or
shrink between levels), and explicit per-breakpoint widths for the level's
left column so the palette keeps its width even while its blocks are hidden
during a delete drag.

Next: [Persistence](./14-persistence.md).
