v0.3 Phase 4g: four-tier semantic tokens + notice usage layer

Round-5 feedback flagged the muddy result of forcing one --color-caution
to be both bright yellow (signal) and accessible text (ochre). The
single-token-per-role model collapsed the visible identity. Caution
notices ended up reading as brown/khaki surfaces because color-mix(
in oklab, var(--color-caution) 8%, transparent) over cream produced
muddy results whatever the source hex.

New architecture: four-tier per-role tokens, hand-tuned -bg surfaces,
plus usage-specific notice tokens on top.

Tier model — each semantic role publishes four tokens:

  signal  Brand-true colour. Left bars, large icons, dots, focus rings.
          Looks like the role at a glance.
  ink     Accessible text variant. Used ONLY when text itself must
          carry the role colour. WCAG AA 4.5:1 on its surface.
  border  Middle value. Visible chip/notice outline; not text-safe.
  bg      Hand-tuned pale tint surface. NOT a color-mix derivation.

Example, light-mode caution:
  --color-caution-signal #FFCD00  (bright yellow)
  --color-caution-ink    #7A5D00  (ochre, for small text only)
  --color-caution-border #D9A900  (mid gold)
  --color-caution-bg     #FFF7D6  (clean pale yellow tint)

--color-{role} retained as a backward-compat alias pointing at -signal.
v0.2 callers keep working; new code reaches for the specific tier.

Usage layer — components subscribe to usage-specific tokens, not
role-tier tokens directly:

  --notice-{role}-bar     left bar, signal-tier
  --notice-{role}-icon    signal in dark, ink in light, signal in HC
  --notice-{role}-border  outer border colour
  --notice-{role}-bg      hand-tuned pale surface

LumotiaNotice reads these via Tailwind arbitrary-value classes
(bg-[var(--notice-info-bg)] etc). v0.2 fallback values defined at
:root (outside quietware blocks) using color-mix from v0.2 --color-
{role} tokens so the Notice keeps rendering sensibly when quietware
is off.

HC contract — every -bg token forces to transparent. HC notices
render text + icon + 2-px border + left bar, no body tint. Brand
atmosphere steps fully aside.

Per Jake's round-5 spec: yellow stays yellow as the visible signal,
ochre only appears as small-text ink, and brown/khaki never
represents the caution role's primary visual identity again. Same
discipline applies to red/blue/green — each role has a clean
hand-tuned -bg pale tint per theme.

Verified — visible result.

  Light caution notice: bright #FFCD00 bar + signal icon + ink-darkened
  small icon + pale #FFF7D6 surface + #D9A900 border. Clean,
  semantically clear, no mud.

  Dark caution notice: bright #FFCD00 bar + signal icon + dark warm
  #29210A surface + bright yellow border. Reads as yellow at a glance.

  HC modes: no body tint, strong bordered notices, semantic colours
  preserved as primary identifier alongside icon + label.

  npm run check: 0 errors, 0 warnings across 5707 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 14:27:46 +01:00
parent 2fcb5aff78
commit 2f11f493c5
3 changed files with 319 additions and 111 deletions

View File

@@ -310,6 +310,47 @@ Foundation for the page-skeleton sweep without yet migrating any page. Two addit
- **`LumotiaNotice` `slim` prop** — collapses padding, drops the title block, smaller icon. For one-line ambient notices like browser-preview state.
### Phase 4g — Four-tier semantic tokens + notice usage layer. Landed 2026-05-15.
Round-5 feedback (2026-05-15) flagged the muddy result of forcing one `--color-caution` to be both bright yellow (signal) and accessible text (ochre). The single-token-per-role model collapsed the visible identity.
New architecture: four-tier per-role tokens with hand-tuned surfaces, plus usage-specific notice tokens on top.
**Tier model.** Each semantic role publishes four tier-specific tokens:
| Tier | Purpose | Example (light caution) |
|---|---|---|
| `signal` | Brand-true colour. Left bars, large icons, dots, focus rings | `#FFCD00` |
| `ink` | Accessible text. Used ONLY when text itself must carry the role colour (small chips, badges). AA 4.5:1 on surface | `#7A5D00` |
| `border` | Middle value. Visible chip/notice outline; does not need AA-text contrast | `#D9A900` |
| `bg` | Hand-tuned pale tint surface. NOT a generic `color-mix` derivation | `#FFF7D6` |
CSS:
```css
--color-{role}-signal
--color-{role}-ink
--color-{role}-border
--color-{role}-bg
```
`--color-{role}` retained as a backward-compat alias pointing at `-signal`. v0.2 callers keep working; new code reaches for the specific tier.
**Usage layer.** Components subscribe to usage-specific tokens, not role-tier tokens directly. This lets per-usage retuning happen in one place:
```css
--notice-{role}-bar /* left bar background, signal-tier */
--notice-{role}-icon /* signal in dark, ink in light, signal in HC */
--notice-{role}-border /* outer border colour */
--notice-{role}-bg /* hand-tuned pale surface tint */
```
LumotiaNotice now reads these via Tailwind arbitrary-value classes (`bg-[var(--notice-info-bg)]` etc). v0.2 fallbacks defined at `:root` (outside quietware blocks) so the v0.2 surface keeps a sensible Notice render without depending on quietware.
**HC contract.** Every `-bg` token forces to `transparent`. Notices in HC render as text + icon + 2-px border + left bar with no body tint. Brand atmosphere steps fully aside.
Per Jake's round-5 spec: yellow stays yellow (visible signal), ochre only appears as small-text ink, and brown/khaki never represents the caution role's primary identity again.
### Phase 5b — Browser-preview reclassification. Landed 2026-05-15.
Targeted scope per Jake's round-4 feedback: the browser-preview state used to render as a red error block in `DictationPage.svelte`. That is an environment limitation, not a failed action. Reclassified as a slim info notice with friendlier copy: