deckhearth/.convoys/unify-glass-panel-surfaces/brief-6-landing-nav-bar.md
Randall Stillwell 8093f6c4c0 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>
2026-06-04 14:06:53 -05:00

4.6 KiB

convoy brief_number depends_on files
unify-glass-panel-surfaces 6
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:

    // 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.