## Theme Taxonomy

Themes define visual *structure* — how depth works, how borders behave, how surfaces feel.
Lightness defines *luminance*. Axes define *tuning*. All orthogonal.

A theme is distinct only if it has a structural property that can't be achieved
by tweaking axes (density, roundness, depth, weight) of another theme.


## Authoring a theme

Every theme is `theme(axes?) → CSS string`. The canonical pattern for new themes:

```js
import baseCSS from './base.js'           // structural reset + shared layout
import { resolveRoles } from './color.js' // shade + accent → semantic role tokens
import { hardShadow, neuShadow, bevel } from './mixins.js'  // reusable CSS fragments

export default function myTheme({ shade = '#f5f4f2', accent, size = 1, ...rest } = {}) {
  const { dark, bg, fg, accent: acc, surface, border } = resolveRoles(shade, accent)
  // build CSS using role tokens...
  return baseCSS + '\n' + `.s-panel { --bg: ${bg}; ... }`
}
```

**`resolveRoles(shade, accent, { contrast })`** returns semantic tokens:
`dark`, `bg`, `surface`, `surface2`, `fg`, `fgMuted`, `border`, `divider`, `accent`, `onAccent`.

`onAccent` chooses black or white from hex / numeric-OKLCH fill luminance.
CSS colors outside the parser's supported formats pass through unchanged and
retain white ink; their contrast must be supplied by the theme or host.

**Mixins** (`theme/mixins.js`): `bevel(grad, w)`, `bevelRing(grad, w)`, `hardShadow(x, y, color)`, `neuShadow(dist, blur, dark, light)`, `neuInset(dist, blur, dark, light)`.

`brutal.js` is the simplest complete example: one control height, one plate-shadow helper, `resolveRoles` for color.


## The Foundational Themes

| # | Name | Status | Import | Structural Distinction | Iconic Reference |
|---|------|--------|--------|----------------------|------------------|
| 1 | **soft** | ✅ shipped | `theme/default` | Subtle shadows, generous radius, gentle transitions | Linear, Tailwind UI, Figma |
| 2 | **swiss** | ✅ shipped | `theme/swiss` | No shadows, grid-pure, typographic hierarchy only | Braun, Stripe, FabFilter |
| 3 | **skeu** | ✅ shipped | `theme/skeu` | Realistic textures, directional lighting, physical affordances | iOS 1-6, Universal Audio |
| 4 | **brutal** | ✅ shipped | `theme/brutal` | Hard offset shadows (no blur), thick borders | Gumroad |
| 5 | **neu** | ✅ shipped | `theme/neu` | Directional rim, contact + ambient shadows, one molded material | Neumorphism / claymorphism |
| 6 | **glass** | ✅ shipped | `theme/glass` | backdrop-filter blur, transparency, thin light borders | macOS Big Sur, Windows 11 |
| 7 | **lab01** | ✅ shipped | `theme/lab01` | Frosted glass + gradient borders + noise texture | lab01.dev |
| 8 | **control-panel** | ✅ shipped | `theme/control-panel` | freeman-lab/control-panel reproduction | control-panel |
| 9 | **classic** | 🔲 planned | — | Serif typography, rule lines, print margins | Notion, iA Writer, The New Yorker |
| 10 | **terminal** | ✅ shipped | `theme/terminal` | Monospace on a character-cell grid, inverse video, no depth | Bloomberg, vim, Ableton |
| 11 | **industrial** | 🔲 planned | — | Exposed structure, functional labels, accent = interaction | Teenage Engineering, Nothing |
| 12 | **retro** | 🔲 planned | — | Inset/outset bevel borders, system colors, pixel-crisp | Windows 95/98, classic GTK |
| 13 | **porcelain** | ✅ shipped | `theme/porcelain` | Glazed ceramic lip, embossed face, mineral frame | Porcelain / ceramic relief |

### What each structurally owns (can't be faked by another)

- **soft**: the *mainstream default* — nothing extreme, everything gentle
- **swiss**: *absence* of depth is the statement — shadows would break it
- **classic**: *print hierarchy* — serif typography and rule lines
- **terminal**: *the character-cell grid* — every size is a whole number of `ch` × lines; no depth, state is inverse video
- **industrial**: *the label IS the decoration* — POWER, SYNC, modular grid
- **brutal**: *hard offset shadow* (4px 4px 0 black) — unique depth model
- **glass**: *backdrop-filter* — unique CSS mechanism, unique depth
- **neu**: *directional relief in one molded material* — rim, contact and ambient lighting
- **porcelain**: *a glazed face seated in a mineral frame* — ceramic lip and embossed relief
- **skeu**: *real material textures* (leather, brushed metal) — unique surface
- **retro**: *bevel via border-color* (light top-left, dark bottom-right) — unique border model


