deckhearth/.convoys/unify-glass-panel-surfaces/brief-6-landing-nav-bar.md

92 lines
4.6 KiB
Markdown
Raw Normal View History

docs(convoys): unify-glass-panel-surfaces + cleanup palette — conductor seed + architect plan (#119) * docs(convoys): seed unify-glass-panel-surfaces + cleanup-card-item-list-and-share-modal-palette Two convoy seeds opened as follow-ups to the 2026-06-04 design pass (#116 corner-border-light → #117 site-wide sweep → #118 card vibrancy reduction). Both were called out in #117's PR body as deferred and are now formally tracked. ## unify-glass-panel-surfaces Migrates remaining panel-shaped surfaces to the gradient-border corner-light treatment so the app shares one surface vocabulary. The audit's key insight: `<GlassSurface>` (`components/ui/GlassSurface.js`) predates the corner-light pattern. Because `<Modal>`, `<StatCard>`, and the landing-page feature/collection cards all delegate to it, upgrading the primitive cascades to ~10 visible surfaces at once. 7 briefs, multitask-parallel after Brief 1 lands: 1. `<GlassSurface>` primitive upgrade — BLOCKING for 3, 4 2. Auth form cards (login.js, signup.js) 3. Floating popovers (mobile drawer, sidebar profile dropdown, UserMenu dropdown) 4. BulkSelectionToolbar (currently `bg-white border-gray-200` — invisible in dark mode) 5. `.card`-class consumers (4 pages); decision to ratify whether to retire `.card` entirely or keep as documented opaque fallback 6. Landing nav bar — wrong pattern; should use existing `.page-header-glass` class 7. `forbidden-bespoke-glass-surface` CI grep gate — prevents regression after the migration ships ## cleanup-card-item-list-and-share-modal-palette Targeted palette cleanup for two files whose interiors weren't addressed in #117: 1. `CardItem.js` list-mode (L183–284) — entirely hardcoded Tailwind palette (`bg-purple-50`, `border-gray-200`, `text-gray-{500-900}`, `bg-blue-100 text-blue-800` etc.); unreadable / off-brand in dark mode. 2. `ShareModal.js` interior rows — purple avatar circles, gray-50 permission row (invisible in dark mode), blue-600 Copy-link button, gray text labels. Token-only swap. 2 parallel briefs, no architect / IA / UX needed (no design decisions — palette to design tokens). ## Sequencing note The two convoys are independent and can run in parallel. The audit agent's recommended sequencing (Brief 1 of `unify-glass-panel-surfaces` first) is encoded in the multitask `slice_dependencies` blocks. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(convoys): architect plan + 7 briefs for unify-glass-panel-surfaces Appends the ## Architecture section to .convoys/unify-glass-panel-surfaces.md ratifying the 4 open Decisions, and writes 7 implementer-brief files under .convoys/unify-glass-panel-surfaces/. Decisions ratified: D1. <GlassSurface> grows a cornerLights='subtle'|'chrome'|'none' prop, default 'subtle' (4-layer gradient-border per PR #118 recipe). D2. Retire .card entirely; migrate all 8 consumers to .glass-panel. D3. Mobile drawer uses subtle tier (.glass-panel-strong). D4. CI gate scopes to JSX inline-style usage only; 3-entry allowlist for documented chrome exceptions. Briefs (1-7, all <100 LOC each, disjoint files): 1. Upgrade <GlassSurface> primitive (no deps, blocks 3+4) 2. Migrate auth form cards (parallel-safe) 3. Migrate floating popovers (sidebar dropdown, mobile drawer, TopSearchBar UserMenu) 4. Migrate BulkSelectionToolbar + interior token sweep 5. Retire .card class; migrate 8 consumers 6. Migrate landing nav bar to .page-header-glass 7. forbidden-bespoke-glass-surface CI gate (runs LAST) Boot-the-brief check: all 4-layer recipes verified against post-PR-#118 styles/globals.css; all box-shadow preservation chains verified against current Layout.js + TopSearchBar.js; .card deletion verified clean (single rule at L729-733); CI gate shape modeled on existing forbidden-modal-shell-without-primitive job. Architecture is read-only output — no application code touched. Awaiting human gate 1 (plan approval) before implementers run. Co-authored-by: Cursor <cursoragent@cursor.com> * docs(convoys): fix Brief 3 TopSearchBar UserMenu elevation token Self-review recheck against current TopSearchBar.js (L211-222) found that the UserMenu dropdown uses var(--elevation-pronounced), not var(--elevation-ambient) as Brief 3's initial sample showed. Brief 3 now documents the verbatim shape (pronounced + role="menu" + aria-label + overflow-hidden) and the convoy's risk-list note is updated to reflect all three popovers' verbatim chains. No semantic change to the plan; just an accuracy fix the implementer of Brief 3 needs to ship the right code on the first try. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 15:09:40 -04:00
---
convoy: unify-glass-panel-surfaces
brief_number: 6
depends_on: []
files:
- pages/index.js
---
# Brief 6: Migrate landing nav bar to `.page-header-glass`
## Goal (1 sentence)
Replace the handrolled translucent `<nav>` on the public landing page with the canonical `.page-header-glass border-b` className, and drop the malformed `boxShadow: 'inset 0 1px 0 var(--rim-light-inner)'` (the token already contains its own `inset 0 1px 0`; double-wrapping breaks the cascade — documented in `styles/globals.css` L748-761).
## Files in scope (do not edit anything else)
- `pages/index.js` — the landing `<nav>` block, currently L61-72 (around the `border-b` declaration with inline `background: 'var(--glass-surface-mid)'` + `backdropFilter` + `boxShadow: 'inset 0 1px 0 var(--rim-light-inner)'`).
**Out of scope:** everything else on the landing page (the Deck Hearth heading, the Sign In / Get Started buttons inside the nav, the hero section, feature cards, footer, the `if (user) return null;` redirect logic, etc.). The migration is a single `<nav>` element's `className` + `style` swap.
## Conventions to follow
- **Verbatim replacement:**
```jsx
// Before:
<nav
className="border-b"
style={{
background: 'var(--glass-surface-mid)',
backdropFilter:
'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))',
WebkitBackdropFilter:
'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))',
borderColor: 'var(--border)',
boxShadow: 'inset 0 1px 0 var(--rim-light-inner)',
}}
>
// After:
<nav
className="page-header-glass border-b"
style={{
borderColor: 'var(--border)',
}}
>
```
The class provides `background`, `backdrop-filter`, and the
correct `box-shadow` (which IS `var(--rim-light-inner), 0 1px 0
var(--border)` per its definition in `globals.css` L300-306). The
`border-b` Tailwind class needs the `borderColor` style to remain
themed; everything else collapses into the class.
- **The malformed boxShadow is the bug:** `var(--rim-light-inner)` is
already a complete `inset 0 1px 0 <color>` declaration. Wrapping
it in another `inset 0 1px 0 ...` produces invalid CSS that the
browser silently drops. The class's own `box-shadow:
var(--rim-light-inner), 0 1px 0 var(--border)` does the right
thing. Removing the inline `boxShadow` line is the fix.
- **Children verbatim:** the `<div className="max-w-7xl mx-auto ...">`
inside the `<nav>`, the `<AnimatedFireLogo>`, the heading, and the
Sign In / Get Started buttons all stay byte-identical. Do not
touch them.
- **`.page-header-glass` placement check:** the class is defined in
`styles/globals.css` L300-306 and is already used by authenticated
pages' header strips (dashboard, my-cards, cards, etc.). It's safe
to reuse on the public landing page — the class has no auth
coupling.
- **Nested backdrop-filter check** (boot-the-brief risk #6): the
landing page has no enclosing Layout (the `pages/index.js` redirect
logic returns `null` for authenticated users and renders its own
full-page `<div>` for anonymous visitors — no `<Layout>` wrapper).
So there's no risk of nested `backdrop-filter` stacking. Verified.
- **AGENTS.md / no-go zones:** `pages/index.js` is an authored page,
not a generated artifact. Allowed.
## Acceptance criteria
- [ ] Landing `<nav>` uses `className="page-header-glass border-b"`.
- [ ] Inline `style` on the `<nav>` retains only `borderColor: 'var(--border)'` — no `background`, no `backdropFilter`, no `WebkitBackdropFilter`, no `boxShadow`.
- [ ] The Deck Hearth heading + Sign In / Get Started buttons inside the nav render identically.
- [ ] Manual: open `/` in an incognito window (anonymous user), verify the nav bar renders with a subtle glassy treatment, an `inset 0 1px 0` highlight (the inner rim), and a 1px bottom border. Verify in both light and dark theme via the theme toggle (which appears on the public landing). Attach light + dark screenshots to PR.
- [ ] `npm run lint` + `npm run test:run` pass (no test count change expected).
- [ ] No edits to other files.
## Rationale (≤3 sentences)
The landing nav is the highest-visibility public surface in the app and currently both (a) duplicates `.page-header-glass`'s composition handrolled, and (b) ships a malformed `boxShadow` that silently breaks. Migrating to the canonical class is a one-line cleanup that fixes a latent bug. No corner-light treatment is appropriate here — the nav is full-bleed, so corner radials would land at viewport edges and never read as light sources; `.page-header-glass` (which uses the rim/border-only composition) is the right shape.