diff --git a/docs/release/v0.3-tactile-quietware.md b/docs/release/v0.3-tactile-quietware.md new file mode 100644 index 0000000..ea47d5c --- /dev/null +++ b/docs/release/v0.3-tactile-quietware.md @@ -0,0 +1,223 @@ +# 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 + +Strict 90-degree square colour harmony pegged at cobalt blue. Locked 2026-05-15. + +Cobalt blue `#0047AB` is the peg. The other three semantic roles sit at exactly 90, 180 and 270 degrees from cobalt on the colour wheel: + +| Hue offset from cobalt | Hue value | Role | Visual character | +|---|---|---|---| +| 0deg | 215deg | `--info` | Cobalt blue | +| +90deg | 305deg | `--danger` | Magenta-pink | +| +180deg | 35deg | `--caution` | Orange-amber | +| +270deg | 125deg | `--success` | Yellow-green | + +Saturation locked at 100%. Lightness adjusted per role to clear WCAG AA 4.5:1 on the relevant background. Yellow and green are perceptually brighter than blue and magenta at the same numeric L, so caution and success use darker L values in light mode. This is perceptual-lightness compensation, not a break from the square geometry. + +### Light mode + +Cobalt literal on cream paper. Other roles match cobalt's saturation; lightness shifts per role for AA. + +| Token | Hex | Hue | L | Contrast on `#FBF8F2` | +|---|---|---|---|---| +| `--color-bg` | `#FBF8F2` | — | — | Base | +| `--color-text` | `#1D1B18` | — | — | 14.43 AAA | +| `--color-info` | `#0047AB` | 215deg | 34% | 7.96 AAA | +| `--color-danger` | `#AB009C` | 305deg | 34% | 6.17 AAA | +| `--color-caution` | `#A76200` | 35deg | 33% | 4.51 AA | +| `--color-success` | `#00850B` | 125deg | 26% | 4.54 AA | + +**Caution remains a fill-only convention on cream.** Even at L=33%, an amber against cream sits close to the AA floor. Pill backgrounds, dots, left-border accents and icons take `--color-caution`. Foreground text inside a caution-coloured pill stays `--color-text`. This matches Material, GOV.UK and IBM Carbon practice and keeps a single token per role intact. + +### Dark mode + +Lifted Coffee Bean base. Same four hues, lightness lifted for AA. + +| Token | Hex | Hue | L | Contrast on `#2A1620` | +|---|---|---|---|---| +| `--color-bg` | `#2A1620` | — | — | Base | +| `--color-text` | `#F3EFE7` | — | — | 13.85 AAA | +| `--color-info` | `#247FFF` | 215deg | 57% | 4.50 AA | +| `--color-danger` | `#EC00D8` | 305deg | 46% | 4.50 AA | +| `--color-caution` | `#C07000` | 35deg | 38% | 4.50 AA | +| `--color-success` | `#00AB0E` | 125deg | 34% | 5.54 AA | + +### High contrast mode + +Same four hues retained so role recognition does not flip between modes. Saturation 80%, lightness 70%. + +| Token | Hex | Contrast on black | +|---|---|---| +| `--color-bg` | `#000000` | Base | +| `--color-text` | `#FFFFFF` | 21.00 AAA | +| `--color-info` | `#75A8F0` | 8.62 AAA | +| `--color-danger` | `#F075E5` | 8.38 AAA | +| `--color-caution` | `#F0BD75` | 12.24 AAA | +| `--color-success` | `#75F080` | 14.53 AAA | + +No texture in high-contrast mode. No translucent overlays. + +--- + +## 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 ``. +- No component changes. No behavioural changes. + +### Phase 2 — Build flag wiring. + +- `VITE_LUMOTIA_QUIETWARE=1` build-time env var sets `data-design="quietware"` on `` 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 `` 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. 4.0 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 ``. v0.2 surface unaffected. +- Verified by visual inspection. Manual activation via dev tools toggling the attribute. + +--- + +## 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: `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, captured in this doc. +- 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). diff --git a/src/app.css b/src/app.css index 582fe89..2e188c3 100644 --- a/src/app.css +++ b/src/app.css @@ -48,6 +48,10 @@ @import "tailwindcss"; +/* v0.3 Tactile Quietware tokens. Inert until . + See docs/release/v0.3-tactile-quietware.md and design-system/v0.3-quietware-tokens.css. */ +@import "./design-system/v0.3-quietware-tokens.css"; + /* === Lumotia Design Tokens === */ @theme { /* Surfaces — warm layered depth */ diff --git a/src/design-system/v0.3-quietware-tokens.css b/src/design-system/v0.3-quietware-tokens.css new file mode 100644 index 0000000..da6c57b --- /dev/null +++ b/src/design-system/v0.3-quietware-tokens.css @@ -0,0 +1,186 @@ +/* ============================================================ + Lumotia v0.3 — Tactile Quietware tokens. + + Phase 1 of the v0.3 release. Tokens only. No component refactors, + no layout changes, no behavioural shifts. The new palette and + typography activate only when html[data-design="quietware"] is set. + + When the attribute is absent the runtime app behaves exactly as it + did in v0.2. + + Activation paths: + 1. Manual: add data-design="quietware" to via dev tools. + 2. Build flag (Phase 2): VITE_LUMOTIA_QUIETWARE=1 will wire the + attribute through +layout.svelte automatically. + + -------------------------------------------------------------- + Palette geometry: strict 90-degree square colour harmony, + pegged at cobalt blue #0047AB. + + Hue spacing fixed at 90 degrees from cobalt: + --info 215deg (cobalt blue, the peg) + --danger 305deg (magenta-pink) + --caution 35deg (orange-amber) + --success 125deg (yellow-green) + + Saturation locked at 100%. Lightness adjusted per role to clear + WCAG AA 4.5:1 on the relevant background. Yellow and green are + perceptually brighter than blue and magenta at the same numeric L, + so caution and success use slightly darker L values in light mode. + This is perceptual-lightness compensation, not a break from the + square geometry. + + Caution stays a fill-only role on cream paper. Bright caution + tones fail 4.5:1 as text on cream regardless of lightness. + Pill backgrounds, dots, left-border accents and icons take + --color-caution. Foreground text inside caution-coloured pills + stays --color-text. + + Typography stack (V4 pairing, locked 2026-05-15): + Work Sans -> body, UI, controls, headers + Young Serif -> brand moments only (wordmark, empty-state hook) + JetBrains Mono -> logs, paths, model IDs + + Source brief: docs/release/v0.3-tactile-quietware.md. + ============================================================ */ + +@font-face { + font-family: 'Work Sans'; + src: url('/fonts/work-sans-variable.woff2') format('woff2-variations'), + url('/fonts/work-sans-variable.woff2') format('woff2'); + font-weight: 100 900; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'Work Sans'; + src: url('/fonts/work-sans-italic-variable.woff2') format('woff2-variations'), + url('/fonts/work-sans-italic-variable.woff2') format('woff2'); + font-weight: 100 900; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: 'Young Serif'; + src: url('/fonts/young-serif.woff2') format('woff2'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +/* ============================================================ + Quietware — dark mode default. + Lifted Coffee Bean base. Square-harmony hues, L lifted for AA + on the dark surface. + ============================================================ */ +:root[data-design="quietware"] { + --color-bg: #2A1620; + --color-bg-elevated: #34222B; + --color-bg-card: #3E2A33; + --color-bg-input: #281620; + --color-border: #6B4D58; + --color-border-subtle: #4E3742; + + --color-text: #F3EFE7; + --color-text-secondary: #BDB6A9; + --color-text-tertiary: #8D8577; + + --color-info: #247FFF; + --color-danger: #EC00D8; + --color-caution: #C07000; + --color-warning: var(--color-caution); + --color-success: #00AB0E; + + --color-sidebar: #1F0F18; + --color-nav-active: #3E2A33; + --color-hover: #34222B; + --color-overlay-dim: rgba(31, 8, 18, 0.7); + + --font-family-body: 'Work Sans', system-ui, sans-serif; + --font-family-display: 'Young Serif', serif; + --font-family-mono: 'JetBrains Mono', monospace; + + /* Texture intensity. 0.06 baseline, slider range 0.05 to 0.08 in advanced. */ + --quietware-texture-opacity: 0.06; + --quietware-texture-color: rgba(243, 239, 231, 1); +} + +/* ============================================================ + Quietware — light mode. + Cream paper base. Cobalt blue #0047AB appears literally as --info. + Other three roles share cobalt's hue offsets (90 / 180 / 270 deg) + with L adjusted per role to clear WCAG AA 4.5:1 on cream. + ============================================================ */ +:root[data-design="quietware"][data-theme="light"] { + --color-bg: #FBF8F2; + --color-bg-elevated: #F3EEE6; + --color-bg-card: #FFFFFF; + --color-bg-input: #F3EEE6; + --color-border: #897D70; + --color-border-subtle: #D8D0C4; + + --color-text: #1D1B18; + --color-text-secondary: #5E574C; + --color-text-tertiary: #74685B; + + --color-info: #0047AB; /* cobalt peg, 215deg, AAA on cream */ + --color-danger: #AB009C; /* 305deg, AA on cream */ + --color-caution: #A76200; /* 35deg, AA on cream */ + --color-warning: var(--color-caution); + --color-success: #00850B; /* 125deg, AA on cream */ + + --color-sidebar: #F3EEE6; + --color-nav-active: #E8E2D6; + --color-hover: #EAE4D8; + --color-overlay-dim: rgba(29, 27, 24, 0.55); + + --quietware-texture-opacity: 0.07; + --quietware-texture-color: rgba(29, 27, 24, 1); +} + +/* ============================================================ + Quietware — high-contrast mode. + Brand chroma steps aside. S=80%, L=70%. Zero texture. + Same four hues retained so role recognition does not flip. + ============================================================ */ +:root[data-design="quietware"][data-contrast="high"] { + --color-bg: #000000; + --color-bg-elevated: #0A0A0A; + --color-bg-card: #111111; + --color-bg-input: #050505; + --color-border: #FFFFFF; + --color-border-subtle: #888888; + + --color-text: #FFFFFF; + --color-text-secondary: #DADADA; + --color-text-tertiary: #C8C8C8; + + --color-info: #75A8F0; + --color-danger: #F075E5; + --color-caution: #F0BD75; + --color-warning: var(--color-caution); + --color-success: #75F080; + + --color-sidebar: #000000; + --color-nav-active: #1A1A1A; + --color-hover: #1A1A1A; + --color-overlay-dim: rgba(0, 0, 0, 0.85); + + /* No texture in high contrast. Clarity over atmosphere. */ + --quietware-texture-opacity: 0; + --quietware-texture-color: rgba(0, 0, 0, 0); +} + +/* ============================================================ + Reduced motion. Honour OS preference; quietware rules require it. + ============================================================ */ +@media (prefers-reduced-motion: reduce) { + :root[data-design="quietware"] * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/src/fonts/work-sans-italic-variable.woff2 b/src/fonts/work-sans-italic-variable.woff2 new file mode 100644 index 0000000..ca6fcb7 Binary files /dev/null and b/src/fonts/work-sans-italic-variable.woff2 differ diff --git a/src/fonts/work-sans-variable.woff2 b/src/fonts/work-sans-variable.woff2 new file mode 100644 index 0000000..8bcc1cb Binary files /dev/null and b/src/fonts/work-sans-variable.woff2 differ diff --git a/src/fonts/young-serif.woff2 b/src/fonts/young-serif.woff2 new file mode 100644 index 0000000..fe31337 Binary files /dev/null and b/src/fonts/young-serif.woff2 differ