diff --git a/docs/release/v0.3-tactile-quietware.md b/docs/release/v0.3-tactile-quietware.md index 7789b52..41042d6 100644 --- a/docs/release/v0.3-tactile-quietware.md +++ b/docs/release/v0.3-tactile-quietware.md @@ -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. diff --git a/src/design-system/v0.3-quietware-tokens.css b/src/design-system/v0.3-quietware-tokens.css index e7e0246..92993d1 100644 --- a/src/design-system/v0.3-quietware-tokens.css +++ b/src/design-system/v0.3-quietware-tokens.css @@ -10,29 +10,26 @@ Activation paths: 1. Manual: add data-design="quietware" to via dev tools. - 2. Build flag (Phase 2): VITE_LUMOTIA_QUIETWARE=1 will wire the + 2. Build flag (Phase 2): VITE_LUMOTIA_QUIETWARE=1 wires the attribute through +layout.svelte automatically. -------------------------------------------------------------- - Palette source — Jake's color.adobe.com primaries, locked 2026-05-15: + Palette — Phase 4d revision (2026-05-15 round 4 feedback). - #FF0700 red (--danger) - #000AFF blue (--info) - #00FF56 green (--success) - #FFCD00 yellow (--caution) + Atmosphere is warm brown-charcoal. Semantic colours are + muted-Material hues, NOT max-saturation primaries. The brand + accent (copper-clay) is intentionally distinct from caution + (yellow) so the two warm attention colours do not collide. - Each primary is used literally where it clears WCAG AA on the - relevant background. Where it does not (typically yellow and green - on cream paper, blue on dark Coffee Bean) a text-safe sibling at - the same hue and saturation is derived by adjusting lightness - until 4.5:1 clears. + Light-mode caution returns to ochre #7A5D00; this passes AA as + text on cream and works with the left-bar Notice pattern. The + earlier "fill-only on cream" rule applied to the bright #FFCD00 + primary; under muted-Material values that constraint dissolves. - Caution stays a fill-only role on cream paper. Any darkened yellow - reads as olive or mustard ("looks like poop", per Jake), which we - refuse to ship. Pill backgrounds, dots, left-border accents and - icons take --color-caution. Foreground text inside caution-coloured - pills stays --color-text. This matches Material, GOV.UK and IBM - Carbon practice. + High contrast is a rendering CONTRACT, not just a palette. Phase + 4e behavioural tokens (--grain-opacity, --shadow-strength, + --border-width-control, --focus-ring-width, --panel-radius) + accompany the palette override. Typography stack (V4 pairing, locked 2026-05-15): Work Sans -> body, UI, controls, headers @@ -70,55 +67,69 @@ /* ============================================================ Quietware — dark mode default. - Lifted Coffee Bean base. Jake's primaries used directly where - they clear AA on the dark surface; lifted siblings for the rest. + Warm brown-charcoal atmosphere. Reads as warm when you notice + it, not coloured at first glance. Semantic and brand-accent + palettes are deliberately separate. ============================================================ */ :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-bg: #12100E; + --color-bg-elevated: #1A1713; + --color-bg-card: #211D18; + --color-bg-input: #181510; + --color-border: #4A4035; + --color-border-subtle: #2C261F; --color-text: #F3EFE7; --color-text-secondary: #BDB6A9; - --color-text-tertiary: #8D8577; + --color-text-tertiary: #908779; - /* --info and --danger lifted from primaries; pure red/blue too dark on dark bg. */ - --color-info: #7076FF; /* lifted from #000AFF, 4.64 AA */ - --color-danger: #FF2A24; /* lifted from #FF0700, 4.54 AA */ - /* --success and --caution use Jake's primaries directly; both already AAA on dark bg. */ - --color-success: #00FF56; /* Jake literal, 12.51 AAA */ - --color-caution: #FFCD00; /* Jake literal, 11.33 AAA */ + /* Brand accent. Copper-clay, distinct from semantic yellow. */ + --color-accent: #C97845; + --color-accent-hover: #B96638; + --color-accent-subtle: #C9784514; + --color-accent-glow: #C9784525; + + /* Semantic palette. Muted-Material hues. */ + --color-danger: #FF8A8A; + --color-caution: #F2C94C; --color-warning: var(--color-caution); + --color-success: #79D59B; + --color-info: #8AB4F8; - --color-sidebar: #1F0F18; - --color-nav-active: #3E2A33; - --color-hover: #34222B; - --color-overlay-dim: rgba(31, 8, 18, 0.7); + --color-sidebar: #0F0E0C; + --color-nav-active: #211D18; + --color-hover: #1A1713; + --color-overlay-dim: rgba(15, 14, 12, 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; + /* Phase 4e behavioural tokens — components opt into the rendering + contract by reading these. Defaults preserve existing v0.3 feel. */ + --grain-opacity: 0.06; + --shadow-strength: 1; + --border-width-control: 1px; + --focus-ring-width: 2px; + --panel-radius: 8px; + + /* Legacy alias — earlier Phase 4c name. Kept for transition. */ + --quietware-texture-opacity: var(--grain-opacity); --quietware-texture-color: rgba(243, 239, 231, 1); } /* ============================================================ Quietware — light mode. - Cream paper base. Jake's blue passes AAA on cream as text and is - used literally. The other three roles use text-safe siblings - derived at the same hue and saturation (lightness shifted for AA). - Caution is fill-only on cream by convention. + Warm paper base. Slight tone on the main work surface so the + page does not read as a generic web app. Caution returns to + ochre #7A5D00 — passes AA as text on cream under the muted + palette. ============================================================ */ :root[data-design="quietware"][data-theme="light"] { --color-bg: #FBF8F2; - --color-bg-elevated: #F3EEE6; - --color-bg-card: #FFFFFF; - --color-bg-input: #F3EEE6; + --color-bg-elevated: #F6F1EA; + --color-bg-card: #FFFDF8; + --color-bg-input: #F4EFE7; --color-border: #897D70; --color-border-subtle: #D8D0C4; @@ -126,70 +137,106 @@ --color-text-secondary: #5E574C; --color-text-tertiary: #74685B; - --color-info: #000AFF; /* Jake literal, 7.96 AAA on cream */ - --color-danger: #E60600; /* text-safe derived from #FF0700, 4.51 AA */ - --color-success: #00852D; /* text-safe derived from #00FF56, 4.51 AA */ - /* Caution is FILL ONLY on cream. Text inside caution pills uses --color-text. */ - --color-caution: #FFCD00; /* Jake literal, fill-only by convention */ + --color-accent: #9D5F32; + --color-accent-hover: #854E29; + --color-accent-subtle: #9D5F3214; + --color-accent-glow: #9D5F3225; + + --color-danger: #B3261E; + --color-caution: #7A5D00; --color-warning: var(--color-caution); + --color-success: #1B6B3A; + --color-info: #2457A6; --color-sidebar: #F3EEE6; --color-nav-active: #E8E2D6; --color-hover: #EAE4D8; --color-overlay-dim: rgba(29, 27, 24, 0.55); - --quietware-texture-opacity: 0.07; + --grain-opacity: 0.07; + --quietware-texture-opacity: var(--grain-opacity); --quietware-texture-color: rgba(29, 27, 24, 1); } /* ============================================================ - Quietware — high-contrast mode. - Same four hues retained so role recognition does not flip between - modes. Saturation 80%, lightness 70%. Zero texture, no translucent - overlays. + Quietware — high-contrast rendering contract. + Different rendering CONTRACT, not just a colour override. The + tactile brand steps aside entirely. No grain, no shadows, + thicker borders, sharper focus rings. Pure black/white with a + single strong-blue focus colour. ============================================================ */ -: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; +:root[data-design="quietware"][data-contrast="high"], +:root[data-design="quietware"][data-theme="light"][data-contrast="high"] { + --color-bg: #FFFFFF; + --color-bg-elevated: #FFFFFF; + --color-bg-card: #FFFFFF; + --color-bg-input: #FFFFFF; + --color-border: #000000; + --color-border-subtle: #000000; - --color-text: #FFFFFF; - --color-text-secondary: #DADADA; - --color-text-tertiary: #C8C8C8; + --color-text: #000000; + --color-text-secondary: #000000; + --color-text-tertiary: #000000; - --color-info: #757AF0; /* 5.80 AA on black */ - --color-danger: #F07975; /* 7.70 AAA on black */ - --color-success: #75F09F; /* 14.72 AAA on black */ - --color-caution: #F0D875; /* 14.78 AAA on black */ + /* Accent collapses to the strong focus blue in HC. Brand + identity steps aside. */ + --color-accent: #005FCC; + --color-accent-hover: #004BA0; + --color-accent-subtle: transparent; + --color-accent-glow: transparent; + + --color-danger: #B3261E; + --color-caution: #7A5D00; --color-warning: var(--color-caution); + --color-success: #1B6B3A; + --color-info: #005FCC; - --color-sidebar: #000000; - --color-nav-active: #1A1A1A; - --color-hover: #1A1A1A; + --color-sidebar: #FFFFFF; + --color-nav-active: #000000; + --color-hover: #F0F0F0; --color-overlay-dim: rgba(0, 0, 0, 0.85); - /* No texture in high contrast. Clarity over atmosphere. */ + /* Behavioural overrides. The contract bites here. */ + --grain-opacity: 0; + --shadow-strength: 0; + --border-width-control: 2px; + --focus-ring-width: 3px; + --panel-radius: 8px; --quietware-texture-opacity: 0; --quietware-texture-color: rgba(0, 0, 0, 0); } +/* Dark-base high-contrast — black background instead of white. + Used when the user explicitly wants HC inside the dark theme. */ +:root[data-design="quietware"][data-contrast="high"]:not([data-theme="light"]) { + --color-bg: #000000; + --color-bg-elevated: #000000; + --color-bg-card: #000000; + --color-bg-input: #000000; + --color-border: #FFFFFF; + --color-border-subtle: #FFFFFF; + + --color-text: #FFFFFF; + --color-text-secondary: #FFFFFF; + --color-text-tertiary: #FFFFFF; + + --color-accent: #75A8F0; + --color-accent-hover: #5C92E0; + + --color-danger: #FF8A8A; + --color-caution: #F2C94C; + --color-success: #79D59B; + --color-info: #8AB4F8; + + --color-sidebar: #000000; + --color-nav-active: #FFFFFF; + --color-hover: #1A1A1A; +} + /* ============================================================ - Static grain overlay. Atmospheric texture across the whole viewport. - Fixed position so it does not scroll. Tile pattern generated inline - via SVG feTurbulence. Opacity driven by --quietware-texture-opacity - (default 0.06 dark / 0.07 light, slider range 0.05 to 0.08 in - advanced settings). mix-blend-mode overlay darkens shadows and - brightens highlights, producing the soft notebook-paper effect. - - pointer-events: none so clicks pass through. z-index 9999 places it - above all content, but content remains fully interactive thanks to - the pointer-events override. - - No texture in high-contrast mode — the [data-contrast="high"] block - above sets --quietware-texture-opacity to 0. + Static grain overlay. Reads --grain-opacity. Zero in HC mode by + contract. Fixed-position so it does not scroll. mix-blend-mode + overlay produces the soft notebook-paper effect. ============================================================ */ :root[data-design="quietware"] body::after { content: ""; @@ -198,7 +245,7 @@ pointer-events: none; z-index: 9999; background-image: url("data:image/svg+xml;utf8,"); - opacity: var(--quietware-texture-opacity); + opacity: var(--grain-opacity); mix-blend-mode: overlay; } diff --git a/src/lib/ui/LumotiaNotice.svelte b/src/lib/ui/LumotiaNotice.svelte index 63bd1dd..dc86136 100644 --- a/src/lib/ui/LumotiaNotice.svelte +++ b/src/lib/ui/LumotiaNotice.svelte @@ -4,19 +4,24 @@ // scattered across pages. Four tones map to the semantic tokens. // // v0.3 Phase 3 update — left-bar accent pattern. The visible status - // signal now lives on a 4-px solid left border in the tone colour - // (100% opacity, fill-grade chroma); the surrounding container uses - // a soft tone-tinted background and a subtle outer border. Icon, - // title and body text all use --color-text so they remain legible - // across every theme combination, including quietware light mode - // where --color-caution is the bright #FFCD00 fill (would fail as - // text on cream). Same accessibility role semantics retained. + // signal lives on a 4-px solid left border in the tone colour, full + // opacity. The surround uses a soft tone-tinted background + outer + // border in the tone colour. Title and body text use --color-text; + // icon uses the tone colour. Same accessibility role semantics + // retained. + // + // v0.3 Phase 4d opacity rebalance (2026-05-15 round 4 feedback): + // Background role colour at 8% (was 10%, less heavy) + // Outer border role colour at 40% (was neutral subtle) + // Left bar role colour at 100% (unchanged) + // Icon role colour (reverted from --color-text once the + // muted-Material palette landed; previous fill-only- + // on-cream concern dissolved with the new ochre + // #7A5D00 light-mode caution). + // Title + body --color-text (unchanged) // // Pattern matches Material Design "banner with leading accent" and - // IBM Carbon "inline notification" guidance: status colour on a - // large fill surface (the bar), neutral foreground text. Works for - // any tone in any theme regardless of WCAG-text contrast on the - // role colour itself. + // IBM Carbon "inline notification" guidance. import { Info, AlertTriangle, AlertOctagon, CheckCircle, X } from "lucide-svelte"; import type { Snippet } from "svelte"; @@ -40,25 +45,33 @@ classes = "", }: Props = $props(); - const palette: Record = { + const palette: Record = { info: { bar: "border-l-info", - bg: "bg-info/10", + bg: "bg-info/8", + border: "border-info/40", + iconColor: "text-info", icon: Info, }, caution: { bar: "border-l-caution", - bg: "bg-caution/10", + bg: "bg-caution/8", + border: "border-caution/40", + iconColor: "text-caution", icon: AlertTriangle, }, danger: { bar: "border-l-danger", - bg: "bg-danger/10", + bg: "bg-danger/8", + border: "border-danger/40", + iconColor: "text-danger", icon: AlertOctagon, }, success: { bar: "border-l-success", - bg: "bg-success/10", + bg: "bg-success/8", + border: "border-success/40", + iconColor: "text-success", icon: CheckCircle, }, }; @@ -73,10 +86,10 @@
-