### What was merged (and why)

| Candidate | Absorbed Into | Reason |
|-----------|--------------|--------|
| flat / material / surface | **swiss** (depth=0) or **soft** (depth>0) | No unique structural property — just depth parameter |
| corporate / enterprise | **swiss** or **soft** | Palette + weight choices, not structure |
| claymorphism | **neu** + color param | Same paired-shadow model, just more colorful |
| aqua | **skeu** (gel material) | Skeuomorphism with a specific material — gel buttons |
| analog / instrument | **skeu** (audio material) | Skeuomorphism with metal/knob material |
| vaporwave / synthwave | palette, not theme | Apply neon palette to any theme's structure |
| neon / cyber | palette, not theme | Glow = colored box-shadow, works on any structure |
| minimal | **swiss** + sparse density | Minimalism is swiss with fewer elements |
| calm UI / friendly professional | **soft** | This IS soft — that's the whole point of soft |


## Coverage Matrix

| Trend/Movement | Covered By |
|----------------|------------|
| Flat design | swiss (depth=0) |
| Minimalism | swiss (sparse density) |
| Material Design | soft (structured elevation) |
| Brutalism (web) | brutal or terminal |
| Skeuomorphism | skeu |
| Neumorphism | neu |
| Claymorphism | neu (+ color, + roundness) |
| Glassmorphism | glass |
| Neobrutalism | brutal |
| Aquamorphism | skeu (gel material) |
| Win95 / system UI | retro |
| Industrial | industrial |
| Editorial / print | classic |
| Corporate / SaaS | swiss or soft |
| Vaporwave / synthwave | any theme + neon palette |


## Implementation Order

**Shipped (v2.0)**

1. **soft** — default, most users, lowest risk
2. **swiss** — restraint as a statement
3. **skeu** — textures, directional lighting
4. **brutal** — hard shadows, high impact
5. **neu** — paired shadows, tactile plastic
6. **glass** — backdrop-filter, frosted surfaces
7. **lab01** — frosted + gradient border + noise
8. **control-panel** — dat.gui-era reproduction
9. **terminal** — character-cell grid, inverse video

**Planned**

10. **classic** — serif, editorial
11. **industrial** — label-as-decoration
12. **retro** — bevel border model



## Structural Rules Per Theme

> Sections marked **(planned)** describe intended design, not yet implemented.

### soft (default)
- Shadows: subtle drop (0 2px 8px, low opacity)
- Borders: 1px, low contrast
- Radius: generous (8-14px)
- Typography: system sans, normal weight
- Surface: solid, gentle palette
- Transitions: smooth (140-200ms)
- Feel: approachable, safe, mainstream

### swiss
- Shadows: none
- Borders: 1px functional (informational, not decorative)
- Radius: 0 (enforced)
- Typography: condensed sans titles (Oswald), sans labels (DM Sans), serif values (DM Serif Display)
- Surface: transparent; the host background remains visible through fields and rows
- Grid: mathematical, visible in alignment
- Feel: an outlined form over its surroundings, with deliberate typographic contrast

### classic *(planned)*
- Shadows: none or hairline rule
- Borders: rule lines (horizontal dividers, not boxes)
- Radius: 0 or very subtle (2px)
- Typography: **serif** (Georgia, Garamond), generous line-height (1.5+)
- Surface: paper/cream tones
- Margins: generous, controlled line length (~66ch)
- Feel: centuries of print wisdom, scholarly, timeless

### terminal
- Shadows: none — state is inverse video (selected, pressed) and a cursor bar (focus)
- Borders: one 1px frame, the title cut into its top edge; folders indent behind a tree guide
- Radius: 0 (enforced)
- Typography: **monospace everywhere**; every dimension a whole number of `ch` × lines (`leading` axis sets the cell height)
- Surface: solid; dark default, a light shade gives a paper terminal
- Color: text, dim, line and well are one contrast ladder off the shade; accent is the phosphor (on, selected, live values)
- Glyphs: `[x]` checkbox, `( )` / `(•)` radio, `[ RUN ]` button, `[+]` / `[-]` fold
- Density: one line per row
- Feel: every pixel earns its place

### industrial *(planned)*
- Shadows: none or minimal
- Borders: visible, structural (like panel seams)
- Radius: small (2-4px)
- Typography: industrial sans (DIN, Eurostile), uppercase labels
- Surface: matte, raw, modular panels
- Accent: high-visibility (orange, yellow) = interaction point
- Labels: literal function words as decoration ("VOLUME", "RATE")
- Feel: the machine is beautiful because it's a machine

### brutal
- Shadows: **hard offset, no blur** (4px 4px 0 black)
- Borders: **thick** (2-4px), always black/dark
- Radius: 0 or small (0-4px)
- Typography: bold sans, can be quirky
- Surface: solid, high saturation, can clash
- Gradients: none
- Feel: raw, confrontational, playful punk

### glass
- Shadows: subtle or none (blur IS the depth)
- Borders: **thin light stroke** (1px white/light at ~20% opacity)
- Radius: generous (12-20px)
- Typography: light/medium weight sans
- Surface: **transparent + backdrop-filter blur** (12-20px)
- Layers: stacked translucent surfaces
- Requires: interesting background behind it
- Feel: airy, premium, modern depth

### neu
- Shadows: thin edge highlight, close contact shadow, broad cast and reflected light
- Material: the same shade on the page, panel, buttons, and knobs
- Typography: clear system sans, distinct primary and secondary ink
- Raised controls have opaque, slightly curved faces; fields and pressed controls use inset lighting
- Depth, diffusion, lighting contrast, direction, and grain can be tuned independently
- The [Neu demo](../demo/cases/neu.html) has a live Material folder for these axes

### porcelain
- A white ceramic face with subtle flowing relief, seated in a pale mineral frame
- A crisp beveled lip catches the light; recessed fields and glazed thumbs share that construction
- Serif labels and blue-grey ink, with explicit keyboard focus outlines
- `shade` tints the body, `accent` the ink/actions, `bevel` scales the lip, `grain` the relief
- All panel textures are embedded SVG; the demo's marble background is a local SVG asset

### skeu
- Shadows: **directional, realistic** (consistent light source, usually top-left)
- Borders: material-dependent (brushed metal ridge, leather stitch)
- Radius: varies by material metaphor
- Typography: varies (can include engraved, embossed)
- Surface: **realistic textures** (leather grain, brushed aluminum, wood, felt)
- Gradients: physical (lighting, curvature)
- Affordances: buttons look pressable, sliders look grabbable
- Feel: the world before screens, analog warmth

### retro *(planned)*
- Shadows: none (depth via border colors)
- Borders: **inset/outset bevel** (light color top+left, dark color bottom+right, 2px)
- Radius: 0 (enforced)
- Typography: system/bitmap feel (small, pixel-aligned)
- Surface: solid system colors (silver/gray, teal, navy)
- Buttons: raised bevel (light top-left, dark bottom-right)
- Inputs: sunken bevel (dark top-left, light bottom-right)
- Feel: nostalgic, OS-native, 1995


## Brand Mapping

| Brand | Theme | Why |
|-------|-------|-----|
| Braun | swiss | Rams' "less but better" |
| Stripe | swiss | Clean grids, generous space |
| FabFilter | swiss | Functional, readable, no flair |
| Figma | swiss | Grid-driven, functional color |
| Linear | swiss | Dark, sparse, keyboard-first |
| Apple (2013+) | swiss | Typographic, whitespace-driven |
| Notion | classic | Serif option, reading-optimized |
| iA Writer | classic | Print heritage, type-first |
| Medium (early) | classic | Editorial, generous margins |
| Bloomberg | terminal | Max density, monospace, status colors |
| vim / htop | terminal | Every pixel earns its place |
| Ableton Live | terminal | Dense, functional, no decoration |
| Elektron | terminal | Monospace, utilitarian |
| Teenage Engineering | industrial | Exposed PCB, orange accent, modular |
| Nothing Phone | industrial | Visible structure, glyph interface |
| Gumroad | brutal | Hard shadows, thick borders, bold |
| macOS Big Sur | glass | Frosted panels, translucent layers |
| Windows 11 | glass | Mica/acrylic blur, thin borders |
| iOS 1–6 | skeu | Leather, wood, realistic shadows |
| Universal Audio | skeu | Photorealistic vintage gear |
| Waves Audio | skeu | Analog plugin replicas |
| Windows 95/98 | retro | Bevel borders, system palette |
| classic GTK | retro | Raised/sunken border model |
| Tailwind UI | soft | Gentle shadows, generous radius |
| Radix / shadcn | soft | Subtle depth, smooth transitions |


## Material studies

The [demo gallery](../demo/cases/index.html) includes Porcelain and seven material presets, using the same light-adjustment controls for comparison:

