--- name: liquid-glass-design-tokens classification: feature success_metric: | styles/globals.css gains the canonical Liquid Glass token layer (`--glass-surface-*`, `--glass-blur-*`, `--rim-light-*`, `--ember-rim-*`, `--elevation-*`) for light + dark themes; docs/DESIGN_TOKENS.md documents every token with a contrast measurement vs --text-primary AND --text-secondary in both themes; ZERO component changes; visual diff baselines remain stable; lint + vitest + smoke green. skip: - ux - ia - qa - flag status: merged created: 2026-06-03 merged: 2026-06-03 depends_on: [] umbrella: liquid-glass-redesign conductor_started: 2026-06-03 --- # Convoy: liquid-glass-design-tokens Foundation sub-convoy #1 of the `liquid-glass-redesign` epic. Adds the token layer that every subsequent sub-convoy consumes. Touches CSS + docs only — **no component or page file is edited here**. ## Conductor stamp (2026-06-03) **Classification:** `feature` (full pipeline with skips below). **Skips ratified:** - `ux` — zero user-visible change; UX reviewer has nothing to evaluate. - `ia` — no information-architecture concern; navigation / URL / labels untouched. - `qa` — no UI to manually click through; lint + vitest + visual-diff + smoke fully cover the surface. - `flag` — repo has no feature-flag wrapper (per `.convoys/liquid-glass-redesign.md` § Hard scoping rules). **Kept in pipeline:** `arch` (architect must ratify the 7 decisions listed below), `design` (design-system auditor is the LEAD role here), `a11y` (contrast measurements are a11y concern — auditor reviews the contrast table, not code), `test` (lint + vitest baseline), `visual` (visual-diff fires on `styles/**`), `smoke` (preview-smoke runs on every PR), `review` (single-shot reviewer post-PR), `docs` (this convoy writes `docs/DESIGN_TOKENS.md`). **Next role:** `role-design-system-auditor` (proposes token names + structure), then `role-architect` (ratifies + writes Brief 1). ## Why The Liquid Glass redesign cannot proceed without a documented, measurable token surface. Today `styles/globals.css` defines: - Color tokens (`--bg-primary` / `--bg-secondary` / etc.) - Three gradients (`--gradient-primary` / `--gradient-secondary` / `.gradient-bg-ember`) - A handful of glow utility classes (`.fire-glow`, `.ember-glow`, `.card-mythic-glow`, etc.) - RGB-component triples for backdrop-blur effects (`--bg-primary-rgb`, etc.) What it does NOT define is a *surface* token (translucency + blur + rim-light + elevation) — every component currently composes those ad-hoc inline. This sub-convoy adds that layer and freezes it as the single source of truth. ## Scope ### In scope - `styles/globals.css` — add new tokens to both `:root` (light) and `[data-theme="dark"]`: - `--glass-surface-low` — primary panel background (modals, cards-in-detail) - `--glass-surface-mid` — sidebar / header / navigation rails - `--glass-surface-high` — overlays, tooltips, dropdowns - `--glass-blur-low` (default `12px`), `--glass-blur-mid` (`20px`), `--glass-blur-high` (`32px`) - `--glass-saturate` (default `140%`) - `--rim-light-inner` — `rgba(255,255,255,0.55)` light / `rgba(255,255,255,0.08)` dark - `--rim-light-outer` — hairline border, theme-tuned - `--ember-rim-subtle` — `rgba(216,67,21,0.35)` 1px ring - `--ember-rim-pronounced` — `rgba(216,67,21,0.45)` 1px ring + 12px bloom - `--elevation-ambient` — soft outer shadow (replaces inline `shadow-lg`) - `--elevation-pronounced` — stacked elevation for modals - `--modal-scrim` — backdrop fill behind a modal (theme-tuned alpha) - `docs/DESIGN_TOKENS.md` (new) — reference doc listing every token, its purpose, both-theme values, and measured contrast ratios against `--text-primary` and `--text-secondary`. Use https://webaim.org/resources/contrastchecker/ values. - `AGENTS.md` § "Branding" — append one paragraph linking `docs/DESIGN_TOKENS.md` and naming the Liquid Glass direction. ### Out of scope - Any change to a `.js` file under `components/**` or `pages/**`. - Deletion of any existing token or utility class (cleanup is sub-convoy #8). - Tailwind config changes — Liquid Glass is implemented in CSS vars, not Tailwind theme extensions. - Storybook adoption — `docs/DESIGN_TOKENS.md` is hand-curated; a real Storybook is its own future convoy. ## Roles invoked 1. `role-design-system-auditor` — proposes token names + structure. 2. `role-architect` — ratifies token naming + theme-specific values + contrast targets; writes Brief 1. 3. `role-implementer` — single brief; adds tokens + docs. 4. `role-doc-writer` — reviews `docs/DESIGN_TOKENS.md` shape. ## Todos - [x] Design-system auditor: token naming + structure proposal → see `.convoys/liquid-glass-design-tokens/design-system-audit.md` (29 tokens proposed; both-theme values + contrast tables + composite recipes + `@supports` fallback values; all 5 operator defaults honoured; 6 pre-existing token violations flagged for #8 cleanup) - [x] Architect: ratify Decisions 1–7 using the audit's § 7 recommendations; write Brief 1 → see § Architecture below + `.convoys/liquid-glass-design-tokens/brief-1-tokens-and-docs.md`. All 7 decisions ratified verbatim from audit; all 3 boot-the-brief checks passed. - [x] **Human gate 1 (plan approval)** — approved by operator 2026-06-03 in the full-portfolio drive-through prompt. - [x] A11y auditor: contrast tables in audit § 4 + § 5 verified (light text-primary 15.18:1 AAA, text-secondary 6.86:1 AA; dark text-primary 17.84:1 AAA, text-secondary 11.42:1 AAA; ember rim non-text 3.18–6.18:1 all clear 3:1 SC 1.4.11 floor). - [x] Brief 1 — tokens + docs (committed 2026-06-03). 110 LOC inserted into `styles/globals.css` (purely additive, comment-fenced), 270 LOC `docs/DESIGN_TOKENS.md`, 23 LOC `AGENTS.md § Visual language`. Lint 0 errors; vitest 84/84 green (baseline preserved). - [x] Post-PR audit — `role-reviewer` (single-shot): zero `.js` touched, zero existing CSS rule modified, `@supports` syntax + 16 `rgba()` triples + 3 multi-shadow stacks all syntactically valid, AGENTS.md insertion at correct topology. ## Decisions to ratify (architect) 1. **Glass tint strength** — Apple-leaning vs Linear-leaning (see umbrella § Open question #1). Operator default: Apple-leaning. 2. **Light-theme glass base** — warm white vs cool white (umbrella § #2). Operator default: warm white. 3. **Dark-theme glass base** — warm black vs cool black (umbrella § #3). Operator default: warm black. 4. **`--glass-blur-low/mid/high` exact px values** — proposal: 12 / 20 / 32. 5. **`--glass-saturate` default** — proposal: 140% (Apple-style vibrancy). 6. **Contrast target** — WCAG AA (4.5:1 for text-primary, 3:1 for text-secondary on large text) vs AAA. Recommended: AA hard floor; AAA where achievable without losing the glass effect. 7. **`@supports not (backdrop-filter: blur(20px))` fallback alpha** — solid-with-alpha values for each `--glass-surface-*` so non-supporting browsers degrade to a flat tinted panel, not a hard opaque box. ## Acceptance criteria 1. `styles/globals.css` defines every token listed in § Scope for both themes. 2. `docs/DESIGN_TOKENS.md` exists, lists every token, shows the contrast measurement table per theme. 3. **No `.js` file is modified.** 4. `npm run lint` + `npm run test:run` + `npm run test:smoke` all green. 5. `Screenshot diff` is invoked (CSS path matches `styles/**`) and shows zero or trivially-noisy diff (sub-pixel color reordering only). If non-trivial diff appears, the architect must explain why before merge (most likely cause: an accidental selector reorder; rollback that change). 6. `AGENTS.md` § Branding mentions Liquid Glass + links `docs/DESIGN_TOKENS.md`. ## CI impact | Workflow / job | Behavior | | --- | --- | | `preview-smoke.yml` | Fires (any PR). | | `visual-diff.yml` | **Fires** (`styles/**` matches paths). Expected diff: none. | | `lint` | Fires. | | `test:` (vitest) | Fires. | | New grep gates | None. | ## Known constraints - **No hardcoded hex** outside `styles/globals.css`. The token surface is the only place hex appears post-sub-convoy. - **Both themes ship together** — every token gets a value in both `:root` and `[data-theme="dark"]`. Reviewer fails the PR if any token is one-theme-only. - **`@supports not (backdrop-filter)` fallback** — every glass surface token has a documented fallback per Hard scoping rule of the umbrella. ## Multitask dispatch ```yaml slice_dependencies: - brief: 1 depends_on: [] files: - styles/globals.css - docs/DESIGN_TOKENS.md - AGENTS.md ``` Single brief; no multitask. Post-PR audit is a single `role-reviewer` invocation. ## Out of scope follow-ups - **`tailwind-theme-extension`** (P3 polish): if downstream sub-convoys find themselves repeatedly composing the same Tailwind-class shape (e.g. `bg-[var(--glass-surface-low)] backdrop-blur-[var(--glass-blur-mid)]`), consider extending `tailwind.config.js` `theme.extend.backdropBlur` / `backgroundColor` with named aliases. Surface only if at least 3 downstream sub-convoys hit the same shape. - **`storybook-adoption`** (P2 DX): would let the design-system-auditor inspect tokens + primitives in isolation. Out of scope here; hand-curated `docs/DESIGN_TOKENS.md` is the v1 surface. ## Architecture (2026-06-03) ### Decisions ratified All 7 decisions in § "Decisions to ratify (architect)" ratified verbatim from the audit's § 7 recommendation table at `.convoys/liquid-glass-design-tokens/design-system-audit.md`. No re-tuning required — the audit's proposal honoured all 5 operator defaults from the umbrella and passed AA contrast on all surfaces in both themes (AAA on body text). | Decision | Ratified value | Source | | --- | --- | --- | | 1. Glass tint strength | `--glass-surface-{low,mid,high}` α = **0.55 / 0.68 / 0.82** | Audit § 2.1 | | 2. Light-theme glass base | Warm white `rgba(254, 252, 248, α)` (via existing `--bg-primary-rgb`) | Audit § 2.1 | | 3. Dark-theme glass base | Warm black `rgba(26, 15, 10, α)` (via existing `--bg-primary-rgb` dark variant) | Audit § 2.1 | | 4. `--glass-blur-{low,mid,high}` px | **12 / 20 / 32** | Audit § 2.2 | | 5. `--glass-saturate` default | **140%** | Audit § 2.2 | | 6. Contrast target | **AA hard floor** (AAA achieved on body text in both themes per audit § 4) | Audit § 4 | | 7. `@supports` fallback alpha | Collapsed ramp **0.92 / 0.95 / 0.98** under `@supports not ((backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px)))` | Audit § 3 | ### File plan | File | Action | Purpose | | --- | --- | --- | | `styles/globals.css` | modified (purely additive) | Insert the 29-variable Liquid Glass token block between the existing dark-theme `]` (line 74) and the `/* Apply theme colors */` comment (line 76); append the `@supports not (...)` fallback block immediately after. **Zero pre-existing rules touched.** | | `docs/DESIGN_TOKENS.md` | new | Reference doc — surface ramp, blur, rim-light, ember rim, elevation, modal scrim, composite recipes, contrast tables, "When NOT to use glass", performance budget, browser support, deprecations. | | `AGENTS.md` | modified | Insert a new `## Visual language` section between `## Product vocabulary` (line ~27) and `## 1. Project overview` (line 29). Three rules of thumb + pointer at `docs/DESIGN_TOKENS.md`. | ### API surface N/A — CSS + docs only. No new route, no API contract change, no authentication surface, no rate-limit consideration. ### Schema diff N/A — no database change. ### Test plan | Stage | Action | | --- | --- | | **vitest** (`npm run test:run`) | No new tests added in this brief (CSS-var surface has no functional unit-test target). Existing 21/21 baseline must stay green. | | **lint** (`npm run lint`) | Must exit 0. | | **smoke** (`npm run test:smoke`) | Existing 3 specs (home / sign-in / health) must stay green. None depend on visual tokens. | | **visual-diff** (`Screenshot diff` workflow) | Fires (`styles/**` matches paths). **Expected output: empty diff** — no consumer of the new tokens is added in this brief. Any non-trivial rendered-pixel diff is a bug and must be explained before merge. | | **manual** | None required for this brief — no UI to click through (per `skip: qa`). | No existing tests are affected. No new test files are created. The "tokens added but unused" property is the test: visual diff is the implicit assertion. ### Risk list 1. **Visual-diff noise from CSS file reorganization.** Mitigation: the block is inserted at a single contiguous location with comment fences; no existing rule is renumbered or moved. `git diff styles/globals.css` should show only inserted hunks. (Risk: low.) 2. **`@supports not ((...) or (...))` syntax error.** The negation of an OR group requires the outer parentheses around the whole group. Brief 1 provides the verbatim shape, copy-pasted; implementer must not reformat. (Risk: low; mitigated by verbatim copy.) 3. **`@supports` block placement order.** The fallback MUST come AFTER the base `:root` + `[data-theme="dark"]` blocks so the override fires when supported. Brief specifies the insertion location. (Risk: low; mitigated by exact-insertion-point instruction.) 4. **`docs/DESIGN_TOKENS.md` path referenced from `AGENTS.md` before the file exists.** Brief is atomic — all three files commit together. (Risk: nil with atomic commit.) 5. **Scope creep — implementer consumes the new tokens in `components/**` or `pages/**`.** This brief is foundation-only; consumption begins in sub-convoy #2. Brief explicitly forbids `.js` changes; pre-PR verification command grep'd in the brief surfaces any leak. (Risk: low; gated by explicit anti-scope + verification.) 6. **No-go zone violation.** `styles/globals.css` is not a no-go zone; `AGENTS.md` is the canonical agent contract (editable through documented sections); `docs/` is new content. ✅ All in scope. 7. **Token-name collision.** None — audit verified all 29 proposed names are unique against the current `styles/globals.css` namespace. (Risk: nil.) 8. **Browser-fallback misfire on Safari 18+.** Safari 18+ supports `backdrop-filter` unprefixed; `@supports not (...)` will NOT fire, so the fallback alphas remain unused — the canonical 0.55 / 0.68 / 0.82 surfaces ship as intended. Cross-checked against caniuse 2026- 06-03. (Risk: nil.) ### Decomposition | Brief # | Title | Files | Depends on | Estimated PR size | | --- | --- | --- | --- | --- | | 1 | `tokens-and-docs` | `styles/globals.css`, `docs/DESIGN_TOKENS.md`, `AGENTS.md` | — | ~110 LOC inserted into `styles/globals.css`; ~260 LOC `docs/DESIGN_TOKENS.md`; ~25 LOC `AGENTS.md`. Total ≈ 395 LOC, all additive. **No deletions.** | Single brief; no multitask possible (single implementer, single PR). Comfortably under the 400-LOC architect anti-pattern threshold. ### Slice dependencies (multitask-ready) ```yaml slice_dependencies: - brief: 1 depends_on: [] files: - styles/globals.css - docs/DESIGN_TOKENS.md - AGENTS.md ``` **Multitask verdict:** no `/multitask` dispatch — single-brief convoy. Conductor's serial-implementer path is the right shape here. ### Boot-the-brief check (architect verification, completed 2026-06-03) 1. **Dep set check.** Zero new packages added. Zero peer-dep concerns. ✅ Pass. 2. **Verbatim code shape check.** - `@supports not ((backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px)))` — CSS Conditional Rules Level 3 valid syntax (negation of a compound condition requires the outer parens around the OR group). Cross-checked against MDN's `@supports` reference. ✅ Verified. - The 16 `rgba(...)` triples in the brief — all integer RGB values 0–255, all alpha values 0.0–1.0. ✅ Syntactically valid. - The 3 `box-shadow` stacks (light + dark `--elevation-pronounced`, `--ember-rim-pronounced`) — comma-separated multi-shadow syntax is CSS Backgrounds and Borders Level 3 valid. ✅ Verified. - `inset` keyword for inner-rim shadows — valid in `box-shadow` and standalone (when in `box-shadow` list). ✅ Verified. - The CSS variable inheritance pattern (theme-independent blur/saturate defined only in `:root`; theme-dependent surfaces redefined in `[data-theme="dark"]`) — matches the existing precedent at `styles/globals.css` lines 100–154. ✅ Verified. 3. **Cross-brief commitments check.** Single brief; no commitments to downstream briefs in this convoy. (Downstream convoys #2–#8 are separate convoys with their own architect passes.) ✅ N/A. All boot-the-brief checks pass. No brief revision needed. ### Architect notes (mid-implementation guidance) - The brief explicitly forbids reformatting the verbatim CSS block. Implementer must copy-paste, not retype. This avoids whitespace drift on the multi-line `box-shadow` stacks. - If the implementer hits any unexpected obstacle (e.g. `Screenshot diff` shows a non-trivial rendered diff despite no consumer being added), STOP and surface to the operator. Do not "fix it" by editing components. - The 26-line AGENTS.md insertion is at a specific topological position (between `## Product vocabulary` and `## 1. Project overview`). Use `StrReplace` to target the line-29 boundary precisely; do not use blind append-to-section.