v0.3 Phase 4d/4e: palette revision + HC rendering contract

Round-4 feedback (2026-05-15) pulled the system away from the
color.adobe.com primaries toward muted-Material values, separated
brand accent from semantic caution, and reframed high-contrast as a
behavioural rendering contract rather than a palette override.

Two phases land together because the palette revision and the HC
contract are inherently linked — HC mode needs both palette overrides
AND behavioural-token overrides to deliver "different rendering
contract" semantics.

Phase 4d palette revision.

  Dark mode (was wine-aubergine #2A1620, now brown-charcoal #12100E):
    --color-bg            #12100E
    --color-bg-elevated   #1A1713
    --color-bg-card       #211D18
    --color-bg-input      #181510
    --color-sidebar       #0F0E0C
    --color-border        #4A4035
    --color-border-subtle #2C261F

  Brand accent (new — was unset, fell through to v0.2 amber that
  competed with semantic yellow):
    Dark:  --color-accent #C97845 (copper)
    Light: --color-accent #9D5F32 (deeper copper)

  Semantic colours (muted-Material, both modes):
    Dark:  danger #FF8A8A  caution #F2C94C  success #79D59B  info #8AB4F8
    Light: danger #B3261E  caution #7A5D00  success #1B6B3A  info #2457A6

  Light mode work surface (slight paper tone, not pure white):
    --color-bg-card #FFFDF8 (was #FFFFFF)
    --color-bg-elevated #F6F1EA

  Caution fill-only-on-cream rule retires. Ochre #7A5D00 passes AA
  as foreground text on cream under the muted palette, so the single-
  token-per-role convention applies across all four semantic colours
  in both modes.

  LumotiaNotice opacity rebalance:
    Background tint  10% -> 8%
    Outer border     neutral subtle -> role at 40%
    Icon             --color-text -> role colour
    Left bar         role at 100% (unchanged)
    Title / body     --color-text (unchanged)

Phase 4e HC rendering contract.

  Behavioural tokens published alongside palette:
    --grain-opacity            0.06 dark / 0.07 light / 0 in HC
    --shadow-strength          1 default / 0 in HC
    --border-width-control     1px default / 2px in HC
    --focus-ring-width         2px default / 3px in HC
    --panel-radius             8px (reserved for future tightening)

  --quietware-texture-opacity retained as a legacy alias pointing at
  --grain-opacity so Phase 4c slider keeps working through the rename.

  HC palette: pure-black or pure-white base, the other for borders,
  single strong-focus blue #005FCC replaces accent. Brand atmosphere
  steps aside. Selector splits via :not([data-theme="light"]) so
  HC-light and HC-dark variants diverge cleanly.

Verified.

  - npm run check: 0 errors, 0 warnings across 5706 files.
  - Plan doc updated with full before/after tables, behavioural-token
    contract table, and Phase 4c / 4d / 4e log sections.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 13:50:11 +01:00
parent 4dca802f0b
commit dab9c7b5a6
3 changed files with 237 additions and 106 deletions

View File

@@ -236,6 +236,77 @@ Architectural finding: the v0.2 `SettingsPage.svelte` (2 891 LOC after Phase 4a)
Rationale: phase 4a already delivers "one section at a time" under quietware. Renaming the eight tabs to match the canonical plan (Output / Vocabulary carved out as top-level) is labelling polish, not user-value. Page-skeleton sweep (Phase 5) delivers more visible improvement per LOC. Phase 4b will return after Phase 5 lands.
### Phase 4d — Palette revision per 2026-05-15 round 4 feedback. Landed 2026-05-15.
The color.adobe.com primaries (#FF0700 / #000AFF / #00FF56 / #FFCD00) earned vividness at the cost of brand identity and accent-vs-caution discipline. Round-4 feedback pulled the system back toward muted-Material values with a clear architectural split:
```
Atmosphere = warm tactile surface
Status = red / yellow / green / blue
Brand = copper-clay amber accent (--color-accent, distinct from caution)
Accessibility = high-contrast override is a different rendering contract
```
Dark mode (revised, brown-charcoal instead of wine-aubergine):
| Token | Before (4c) | After (4d) |
|---|---|---|
| `--color-bg` | `#2A1620` | `#12100E` |
| `--color-bg-elevated` | `#34222B` | `#1A1713` |
| `--color-bg-card` | `#3E2A33` | `#211D18` |
| `--color-sidebar` | `#1F0F18` | `#0F0E0C` |
| `--color-accent` | (unset, fell through to v0.2) | `#C97845` |
| `--color-danger` | `#FF2A24` | `#FF8A8A` |
| `--color-caution` | `#FFCD00` | `#F2C94C` |
| `--color-success` | `#00FF56` | `#79D59B` |
| `--color-info` | `#7076FF` | `#8AB4F8` |
Light mode (revised, semantic values back to Material AA-friendly hues):
| Token | Before (4c) | After (4d) |
|---|---|---|
| `--color-bg-card` | `#FFFFFF` | `#FFFDF8` (warm white) |
| `--color-bg-elevated` | `#F3EEE6` | `#F6F1EA` |
| `--color-accent` | (unset) | `#9D5F32` |
| `--color-danger` | `#C54B1F` | `#B3261E` |
| `--color-caution` | `#FFCD00` (fill-only) | `#7A5D00` (passes as text) |
| `--color-success` | `#00852D` | `#1B6B3A` |
| `--color-info` | `#0047AB` | `#2457A6` |
The "caution fill-only on cream" rule retires under the muted palette. Ochre `#7A5D00` passes AA as foreground text against cream, so the same single-token-per-role convention applies across all four semantic colours in light mode.
LumotiaNotice opacity rebalance:
| Surface | Before | After |
|---|---|---|
| Background tint | role at 10% | role at 8% |
| Outer border | neutral subtle | role at 40% |
| Left bar | role full | role full (unchanged) |
| Icon | `--color-text` | role colour |
| Title / body | `--color-text` | `--color-text` (unchanged) |
### Phase 4e — High-contrast rendering contract. Landed 2026-05-15.
High-contrast is not a colour variant — it's a different rendering contract that the entire UI subscribes to. The tokens block now publishes behavioural variables alongside the palette overrides, so components can opt into the contract by reading them.
Behavioural tokens (defaults + HC values):
| Token | Default | HC |
|---|---|---|
| `--grain-opacity` | 0.06 (dark) / 0.07 (light) | 0 |
| `--shadow-strength` | 1 | 0 |
| `--border-width-control` | 1px | 2px |
| `--focus-ring-width` | 2px | 3px |
| `--panel-radius` | 8px | 8px (unchanged for now) |
`--quietware-texture-opacity` retained as a legacy alias pointing at `--grain-opacity` so Phase 4c controls keep working through the rename.
HC palette tweaks (round-4 feedback):
- **HC light** is now true pure-white background (`#FFFFFF`) + true pure-black text/borders (`#000000`). Brand atmosphere steps aside completely. Single strong-focus blue `#005FCC` replaces the accent.
- **HC dark** stays pure black `#000000` with white borders, semantic muted hues that read clearly. Matches the v0.3 dark feel but at maximum legibility.
- Hue-based selectors: `[data-design="quietware"][data-contrast="high"]` matches both base themes; the dark-base variant is scoped via `:not([data-theme="light"])` so light-base HC and dark-base HC can diverge.
### Phase 4c — Texture-opacity slider + high-contrast toggle. Landed 2026-05-15.
- New static grain overlay defined in `src/design-system/v0.3-quietware-tokens.css`. Fixed-position `body::after`, `mix-blend-mode: overlay`, opacity driven by `--quietware-texture-opacity`. Pattern generated inline via SVG `feTurbulence` (`baseFrequency=0.85`, `numOctaves=2`, `stitchTiles=stitch`). Tile size 240×240, repeated across viewport. `pointer-events: none` so the overlay never intercepts clicks. Active only under `html[data-design="quietware"]` and only on the dark and light modes — high-contrast forces opacity to 0.