# ADR-S4: UI Composition and Theming

**Status**: Adopted (agent-recorded design decision) — pending named
architecture ratification **Date**: 2026-07-24 **Authors**: V1 Domain
Workbenches extraction audit (Phase S)

> Records the UI composition + theming contract for the shared workbench-kit
> (`V1_DOMAIN_WORKBENCHES_TODOS_2026-07-23.md` §S0.9). Built on §S0.9.a
> (`design-system-comparison.json`) and §S0.9.b
> (`ui-composition-boundary.json`): the token **contract** (naming) is
> kit-owned, the token **values** are host-owned, and the five systems do not
> share one styling approach. The machine-checked model is
> `evidence/v1-workbenches/workbench-kit-theme-contract.json`; the running
> prototype is `evidence/v1-workbenches/workbench-kit-theme/`.

## Context

§S0.9.a found the five systems diverge hard: token **owners** oshun (600) +
yemaya (67) at very different scales, a token **consumer** isis (0 local defs),
and **non-token** euterpe (inline styles) + bellona (minimal). A single shared
token _value_ set is therefore not adoptable. §S0.9.b concluded the neutral,
shareable thing is the token **naming contract**, not the values.

## S0.9.c — Token contract (9 categories)

The kit owns nine categories of role-name custom properties (`--wk-*`). Six map
onto real oshun `--l-*` tokens; three (**spacing, density, focus**) the contract
introduces because oshun does not tokenize them today.

| Category           | Roles (excerpt)                                | Maps to (oshun)                                         |
| ------------------ | ---------------------------------------------- | ------------------------------------------------------- |
| color              | `--wk-color-bg/surface/ink/muted/accent/rule`  | `--l-bg/-paper/-surface-card/-ink/-muted/-accent/-rule` |
| typography         | `--wk-font-sans/serif/mono`, `--wk-text-scale`, `--wk-measure` | `--l-sans/-serif/-mono`                 |
| spacing            | `--wk-space-1..6`                              | _contract introduces_                                   |
| density            | `--wk-density` (via `[data-density]`)          | _contract introduces_                                   |
| elevation          | `--wk-elevation-0..3`                          | `--l-surface-wash/-veil/-card/-solid`                   |
| motion             | `--wk-motion-fast/base/slow`, `--wk-ease`      | `--l-motion-fast/-base/-slow`, `--l-ease-*`             |
| focus              | `--wk-focus-ring/offset`                       | _contract introduces_                                   |
| semantic-states    | `--wk-state-ok/warn/danger/info` (+`-fg`)      | `--l-ok/-warn/-alert`                                   |
| data-visualization | `--wk-viz-1..6`                                | `--l-kg-*`, `--l-eisen-q1..q4`                          |

## S0.9.d — Theme injection isolation (prototype)

`workbench-kit-theme/tokens.css`. Four isolation guarantees, each verified:

1. **No global CSS leakage** — all tokens under `[data-workbench-theme]`, never
   bare `:root` (checked: 0 `--wk-*` in a `:root` block).
2. **No class collisions** — the kit exposes custom-property _names_, not
   classes.
3. **No duplicate providers** — one scoped element; nesting re-scopes via the
   cascade, no separate JS provider to duplicate.
4. **No inaccessible overrides** — `prefers-reduced-motion` + `forced-colors`
   handled at the contract level under the scoped selector.

## S0.9.e — Archetype compositions (reconciled, not cloned)

`workbench-kit-theme/archetypes.css`. Four archetypes consume the **same**
contract with divergent values:

| Archetype           | System         | Character                                       |
| ------------------- | -------------- | ----------------------------------------------- |
| calm-authoring      | oshun          | comfortable density, soft motion, serif-forward |
| operator            | isis           | standard density, crisp motion, clear states    |
| creative-production | yemaya/euterpe | dark-surface, snappy motion, vivid viz          |
| control-room        | bellona        | compact density, minimal motion, high-contrast  |

They differ in ≥2 density values and multiple color/motion tokens — proving the
contract supports divergence **without a visual clone**.

## S0.9.f — Accessibility coverage matrix

Each condition maps to a contract mechanism present in the prototype. (Live
per-pixel cross-host screenshots are the **runtime** layer; this validates the
a11y _contract_ coverage.)

| Condition           | Mechanism                                                |
| ------------------- | -------------------------------------------------------- |
| light/dark theme    | color tokens overridden per archetype (dark bg/ink)      |
| compact density     | `[data-density="compact"]` → `--wk-density: 0.75`        |
| comfortable density | `[data-density="comfortable"]` → `--wk-density: 1.15`    |
| zoom                | rem-based spacing + `--wk-text-scale` (no fixed px)      |
| reduced motion      | `@media (prefers-reduced-motion)` zeroes `--wk-motion-*` |
| forced colors       | `@media (forced-colors)` defers to the system palette    |

## Consequences

- The kit ships **token names + a scoped injection contract**, never values.
  Every host (oshun/isis/yemaya/euterpe/bellona) keeps its own visual identity.
- The three unmodeled categories (spacing/density/focus) are the contract's
  net-new contribution — adopting the kit tokenizes them where hosts do it ad
  hoc today.
- Named ratification remains a human step; the contract, isolation, archetypes,
  and a11y matrix are coherence-gated in CI against the §S0.9.a/b evidence.

## References

- `V1_DOMAIN_WORKBENCHES_TODOS_2026-07-23.md` §S0.9
- `evidence/v1-workbenches/design-system-comparison.json` (§S0.9.a),
  `ui-composition-boundary.json` (§S0.9.b)
- `evidence/v1-workbenches/workbench-kit-theme/` (prototype),
  `workbench-kit-theme-contract.json` (machine-checked model)
- `docs/adr/ADR-S1-*.md` … `ADR-S3-*.md`
