* feat(design-system): Liquid Glass redesign portfolio — foundation + primitive kit + Layout shell Operator-requested epic to migrate the UI from the current "warm panel + side-highlight + heavy gradient" visual language to a Liquid Glass aesthetic that retains Deck Hearth's fireplace warmth as accent / gradient / motion (not as panel fill). This squash carries the full 8-convoy portfolio drive-through; 5 sub-convoys reach merged state, 3 land architecture-only and queue impl for follow-up turns gated on dedicated visual-diff baseline re-seeds. Sub-convoy #1 (liquid-glass-design-tokens) — MERGED. 29 CSS custom properties: glass-surface {low,mid,high} alpha ramp + blur/saturate + rim-light (inner/outer) + ember-rim (subtle/pronounced; RGB triple) + 3-tier elevation + modal-scrim, both light + dark themes with eye-perception-corrected alphas; @supports not (backdrop-filter) fallback collapsing surfaces toward solid (preserves ramp ordering). Authored docs/DESIGN_TOKENS.md (270 LOC reference with WCAG AA contrast tables, composite recipes, when-NOT-to-use-glass guidance, per-card grid GPU budget). AGENTS.md gains a § Visual language section as the new agent-contract surface. Sub-convoy #2 (liquid-glass-modal-and-surface-primitive) — Brief 1 MERGED. Adds <GlassSurface> (forwardRef composable; tint / rim / elevation / blur props) and <Modal> primitive (focus-trap, ESC + backdrop close, body-scroll lock, ARIA dialog shape, built-in close button) consuming the token surface. lib/use-focus-trap.js — homegrown hook (~60 LOC, no dep). 10 new vitest cases covering open/close render, ARIA, ESC + closeOnEsc gate, backdrop gate, hideCloseButton, body-scroll lock + restore. 4 reference modal migrations as proof-of-pattern: ShareModal, CollectionDeleteModal, CollectionsCreateModal, CardDetailQuantityModal. Brief 2 (11 remaining modals) queued; CI grandfather list locks the pattern in. Sub-convoy #3 (liquid-glass-form-primitives) — Brief 1 MERGED. Adds <Button> (primary ember-gradient with ember-rim-pronounced; secondary glass-mid; danger; ghost), <Input> (glass-high with ember focus ring + label + helperText + error + aria-invalid + describedby wiring + leadingIcon decorative + trailingAction interactive), <SearchBar> (composes Input with leading search icon + conditional clear button). 10 new vitest cases. pages/login.js + pages/signup.js fully migrated — 2 submit buttons + 7 inputs total; existing test/pages/login.test.js assertion ("Sign in to Deck Hearth" button text) preserved. Brief 2 (profile/settings + deck-builder + scanner + card-editor + collection-cluster modal forms) queued. Sub-convoy #4 (liquid-glass-layout-shell) — MERGED. 6 shell surfaces glass-migrated: desktop sidebar rail (glass-mid + rim + ambient elevation), mobile drawer (glass-mid + pronounced elevation), mobile overlay scrim (modal-scrim + blur-high — visually consistent with <Modal>), search header strip (glass-mid + rim), UserProfileDropdown popover (glass-high + ember-rim-subtle + ambient — matches popover recipe), MobileNavigation bottom bar (replaces legacy mobile-nav-backdrop class). The 5 Layout regression-lock tests (logged-out CTA, no maintainer-email default, "Sign in" link present, supplied email renders, no "Guest" placeholder) all still pass — every edit preserved the documented contract. Sub-convoy #5 (liquid-glass-card-surfaces) — ARCHITECTURE RATIFIED; implementation queued. Pixel-sensitive (rarity-glow reconciliation) so wants a dedicated visual-diff baseline re-seed PR. Pre-blocked on a fix-card3d-state convoy (Card3D has pre-existing state-management bug: state setters used without useState declarations). Sub-convoy #6 (liquid-glass-public-and-auth) — ARCHITECTURE RATIFIED; partial impl shipped via #3 (login + signup form primitives migrated). Landing page editorial + public collection/deck views + login/signup outer-wrapper sweep queued. Sub-convoy #7 (motion-system-pass) — MERGED. 8 motion tokens (5-tier duration taxonomy: instant/quick/default/slow/deliberate; 3 easings: ease-out default, spring for delight, linear for progress) added to the token surface. prefers-reduced-motion upgraded from a narrow nav-item rule to a site-wide universal sweep collapsing animation-duration + transition-duration to 0.01ms (preserves end states, no flicker); .motion-essential class is the opt-in escape hatch for state-meaningful animation (loading spinners, scan reticles). Authored docs/MOTION_SYSTEM.md with WCAG SC 2.3.3 contract, composition recipes, audit of existing keyframes, and adding-new-animation checklist. Sub-convoy #8 (cleanup-legacy-design-css) — Brief 1 MERGED. Two new CI jobs in .github/workflows/ci.yml: (1) forbidden-modal-shell-without-primitive (BLOCKING) — fails build if any new file outside the 9 grandfathered legacy modals uses the fixed inset-0 bg-black bg-opacity- shell pattern; locks in the discipline that every modal must compose <Modal> from components/ui. (2) forbidden-deprecated-color-aliases (WARN-only) — audits pre-Deck-Hearth blue/purple/pink aliases (gradient-text-purple/pink/blue, glow-purple/pink/blue, gradient-bg-purple/blue/pink) as a baseline; graduates to FAIL after #8 Brief 2 sweeps consumers. .cursor/rules/ui-and-theming.mdc updated to document the components/ui/ primitive kit and point at the new canonical reference modals. Verification: lint 0 errors (2 pre-existing warnings in unrelated CardEditorForm.js + CollectionsPageView.js — out of scope); vitest 104/104 passing (was 84 — +20 from new primitive tests: 10 Modal + 10 ui-primitives); ci.yml valid YAML; both new CI gates locally exercised and pass on the current tree. Operator follow-ups documented in .convoys/ship-readiness.md § "Design-system redesign portfolio": - Re-seed Linux visual-diff baselines via Docker workflow (AGENTS.md § 6) after this merges. - preview-smoke.yml runs against the preview; auth + scanner specs touch the migrated surfaces. - Vercel promote to production once smoke + visual gates pass. - Queued follow-up implementer turns: #2 Brief 2 (11 modals), #3 Brief 2 (other forms), #5 Brief 1 (cards, after fix-card3d-state), #6 Brief 1 (landing editorial), #8 Brief 2 (legacy CSS deletion + WARN→FAIL graduation). The user-visible promise — "modern fireplace aesthetic; modals blur the page behind them; reusable components" — is delivered TODAY by the merged work. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(use-focus-trap): preserve named useFocusTrap export for ScannerPageView The portfolio squash inadvertently overwrote the pre-existing lib/use-focus-trap.js (named `export function useFocusTrap(active)` returning a ref — used by ScannerPageView, line 21) with a default- only export shaped for the new `<Modal>` primitive. Vercel build failed: "Export useFocusTrap doesn't exist in target module". Fix: the file now exports BOTH — - `useFocusTrap(active)` (named, original) — returns a ref; pre-Liquid-Glass call sites (ScannerPageView) keep working. - `useFocusTrapContainer({ active, containerRef, ... })` (default, new) — takes a caller-owned ref so panel refs can forward through forwardRef chains (Modal.js consumes this shape). Both hooks are commented to document which to use when. Modal.js imports default already, so no change needed there. Verified: npm run build passes (was failing in CI); lint 0 errors; vitest 104/104 still green. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
255 lines
9.9 KiB
Markdown
255 lines
9.9 KiB
Markdown
---
|
||
name: liquid-glass-public-and-auth
|
||
classification: feature
|
||
success_metric: |
|
||
`pages/index.js`, `pages/login.js`, `pages/signup.js`, and the
|
||
public branches of `pages/cards.js` / `pages/collection/[id].js` /
|
||
`pages/deck/[id].js` render under Liquid Glass with a refreshed hero
|
||
+ auth surface; the 3 smoke specs (home / sign-in / health) stay
|
||
green; visual-diff baselines re-seeded; first-impression is
|
||
measurably modernized (Lighthouse desktop Performance + a11y
|
||
preserved ± 5 / ± 0).
|
||
skip: []
|
||
status: architecture-ratified-partial-implementation
|
||
created: 2026-06-03
|
||
architecture_ratified: 2026-06-03
|
||
partial_implementation: 2026-06-03
|
||
depends_on:
|
||
- liquid-glass-design-tokens
|
||
- liquid-glass-modal-and-surface-primitive
|
||
- liquid-glass-form-primitives
|
||
- liquid-glass-layout-shell
|
||
- liquid-glass-card-surfaces
|
||
umbrella: liquid-glass-redesign
|
||
---
|
||
|
||
# Convoy: liquid-glass-public-and-auth
|
||
|
||
Sub-convoy #6 of the `liquid-glass-redesign` epic. This convoy is the
|
||
**first-impression delivery**: the landing page, the auth pages, and
|
||
the public-facing browse views are what visitors see before they sign
|
||
up. They get the most polish budget and the most editorial attention.
|
||
|
||
## Why
|
||
|
||
`pages/index.js` is 316 lines and was flagged in
|
||
`.convoys/ship-readiness.md` § Role-ia-architect: *"current
|
||
`pages/index.js` is 316 lines; needs an editorial pass. What's the
|
||
value prop in one sentence? Right now it's mostly 'we have cards'."*
|
||
|
||
The Liquid Glass redesign without an editorial pass on the landing
|
||
would be paint over a structural problem. This convoy bundles:
|
||
|
||
1. The visual migration of public + auth pages onto the new glass
|
||
primitives.
|
||
2. An **editorial pass** on the landing page — one sentence value
|
||
prop, hero shape, primary CTA, secondary CTA, social proof slot.
|
||
3. Auth page polish — login + signup are the most-completed user
|
||
journey before sign-up; they get glass surface + the new `<Input>`
|
||
+ `<Button>` from #3 + rebuilt error state (closes the
|
||
`aria-describedby` finding via #3's primitive).
|
||
|
||
This convoy depends on the entire foundation (#1–#5) so every primitive
|
||
+ surface is available when the editorial pass lands.
|
||
|
||
## Scope
|
||
|
||
### In scope
|
||
|
||
- `pages/index.js`:
|
||
- Editorial pass — one-sentence value prop, hero, primary CTA, secondary
|
||
CTA, social proof / sample-content slot.
|
||
- Liquid Glass: hero gradient with ember-flame core, glass surfaces
|
||
for content sections.
|
||
- Drop legacy `fire-glow-bg` background animation (per umbrella §
|
||
Open question #5 — operator default: drop).
|
||
- Retain `ember-float` as a localized accent on hero only (motion
|
||
budget per #7).
|
||
- `pages/login.js`:
|
||
- Outer container `<GlassSurface tint="low" rim="ember"
|
||
elevation="pronounced">`.
|
||
- Inputs + button via #3 primitives.
|
||
- Error state via `<Input error="...">` (closes a11y finding).
|
||
- Quick Login removed per `purge-quick-login-from-loginpage` (PR #56,
|
||
2026-05-29) — confirm still gone.
|
||
- `pages/signup.js`:
|
||
- Mirror of login layout for visual consistency.
|
||
- Same primitive consumption.
|
||
- Public branches:
|
||
- `pages/cards.js` (`PublicCardsView` render path).
|
||
- `pages/collection/[id].js` (public viewer branch).
|
||
- `pages/deck/[id].js` (public viewer branch).
|
||
- `pages/community/collections.js`.
|
||
- `pages/community/decks.js` (if shipped — per ship-readiness §
|
||
Role-ia-architect, currently a placeholder; if still placeholder,
|
||
skip).
|
||
- `components/LoginCTA.js` — if it composes legacy button utility
|
||
classes, migrate to `<Button>`; otherwise leave.
|
||
- `components/PublicCardsView.js` — already a component; glass-rate.
|
||
|
||
### Out of scope
|
||
|
||
- Onboarding wizard (the multi-step `/onboarding` surfaced by
|
||
ship-readiness § Role-ia-architect) — separate convoy.
|
||
- Profile / settings pages (authenticated-only; not a first-impression
|
||
surface).
|
||
- Pricing / Terms / Privacy pages — separate convoys when content lands.
|
||
- Marketing copy beyond the one-sentence value prop on `index.js` —
|
||
defer to a future `marketing-copy-pass` convoy.
|
||
|
||
## Roles invoked
|
||
|
||
1. `role-ia-architect` — landing IA + value-prop wording.
|
||
2. `role-ux-reviewer` — auth flow, public browse, mobile-first review.
|
||
3. `role-architect` — brief decomposition (likely per-page; highly
|
||
parallel via multitask).
|
||
4. `role-design-system-auditor` — verify token consumption.
|
||
5. `role-a11y-auditor` — auth form a11y (error wiring already closed
|
||
by #3, but per-page focus order + skip-to-content audit).
|
||
6. `role-implementer` — multitask-friendly per-page briefs.
|
||
7. Post-PR audit fleet.
|
||
|
||
## Architecture + status (2026-06-03)
|
||
|
||
**Already shipped via earlier sub-convoys:**
|
||
- **`pages/login.js`** — form inputs + submit button migrated to
|
||
`<Input>` + `<Button>` primitives (via `liquid-glass-form-primitives`
|
||
Brief 1). The outer `<div className="p-8 rounded-2xl shadow-2xl
|
||
backdrop-blur-sm border border-opacity-20">` editorial wrapper
|
||
still uses the legacy `rgba(var(--bg-secondary-rgb), 0.85)`
|
||
pattern — to be swept under this convoy's Brief 1.
|
||
- **`pages/signup.js`** — same as login; 6 inputs + submit button
|
||
migrated. Outer editorial wrapper still legacy.
|
||
|
||
**Queued under this convoy's Brief 1:**
|
||
1. **`pages/index.js`** (landing) — hero treatment, feature-cards
|
||
row, CTA buttons. Replace `gradient-text-flame` h1 with a
|
||
layered ember rim-light treatment; convert feature cards to
|
||
`<GlassSurface tint="low" rim="subtle" elevation="ambient">`.
|
||
2. **Login/signup outer wrapper** — replace the legacy
|
||
`rgba(var(--bg-secondary-rgb), 0.85)` + `backdrop-blur-sm`
|
||
composition with `<GlassSurface tint="low" elevation="pronounced"
|
||
rim="subtle">`. Removes legacy token usage; consistent with
|
||
`<Modal>` panel recipe.
|
||
3. **`pages/community/*.js`** (community lists, decks, forums) —
|
||
apply card-grid-container composition once #5 lands.
|
||
4. **Public collection / deck pages** (`pages/collection/[id].js`,
|
||
`pages/deck/[id].js` when accessed unauthenticated) — anonymous
|
||
visitors see the same glass shell.
|
||
5. **Editorial copy pass** — `pages/index.js` hero copy currently
|
||
reads "Welcome to Deck Hearth — Sign in to access My Collection".
|
||
Replace with a value-prop-first headline that does NOT imply
|
||
ownership-gate ("Build your collection." / "Track every card.").
|
||
Coordinate with `.cursor/rules/api-routes.mdc` § "Product
|
||
vocabulary" — use `VOCAB` constants for any user-facing nouns.
|
||
|
||
**Sequencing rationale:** the landing-page hero is a pixel-final
|
||
choice that benefits from a visual-diff round-trip BEFORE the rest
|
||
of the public sweep. Better as its own PR with re-seeded baselines
|
||
than batched here.
|
||
|
||
## Todos
|
||
|
||
- [ ] IA architect: landing value-prop + hero shape
|
||
- [ ] UX reviewer: auth flow, public browse, mobile
|
||
- [ ] Architect: per-page brief decomposition
|
||
- [ ] A11y auditor: auth form + skip-to-content
|
||
- [ ] Brief 1 — `pages/index.js` editorial + glass
|
||
- [ ] Brief 2 — `pages/login.js` + `pages/signup.js` glass
|
||
- [ ] Brief 3 — public collection + deck views
|
||
- [ ] Brief 4 — `community/*` pages
|
||
- [ ] Post-PR audit per brief
|
||
|
||
## Decisions to ratify
|
||
|
||
1. **Landing value-prop wording** — operator decision. IA architect
|
||
proposes 3 candidates; operator picks one.
|
||
2. **Landing hero composition** — animated `AnimatedFireLogo` vs static
|
||
glass card vs static + subtle motion. Recommended: static glass card
|
||
with localized ember-float particles; reserve `AnimatedFireLogo` for
|
||
logo-only contexts (logged-in chrome).
|
||
3. **Auth-page background** — flat glass on warm gradient bg vs
|
||
layered glass with hero illustration. Recommended: flat glass on
|
||
warm gradient (simpler, faster, matches Layout's logged-out CTA tone).
|
||
4. **Public branch glass density** — full glass or selective. Confirm
|
||
per-page.
|
||
5. **Drop `fire-glow-bg`** — confirm operator default: drop.
|
||
|
||
## Acceptance criteria
|
||
|
||
1. Every page in § Scope renders under Liquid Glass.
|
||
2. Landing value-prop is one sentence; primary + secondary CTAs are
|
||
`<Button>` primitives.
|
||
3. Auth forms use `<Input>` + `<Button>`; error states wire
|
||
`aria-describedby`.
|
||
4. Smoke specs (home / sign-in / health) all green.
|
||
5. Lint + vitest green.
|
||
6. Linux visual-diff baselines re-seeded per brief.
|
||
7. Lighthouse desktop on `pages/index.js`: Performance ± 5,
|
||
Accessibility ± 0 from pre-redesign baseline.
|
||
|
||
## CI impact
|
||
|
||
| Workflow / job | Behavior |
|
||
| --- | --- |
|
||
| `preview-smoke.yml` | Fires per brief; spec 1 (home) + spec 2 (sign-in) defend Briefs 1 + 2 directly. |
|
||
| `visual-diff.yml` | **Fires + LOUD** per brief. Per-page baseline re-seed mandatory. |
|
||
| `lint` | Fires. |
|
||
| `test:` (vitest) | Fires. |
|
||
| Lighthouse | Run pre + post on `pages/index.js`. |
|
||
|
||
## Known constraints
|
||
|
||
- **Smoke spec 2 wording** — `'sign-in page renders'` asserts
|
||
`getByRole('button', { name: /sign in/i })`. Confirm Brief 2 keeps
|
||
the button label as "Sign in" (any rename breaks smoke).
|
||
- **Theme tokens only** — no hex.
|
||
- **Layout dependency** — `pages/index.js` legitimately renders Layout
|
||
for the logged-out branch (per `.cursor/rules/ui-and-theming.mdc`).
|
||
Verify post-#4 Layout integration.
|
||
|
||
## Multitask dispatch
|
||
|
||
Pre-ratification proposal:
|
||
|
||
```yaml
|
||
slice_dependencies:
|
||
- brief: 1
|
||
depends_on: []
|
||
files:
|
||
- pages/index.js
|
||
- brief: 2
|
||
depends_on: []
|
||
files:
|
||
- pages/login.js
|
||
- pages/signup.js
|
||
- brief: 3
|
||
depends_on: []
|
||
files:
|
||
- pages/cards.js
|
||
- pages/collection/[id].js
|
||
- pages/deck/[id].js
|
||
- components/PublicCardsView.js
|
||
- brief: 4
|
||
depends_on: []
|
||
files:
|
||
- pages/community/collections.js
|
||
- pages/community/decks.js
|
||
```
|
||
|
||
All four briefs are file-disjoint and parallel-safe via
|
||
`/multitask role-implementer briefs 1, 2, 3, 4`.
|
||
|
||
Post-PR audit per brief:
|
||
|
||
```
|
||
/multitask role-reviewer + role-design-system-auditor + role-a11y-auditor
|
||
```
|
||
|
||
## Out of scope follow-ups
|
||
|
||
- **`onboarding-wizard`** — surfaced by ship-readiness § Role-ia-
|
||
architect. Multi-step `/onboarding` flow. P2 feature.
|
||
- **`marketing-copy-pass`** — beyond the one-sentence value prop. P3.
|
||
- **Privacy / Terms / pricing pages** — required pre-launch but
|
||
content-blocked.
|