| Case | Theme | Axes |
|------|-------|------|
| [Porcelain](../demo/cases/variants.html#porcelain) | porcelain | glazed ceramic face, mineral rim, embossed relief |
| [Chalk](../demo/cases/variants.html#chalk) | neu | pale grey, depth .85, diffusion 1.4, contrast .8 |
| [Amber](../demo/cases/variants.html#amber) | neu | warm ochre, depth 1.2, contrast 1.25, matte grain .6 |
| [Graphite](../demo/cases/variants.html#graphite) | neu | charcoal, pale steel accent, depth 1.1, diffusion 1.1 |
| [Frost](../demo/cases/variants.html#frost) | glass | light mineral tint, blur 28, tint .85 |
| [Soft](../demo/cases/variants.html#soft) | skeu | matte silver, green accent, spacing 1.6, depth .7 |
| [Silver](../demo/cases/variants.html#silver) | lab01 | silver tint, compact segments, consistent row spacing |
| [Ink](../demo/cases/variants.html#ink) | brutal | off-white stock, lime accent, 2px borders, 3px offset |

Save keeps a snapshot for the current session; Reset restores it (or the initial
values before the first Save). Porcelain is a separate theme; the other cases are axis presets. Skeu / Soft uses
the current Skeu engine. Studio is reserved for a future design.

Glass works without page-provided SVG filters. Its shade tints the backdrop to
support readable text; blur controls the frost. The experimental lens remains
available in [the glass demo](../demo/cases/glass.html#lens) through the optional
`--glass-refraction` CSS property. A host may override `--glass-backdrop` too.

Lab01 uses `--row-gap` for sibling controls and folder contents, a smaller
`--card-label-gap` between a card picker and its label, and shared header/content
edge padding. All three track the spacing axis. Open panel content allows
shadows and keyboard focus rings to extend beyond its layout box.


## Gallery and live preview

The [main gallery](../index.html) renders one shared miniature specimen for every
engine: **Layer**, Blend select, Opacity slider, Enabled toggle, Apply effect button.
The larger preview adds Name, Tint, toggle help text, and a secondary Reset action. Values survive theme and axis changes;
Reset preview values restores the specimen while keeping the selected axes.

The colormap selector runs from dark to light: Dark, Graphite, Slate, Copper, Gold,
Gray, Sage, Silver, Ivory, Chalk, and Light. Light is pure white (`#ffffff`) with
a blue accent, matching the native DevTools light palette; Chalk stays off-white
(`#f1f2f4`). Dark uses Lab01’s near-black `#111111`; Graphite keeps its lighter
charcoal `#292b2e`. Each map sets the surface palette and suggests an accent;
choosing a custom accent keeps it across maps, and Auto restores the map's accent.
Themes interpret the colors through their own materials: Swiss remains transparent,
while Glass reveals the palette-colored backdrop. Silver and Gold supply color,
not an added metallic finish. Classic themes adapt their text and field roles;
their standalone native defaults remain unchanged. Lighting direction stays fixed.
Shared links store `colormap`; older `time` links map to the nearest palette.
Axis controls appear only when the selected engine supports them.

All engines now expose size, density, and body font using the
[shared dimensional tokens](axes.md#shared-dimensional-tokens). Native typefaces
and compact baselines remain theme defaults. The gallery surround is deliberately
distinct from panel fills so flat themes retain visible edges. Swiss intentionally
stays transparent, placing rules and typography over the host background; its
`shade` selects the ink contrast. UIL uses flexible label/value columns; Apple uses a continuous sheet
with inset fields and hairline row dividers.

**DevTools** (`theme/devtools.js`) defaults to Chrome's white Styles-pane palette:
red property names, neutral CSS values, inline punctuation, and compact monospace rows.
Its palette follows Chromium's [design tokens](https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/design_system_tokens.css).
The [declaration editor](../demo/cases/devtools.html) switches between native Light
(`#ffffff`) and Dark (`#282828`) without resetting edits; gallery colormaps tint
these surfaces. Native sliders, checkboxes, and action buttons remain interactive.
Use `devtools()` for Light or `devtools({ shade: '#282828' })` for Dark.

Search and Originals/Classics filters compose. Use theme provides JavaScript and
CSS, and Copy preview link stores the theme and axes in the URL (not edited sample
values). Desktop columns scroll independently; selecting a card on mobile returns
to the preview. The [playground](../demo/playground.html) retains the original editor.

The gallery shell uses Sprae for lists, filters, selection, axis bindings, and
export state. Inputs pair `:value` with `:change`; ARIA states use explicit strings.
Theme navigation batches state and history updates so synchronous effects preserve
the Back stack. Preview mounting runs untracked, keeping edits from remounting the
panel; replacing a preview disposes its controls and stylesheet.
