Round-7 redirect (Option D): move counterlines from notices (where
they're invisible) to interactive controls (where they add identity).
Three-level model:
Level 0 no counterline panels, notices (default), content, disabled
Level 1 quiet controls, chips, active nav
1 px, 48% opacity dark / 34% light
Level 2 focus / strong keyboard focus, recording state
2 px, 85% opacity
Notices retire from default counterline rendering. Notice already
carries enough semantic language: bar + icon + border + bg + label.
A complementary inset on top was adding nothing. Notice can opt in
via <LumotiaNotice counterline ... /> when it deliberately mimics
control identity.
Token deltas vs Phase 4h.
--counterline-width: 1px unchanged
--counterline-width-focus: 2px new (Level-2 width)
--counterline-opacity-dark: 0.48 was 0.32 (raised so Level-1
actually reads on controls)
--counterline-opacity-light: 0.34 was 0.22
--counterline-opacity-focus: 0.85 new
--role-brand-counterline: #3A6BFF new (blue counter for the
orange brand accent so
primary buttons get an
identity edge like the
other roles)
--button-{role}-counterline new (per-role component tokens
subscribing to role-counterline
via color-mix)
--focus-ring-color new (defaults to brand accent;
HC overrides to #005FCC)
LumotiaButton applies counterlines to primary + destructive variants
only. Secondary + tertiary stay clean. All variants get a Level-2
focus-visible ring at --focus-ring-color * opacity-focus, with the
existing ring-offset-2 ring-offset-bg pattern.
LumotiaNotice gains a `counterline` boolean prop, default false. When
set, the previous Phase 4h inset shadow re-applies.
HC contract: counterline-width 0 + all -counterline tokens transparent.
Focus width stays 2 px because the HC focus ring IS the tactile
detail in that mode. focus-ring-color forces to #005FCC.
Honest evaluation of the visible result.
Notices: visibly cleaner without the default inset shadow. Reads
with more confidence. Good change.
Buttons: counterline applied at 1 px / 48% dark / 34% light is
perceptible at standard viewing but screenshot-zoom subtle. Focus
state implemented but not visible in static screenshots; requires
manual tab-test in the dev server.
Recommend keeping the architecture even if the visual is restrained,
because the focus-state work is genuinely valuable accessibility
scaffolding regardless of how the Level-1 reads.
Verified.
- npm run check: 0 errors, 0 warnings across 5707 files.
Phase 5c (Dictation layout migration) still queued for a focused
fresh sitting. This commit does not block it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
478 lines
30 KiB
Markdown
478 lines
30 KiB
Markdown
# Lumotia v0.3 — Tactile Quietware
|
||
|
||
> Calm enough for overloaded brains, structured enough to recover thoughts, tactile enough to feel like a local desktop tool rather than SaaS.
|
||
|
||
The v0.3 release reframes Lumotia around one thesis: a low-cognitive-load capture instrument. Built on the WCAG 2.2 + W3C COGA + NN/G evidence base, validated against the four HMRC accessibility personas that map most directly onto a dictation-first desktop tool.
|
||
|
||
This document is the single source of truth for v0.3. Phase log, regression diary, palette spec and font stack all live here.
|
||
|
||
---
|
||
|
||
## Source brief
|
||
|
||
Locked 2026-05-15 from Jake's design brief and three rounds of capture-pipeline iteration.
|
||
|
||
- Palette: `inputs/inbox/2026-05-15-lumotia-colour-layout-changes.md` plus the colour-palette refinements at `inputs/inbox/2026-05-15-re-lumotia-v03-renders-revised-palette-typography-.md`.
|
||
- Personas: HMRC Virtual Empathy Hub, eight personas at `https://personas-prototype.herokuapp.com/`.
|
||
- Accessibility tools: DfE manual at `https://accessibility.education.gov.uk/tools-testing/tools`.
|
||
|
||
## Rule set
|
||
|
||
The five rules every v0.3 PR has to clear.
|
||
|
||
| Rule | Meaning |
|
||
|---|---|
|
||
| Texture = atmosphere | Static global grain. No per-panel noise. No motion. Default 6%, slider 5 to 8% in advanced. |
|
||
| Colour = status | Brand palette IS the semantic palette. Brand chroma earns its keep by signalling state. Decorative colour is forbidden. |
|
||
| Layout = calm | Every page uses the same skeleton. Files, Tasks, History and Dictation must not invent their own structure. |
|
||
| Motion = feedback only | Animation only for recording, loading, success and failure. Honour `prefers-reduced-motion` at root. |
|
||
| Settings = progressive disclosure | One sectional tab visible at a time. Eight tabs. No long scroll. |
|
||
|
||
---
|
||
|
||
## Palette
|
||
|
||
Locked 2026-05-15 from Jake's color.adobe.com primaries. Each primary is used literally where it clears WCAG AA on the relevant background. Where it does not, a text-safe sibling at the same hue and saturation is derived.
|
||
|
||
### Source primaries
|
||
|
||
| Role | Primary | Hue | Notes |
|
||
|---|---|---|---|
|
||
| `--danger` | `#FF0700` | 2deg | Pure red |
|
||
| `--info` | `#000AFF` | 238deg | Pure blue |
|
||
| `--success` | `#00FF56` | 140deg | Pure green |
|
||
| `--caution` | `#FFCD00` | 48deg | Pure yellow |
|
||
|
||
### Light mode
|
||
|
||
Cream paper base. Jake's blue passes AAA on cream and is used literally. The other three are darkened siblings for AA text contrast, with caution kept fill-only because any darkened yellow reads as olive or mustard ("looks like poop").
|
||
|
||
| Token | Hex | Contrast on `#FBF8F2` | Notes |
|
||
|---|---|---|---|
|
||
| `--color-bg` | `#FBF8F2` | Base | Cream paper |
|
||
| `--color-text` | `#1D1B18` | 14.43 AAA | Near-black |
|
||
| `--color-info` | `#000AFF` | 7.96 AAA | Jake literal |
|
||
| `--color-danger` | `#E60600` | 4.51 AA | Sibling derived from `#FF0700` |
|
||
| `--color-success` | `#00852D` | 4.51 AA | Sibling derived from `#00FF56` |
|
||
| `--color-caution` | `#FFCD00` | 1.42 (fill-only) | Jake literal, fill-only convention |
|
||
|
||
**Caution is fill-only on cream.** Pill backgrounds, dots, left-border accents and icons take `--color-caution`. Foreground text inside a caution-coloured pill stays `--color-text`. Matches Material, GOV.UK and IBM Carbon practice.
|
||
|
||
### Dark mode
|
||
|
||
Lifted Coffee Bean base. Jake's green and yellow primaries already clear AAA on the dark surface and are used literally. Red and blue need lifting because pure-saturated dark hues fail against a dark background.
|
||
|
||
| Token | Hex | Contrast on `#2A1620` | Notes |
|
||
|---|---|---|---|
|
||
| `--color-bg` | `#2A1620` | Base | Lifted Coffee Bean |
|
||
| `--color-text` | `#F3EFE7` | 13.85 AAA | |
|
||
| `--color-info` | `#7076FF` | 4.64 AA | Lifted from `#000AFF` |
|
||
| `--color-danger` | `#FF2A24` | 4.54 AA | Lifted from `#FF0700` |
|
||
| `--color-success` | `#00FF56` | 12.51 AAA | Jake literal |
|
||
| `--color-caution` | `#FFCD00` | 11.33 AAA | Jake literal |
|
||
|
||
### High contrast mode
|
||
|
||
Same four hues retained so role recognition does not flip between modes. Saturation 80%, lightness 70%. Zero texture, no translucent overlays.
|
||
|
||
| Token | Hex | Contrast on black |
|
||
|---|---|---|
|
||
| `--color-bg` | `#000000` | Base |
|
||
| `--color-text` | `#FFFFFF` | 21.00 AAA |
|
||
| `--color-info` | `#757AF0` | 5.80 AA |
|
||
| `--color-danger` | `#F07975` | 7.70 AAA |
|
||
| `--color-success` | `#75F09F` | 14.72 AAA |
|
||
| `--color-caution` | `#F0D875` | 14.78 AAA |
|
||
|
||
---
|
||
|
||
## Typography stack (V4 pairing, locked 2026-05-15)
|
||
|
||
Three production fonts. Self-hosted as WOFF2. No CDN dependency.
|
||
|
||
| Role | Font | Licence | Used for |
|
||
|---|---|---|---|
|
||
| Body and UI | Work Sans (variable) | OFL | Headers, labels, controls, sidebar, body, transcript surface |
|
||
| Brand moments | Young Serif | OFL | Wordmark, splash, empty-state hook copy, About modal |
|
||
| Mono | JetBrains Mono | Apache 2.0 | Logs, model IDs, file paths, hotkey strings |
|
||
|
||
Atkinson Hyperlegible Next and OpenDyslexic stay as opt-in accessibility fonts via Settings. Archivo, Lexend and Instrument Serif from v0.2 stay shipped during v0.3 transition; future release may remove them after persona testing.
|
||
|
||
---
|
||
|
||
## Persona test gates
|
||
|
||
Each phase must pass these four manual gates before merge. Tools and tasks from the DfE manual.
|
||
|
||
| Persona | Condition simulated | Primary risk for Lumotia | Gate |
|
||
|---|---|---|---|
|
||
| Pawel | Autistic | Sensory load, predictability, motion sensitivity | Empty states speak. No surprise motion. Same skeleton on every page. |
|
||
| Simone | Dyslexic | Transcript readability, dense paragraphs | Transcript body uses Work Sans at 16px minimum, line-height ≥ 1.6, comfortable measure. |
|
||
| Chris | Rheumatoid arthritis | Click target size, keyboard fallback for every action | All interactive targets ≥ 44 x 44 px. Every action reachable by keyboard with visible focus ring. |
|
||
| Ron | Older user, multiple conditions | Combined: vision + cognitive + motor | All three of the above hold simultaneously. |
|
||
|
||
Medium-priority personas (Claudia magnifier, Saleem deaf) get explicit checks at Phase 5. Lower-priority personas (Ashleigh screen reader, Helena dyscalculia) get checks at v0.4.
|
||
|
||
---
|
||
|
||
## Phase 0 — Accessibility tools checklist
|
||
|
||
Manual gov.uk DfE tools applied to every v0.3 phase before merge. Tools that map onto a Tauri webview tested via the same browser-preview surface already shipped in v0.2.
|
||
|
||
- [ ] Contrast Checker. All palette pairs verified against WCAG AA. Annotated in the relevant phase commit message.
|
||
- [ ] axe DevTools. Run on every page after the phase migrates it.
|
||
- [ ] Resize Text. 200% zoom does not break any layout.
|
||
- [ ] Text Spacing. Increased letter, word, line spacing per WCAG 1.4.12 does not clip content.
|
||
- [ ] Target Size. All interactive targets ≥ 44 x 44 px (WCAG 2.5.8).
|
||
- [ ] HeadingsMap. Settings sectional refactor preserves a sensible h1 → h6 hierarchy.
|
||
- [ ] Blur. Smoke check that primary actions remain legible under simulated low vision.
|
||
- [ ] Screen reader smoke test. NVDA or Orca on the Settings page after Phase 3.
|
||
|
||
A future-Phase CI step will automate axe-core + contrast checks. Out of scope for v0.3 per Jake's 2026-05-15 decision.
|
||
|
||
---
|
||
|
||
## Phase plan
|
||
|
||
Each phase ships as its own PR. Each is flag-gated by `html[data-design="quietware"]`. The current v0.2 user-facing surface is unaffected until Phase 6 promotes quietware to the default.
|
||
|
||
### Phase 1 — Tokens. (this PR)
|
||
|
||
- New file `src/design-system/v0.3-quietware-tokens.css` with three palette scopes (dark, light, high-contrast).
|
||
- Self-hosted Work Sans (variable), Work Sans Italic (variable), Young Serif (static) at `src/fonts/`.
|
||
- Import wired in `src/app.css` directly after the tailwind import. Inert until `data-design="quietware"` is present on `<html>`.
|
||
- No component changes. No behavioural changes.
|
||
|
||
### Phase 2 — Build flag wiring.
|
||
|
||
- `VITE_LUMOTIA_QUIETWARE=1` build-time env var sets `data-design="quietware"` on `<html>` via `src/routes/+layout.svelte`.
|
||
- Manual override path stays: dev tools, or a Settings toggle gated behind the same flag.
|
||
|
||
### Phase 3 — Status grammar primitives.
|
||
|
||
- `LumotiaStatusPill`, `LumotiaNotice` with icon + label + body + actions.
|
||
- Caution is fill-only across both. Foreground text uses `--color-text`.
|
||
- Component preview added to `src/routes/design-system-v2/`.
|
||
|
||
### Phase 4 — Settings sectional refactor.
|
||
|
||
- Split the 2 791 LOC `SettingsPage.svelte` across eight tabs: Start Here, Models, Output, Vocabulary, Tasks, Accessibility, Privacy, Advanced.
|
||
- Texture-opacity slider lives in Accessibility. Range 0.05 to 0.08. Default 0.06.
|
||
- High-contrast toggle in Accessibility. Toggle overrides system `prefers-contrast` query when set.
|
||
- One section visible at a time. No long-scroll.
|
||
|
||
### Phase 5 — Critical-path simplification.
|
||
|
||
- Dictation page: header + transcript surface + action rail + empty state. No cockpit furniture.
|
||
- Files, Tasks, History migrated to the shared page skeleton (left nav, header, optional toolbar, primary work surface, optional right drawer, status row).
|
||
- Empty states speak on all four pages.
|
||
- Persona-test gates for Pawel, Simone, Chris, Ron at this phase.
|
||
|
||
### Phase 6 — Icon and wordmark integration.
|
||
|
||
- Real Lumotia wordmark + mark lifted from brand-proposal v1 colophon. Replaces the placeholder swirl.
|
||
- Surfaces: window icon (.ico, .icns, multi-size .png), splash, About modal, empty-state anchor, status-pill leading glyph for "Ready".
|
||
- Removes any remaining Magnotia / Wyrdnote / Kon-era assets.
|
||
|
||
### Phase 7 — Motion audit. (final v0.3 polish)
|
||
|
||
- Inventory every animation, transition and decorative motion currently in the app.
|
||
- Keep: recording-active heartbeat, loading spinner, success / failure feedback.
|
||
- Strip: decorative pulse, animated background, sliding panels, attention shimmer.
|
||
- `prefers-reduced-motion` reducer set at the root selector for quietware (already in tokens CSS).
|
||
|
||
### Phase 8 — Promote to default. (post-release decision)
|
||
|
||
- Flip `<html data-design="quietware">` to be the default; remove the flag.
|
||
- Either lands as a major release (v1.0) or stays opt-in indefinitely.
|
||
- This decision is deferred to after Phase 6 user testing.
|
||
|
||
---
|
||
|
||
## Phase log
|
||
|
||
### Phase 1 — Tokens. Landed 2026-05-15.
|
||
|
||
- `src/design-system/v0.3-quietware-tokens.css` written. 5.7 KB.
|
||
- Three WOFF2 fonts added at `src/fonts/`: `work-sans-variable.woff2`, `work-sans-italic-variable.woff2`, `young-serif.woff2`. 287 KB total.
|
||
- `src/app.css` imports the new tokens file directly after `@import "tailwindcss"`.
|
||
- Inert without `data-design="quietware"` on `<html>`. v0.2 surface unaffected.
|
||
- Verified by visual inspection. Manual activation via dev tools toggling the attribute.
|
||
- Palette iterated three times this session (brand-as-semantic → cobalt-pegged square → color.adobe.com primaries). Final values locked in commit on amendment.
|
||
|
||
### Phase 2 — Build flag wiring. Landed 2026-05-15.
|
||
|
||
- `src/routes/+layout.svelte` extended with a `$effect` block that reads `import.meta.env.VITE_LUMOTIA_QUIETWARE` at runtime and sets `<html data-design="quietware">` when the flag is `"1"`.
|
||
- Hot-reload safety: if the env var is unset between dev rebuilds, the attribute is cleared.
|
||
- Activation: `VITE_LUMOTIA_QUIETWARE=1 npm run dev` (or `npm run build`) lights up the quietware tokens. Without the env var, app renders v0.2 unchanged.
|
||
- Combine with `data-theme="light"` and `data-contrast="high"` (already wired by v0.2) to reach the light and high-contrast quietware modes.
|
||
- No new dependencies. No bundle-size impact in the off path.
|
||
|
||
### Phase 3 — Status grammar primitives. Landed 2026-05-15.
|
||
|
||
Architectural finding: both `LumotiaStatusPill` and `LumotiaNotice` already shipped in v0.2 Phase 5. Phase 3 became an audit-and-adapt task rather than a new-component build.
|
||
|
||
- `LumotiaStatusPill` ([src/lib/components/StatusPill.svelte](../../src/lib/components/StatusPill.svelte)) audited. Pattern is already accessibility-correct: neutral pill background + neutral label text + role colour confined to a 6×6 px dot. Colour is supplementary, label is always perceivable. Works unchanged across all three quietware modes. No changes shipped.
|
||
|
||
- `LumotiaNotice` ([src/lib/ui/LumotiaNotice.svelte](../../src/lib/ui/LumotiaNotice.svelte)) refactored to the left-bar accent pattern. Old version put the role colour on the icon + outline; in quietware light mode that rendered a bright `#FFCD00` caution icon faded against cream paper. New version places the role signal on a 4-px solid left border (visible at any contrast level), with the rest of the surround as a soft tone-tinted background plus subtle neutral outer border. Icon, title and body text all use `--color-text`. Matches Material "banner with leading accent" and IBM Carbon "inline notification" guidance. ARIA semantics (`role="alert"` for danger, `role="status"` for the rest) preserved.
|
||
|
||
- Design-system-v2 preview route already imports `LumotiaNotice` and `LumotiaStatusPill`. The updated Notice renders correctly there with the existing preview content; no additional preview wiring needed.
|
||
|
||
- All four tones (info / caution / danger / success) verified by the pattern itself: the visible signal is the left bar, which is `border-l-{tone}` at 100% opacity, working at any colour intensity. Caution remains a fill-only convention on cream by design.
|
||
|
||
### Phase 4a — Settings tab shell. Landed 2026-05-15.
|
||
|
||
Architectural finding: the v0.2 `SettingsPage.svelte` (2 891 LOC after Phase 4a) was already structured as eight numbered sections that align almost 1:1 with the v0.3 plan. The cheapest path to "one section visible at a time" is therefore a tab-shell overlay rather than a file split. Behaviour stays identical to v0.2 when quietware is off; with quietware on, only the active tab's section renders.
|
||
|
||
- New `LumotiaSettingsTabs.svelte` ([src/lib/ui/LumotiaSettingsTabs.svelte](../../src/lib/ui/LumotiaSettingsTabs.svelte)) implements the WAI-ARIA tabs (automatic activation) pattern. Arrow / Home / End keyboard navigation. Active tab uses the brand left-bar accent (`border-l-caution`) so it carries the same grammar as the LumotiaNotice refactor.
|
||
|
||
- `SettingsPage.svelte` gained a small reactive `isQuietware` flag, a `MutationObserver` watching `<html data-design>`, and 8 `{#if !isQuietware || activeTab === 'X'}` wrappers around the existing eight top-level `<SettingsGroup>` sections. The settings tree is unchanged; only its top-level rendering gate changed.
|
||
|
||
- v0.2 fallback behaviour: when `data-design="quietware"` is absent the tablist does not render and all eight sections stack as before. The search filter still spans every section in v0.2 mode. This is the smallest-possible behavioural change for "one section at a time".
|
||
|
||
- Tab IDs in this commit map 1:1 to existing v0.2 section names (start-here / transcription / models / tasks / accessibility / privacy / advanced / help). Phase 4b will restructure to match the plan's canonical names (carving Output from Advanced and Vocabulary from Transcription).
|
||
|
||
### Phase 4b — Settings restructure to canonical tab names. Deferred to post-Phase-5.
|
||
|
||
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 4f — Semantic source / derived token architecture. Landed 2026-05-15.
|
||
|
||
Round-4 feedback formalised the relationship between the brand-source palette and the theme-derived semantic tokens. Source tokens are stable across all themes (they encode the role's hue identity); derived tokens are theme-tuned to meet WCAG AA in context.
|
||
|
||
Added to `src/design-system/v0.3-quietware-tokens.css`:
|
||
|
||
```css
|
||
:root[data-design="quietware"] {
|
||
--semantic-red-source: #FF0700; /* error / failed / destructive / blocked */
|
||
--semantic-yellow-source: #FFCD00; /* needs review / caution / pending */
|
||
--semantic-green-source: #00FF56; /* ready / saved / complete / safe */
|
||
--semantic-blue-source: #000AFF; /* info / processing / system guidance */
|
||
}
|
||
```
|
||
|
||
The existing `--color-{danger,caution,success,info}` tokens are documented as derivations of these sources, retuned per theme (muted-Material values in normal modes, clarity-first values in HC). New `--color-{role}-bg` subtle-fill tokens derived via `color-mix(in oklab, var(--color-{role}) 8%, transparent)` — used by Notice backgrounds, hover tints and focus halos. HC mode forces all `-bg` tokens to `transparent` so HC notices render as text + icon + 2-px border + left bar with no body tint.
|
||
|
||
### Phase 5a — Page skeleton primitive + slim notice variant. Landed 2026-05-15.
|
||
|
||
Foundation for the page-skeleton sweep without yet migrating any page. Two additions:
|
||
|
||
- **`LumotiaPageSkeleton.svelte`** ([src/lib/ui/](../../src/lib/ui/LumotiaPageSkeleton.svelte)) — six-zone layout used by every quietware page: header / optional slim notice / primary work surface / optional right rail / optional bottom action bar / optional mono metadata footer. Sidebar lives in AppChrome above the skeleton. Every snippet is optional except `primary`. `primaryBleed` prop drops the surface's inner card chrome for full-bleed transcript canvases.
|
||
|
||
- **`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 4i — Counterlines as interaction-affordance identity. Landed 2026-05-15.
|
||
|
||
Round-7 redirect (Option D): move counterlines from notices (where they're invisible) to interactive controls (where they add identity). Three-level model:
|
||
|
||
| Level | Surface | Width | Opacity |
|
||
|---|---|---|---|
|
||
| 0 — none | panels, notices (default), content, disabled | — | — |
|
||
| 1 — quiet | controls, chips, active nav | 1 px | 48% dark / 34% light |
|
||
| 2 — focus | keyboard focus, recording state | 2 px | 85% |
|
||
|
||
Notice retires from default counterline rendering. Opt-in via `<LumotiaNotice counterline ... />` when a specific notice deliberately mimics control identity.
|
||
|
||
LumotiaButton primary + destructive variants gain a Level-1 inset counterline:
|
||
|
||
- primary: `--button-brand-counterline` (softened blue, complement of brand amber)
|
||
- destructive: `--button-danger-counterline` (softened blue, complement of red)
|
||
- secondary / tertiary: no counterline (clean neutral)
|
||
- All variants on `:focus-visible`: 2-px ring at `--focus-ring-color` (default `--color-accent`) at 85% opacity. HC overrides to a strong blue `#005FCC`.
|
||
|
||
Token deltas vs Phase 4h:
|
||
|
||
```css
|
||
--counterline-width: 1px /* unchanged */
|
||
--counterline-width-focus: 2px /* new — Level-2 width */
|
||
--counterline-opacity-dark: 0.48 /* was 0.32 */
|
||
--counterline-opacity-light: 0.34 /* was 0.22 */
|
||
--counterline-opacity-focus: 0.85 /* new */
|
||
--role-brand-counterline: #3A6BFF /* new — blue counter for orange brand */
|
||
--button-{role}-counterline /* new — per-role component tokens */
|
||
--focus-ring-color /* new — context-overridable focus tint */
|
||
```
|
||
|
||
HC contract: every counterline token forced transparent, `--counterline-width: 0`, focus width kept at 2 px (HC focus ring carries the tactile detail in that mode), `--focus-ring-color: #005FCC`.
|
||
|
||
### Phase 4h — Counterlines test (RETIRED 2026-05-15, superseded by Phase 4i). Landed 2026-05-15.
|
||
|
||
Test commit per Jake's round-6 spec. Subtle 1-px inner-shadow detail in a softened complementary hue, applied to LumotiaNotice only. Other test surfaces (Button.destructive, status pills, record ring, active nav) reserved for after evaluation.
|
||
|
||
Tokens added under quietware scope:
|
||
|
||
```css
|
||
--counterline-width: 1px;
|
||
|
||
--role-info-counterline: var(--color-accent); /* copper for blue */
|
||
--role-danger-counterline: #6EA8FF; /* soft blue for red */
|
||
--role-success-counterline: #B891FF; /* soft violet for green */
|
||
--role-caution-counterline: #3A6BFF; /* soft blue for yellow */
|
||
|
||
--notice-{role}-counterline: color-mix(in srgb, <role-counterline> {32% dark / 22% light}, transparent)
|
||
```
|
||
|
||
HC contract: `--counterline-width: 0`, all counterline tokens forced to `transparent`. The 2-px HC border IS the tactile detail in that mode.
|
||
|
||
LumotiaNotice applies the counterline via Tailwind arbitrary value:
|
||
|
||
```svelte
|
||
shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-{tone}-counterline,transparent)]
|
||
```
|
||
|
||
**Honest evaluation.** At 1px / 22% light / 32% dark opacity the effect is whisper-quiet to the point of being almost invisible at standard viewing. Doesn't look noisy (which was the risk Jake flagged), but also doesn't add perceptible tactility. Pending Jake's call: keep with raised opacity (perhaps 45% dark / 35% light), keep at current opacity for the quietness, or revert. Phase 5c proceeds either way.
|
||
|
||
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:
|
||
|
||
```
|
||
Old: bg-danger/10 border-danger/20, red text, technical-details affordance
|
||
New: LumotiaNotice tone="info" slim, "You're in a browser preview. Local
|
||
transcription only works in the Lumotia desktop app."
|
||
```
|
||
|
||
Other error states (transcription failed, needs review) still render through the original danger-tinted block with the technical-details `<details>` affordance preserved. Only the browser-preview path branches into the info-classed notice.
|
||
|
||
The larger Dictation page restructure (header recomposition, Template/Extract Tasks demotion to bottom action bar, empty-state typography) is reserved for a focused Phase 5c sitting — `DictationPage.svelte` is 1 262 LOC of state-heavy code and warrants surgical attention rather than a tail-end rush.
|
||
|
||
### 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.
|
||
- New `QuietwareAccessibilityControls.svelte` ([src/lib/components/](../../src/lib/components/QuietwareAccessibilityControls.svelte)) ships two controls:
|
||
- **High-contrast toggle**, wired through `LumotiaToggle`. Sets `<html data-contrast="high">` so the quietware HC palette block in the tokens CSS activates. Persists via `localStorage`. Overrides the OS `prefers-contrast: more` query when explicitly enabled.
|
||
- **Texture-intensity slider**, range 0.05–0.08, step 0.005, default 0.06. Sets the `--quietware-texture-opacity` CSS variable inline on `<html>` so it overrides the per-mode default in the tokens CSS. Disabled when high-contrast mode is on. Reset button restores the 0.06 default.
|
||
- Component injected into `SettingsPage.svelte` inside the Accessibility section, gated by `{#if isQuietware}`. v0.2 fallback unaffected.
|
||
- Persistence path: localStorage keys `lumotia:quietware:high-contrast` and `lumotia:quietware:texture-opacity`. Full integration with the central `Preferences` store is a follow-up; localStorage keeps Phase 4c contained.
|
||
- Verified: `npm run check` reports 0 errors, 0 warnings across 5706 files.
|
||
|
||
---
|
||
|
||
## Regression diary
|
||
|
||
Empty. Update inline as findings emerge per phase.
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
- Source brief: `inputs/inbox/2026-05-15-lumotia-colour-layout-changes.md`.
|
||
- Palette refinement round 1 (brand-as-semantic): `inputs/inbox/2026-05-15-re-lumotia-v03-renders-revised-palette-typography-.md`.
|
||
- Palette refinement round 2 (cobalt-square peg): chat decision 2026-05-15.
|
||
- Palette refinement round 3 (color.adobe.com primaries): `inputs/inbox/2026-05-15-re-lumotia-v03-phase-1-landed-cobalt-pegged-square.md` + attached `2.jpeg`. Locked.
|
||
- W3C COGA: `https://www.w3.org/TR/coga-usable/`.
|
||
- WCAG 2.2 Understanding docs: `https://www.w3.org/WAI/WCAG22/Understanding/`.
|
||
- HMRC accessibility personas: `https://personas-prototype.herokuapp.com/`.
|
||
- DfE accessibility tools manual: `https://accessibility.education.gov.uk/tools-testing/tools`.
|
||
- v0.2 release doc: `docs/release/v0.2-frontend-overhaul.md` (predecessor; reference patterns).
|