All 8 sub-convoys from the redesign-v2 epic landed across 5 PRs (#102 → #107). Updates the umbrella convoy with: - frontmatter status: open → shipped, shipped: 2026-06-04 - § 9: table mapping each sub-convoy to its PR + squash commit + brief one-liner so the next agent reading .convoys/ has a complete audit trail - § 9: 9 queued follow-up convoys explicitly captured (Daily Ember backend, rarity aggregation, wishlist feature, user activity feed, market data + chart library decision, featured collection filters, federated command palette, page-header- glass CSS cleanup, top-bar user dropdown). Each names the upstream call site (component / hook / TODO comment) so the follow-up author has a starting line. Zero code changes. Lint clean. No tests touched (docs-only). Co-authored-by: Cursor <cursoragent@cursor.com>
23 KiB
| name | classification | success_metric | skip | status | created | shipped |
|---|---|---|---|---|---|---|
| redesign-v2-from-mockups | epic | When a logged-in user opens deckhearth.com/dashboard, the screen they see is recognizably the visual language of the operator's two reference mockups (saved 2026-06-04 in /Users/rstillw/.cursor/projects/Users-rstillw-Documents-Personal-Coding-Projects-tcg-vault/assets/image-d1fca5e0-cdde-4a5a-99a3-2e008408b19e.png and image-dea39822-cea5-4c33-8e58-12b43095468d.png): visible warm ember pools in the viewport corners (both themes), a bold gradient active-pill in the sidebar, a "Deck|Hearth" gradient wordmark with flame logomark, four stat cards with colored gradient icon tiles, a prominent top search bar (Cmd+K hint), a Daily Ember progress widget at the bottom of the sidebar, and a content-card grid with warm outer-glow border treatment. All eight gates green (lint, vitest, build, smoke, screenshot diff, the three forbidden-* grep gates, Vercel preview). | shipped | 2026-06-04 | 2026-06-04 |
Redesign v2 — from operator mockups
Umbrella convoy that completes the Liquid Glass redesign by aligning
the actual look-and-feel with the operator's two reference mockups
(2026-06-04). The prior liquid-glass-redesign umbrella (PRs #95-#101,
8 sub-convoys completed) shipped the architectural foundation —
design tokens, primitives, .glass-panel + .page-header-glass
utilities, the layered hearth gradient, the <GlassSurface> /
<Modal> / <Button> / <Input> / <SearchBar> JSX primitives. But
when the operator opened the deployed product they reported "I am not
seeing very many changes with the new look" and shared the two
mockups linked in success_metric above. This convoy reads those
mockups as the actual aesthetic spec and ships the missing pieces.
This convoy is planning-only. No source files are touched here. Each numbered sub-convoy below is its own gated PR.
1. The gap, honestly
The prior epic ships architecturally-correct CSS but visually-timid output:
| Mockup shows | Prior epic delivered |
|---|---|
| Bright ember pools glowing at viewport corners (both themes) | 28% alpha radials that read as faint warmth, not embers |
| Bold gradient active-pill in sidebar with ember-orange fill + soft outer glow | Thin 1px ember border-left indicator on a nearly-transparent rect |
| "Deck | Hearth" wordmark with flame logomark on the left | "DH" monogram badge + plain text "Deck Hearth" |
| Stat cards with colored gradient icon tiles (gold / purple / blue / red rounded squares with white icon) | Plain icon next to text inside a glass-panel |
| Top search bar stretched across the top with Cmd+K hint, notif bell with badge, mail icon, avatar+name+level chip | Page-header-strip (.page-header-glass) with title + action button |
| Daily Ember progress widget at the bottom of the sidebar (flame icon, "16 / 20", progress bar, helper text) | Nothing — never built |
| Card grid items with warm outer glow | Card thumbnails sit on solid bg with default shadow |
| Dark theme with deep navy + visible ember corner glow + rich card chrome | Dark theme exists but corner gradient is even more subtle than light |
| Right-rail Card Spotlight with metadata table + price chart + watchlist | Not part of current dashboard at all |
The operator is right. The prior epic was a foundation; this convoy is the actual visual identity layer on top of it.
2. What this convoy is NOT
- NOT a rewrite from zero. The prior epic's tokens
(
--glass-surface-*,--rim-light-*,--elevation-*) and JSX primitives (<GlassSurface>,<Modal>,<Button>) are correct and reused. The.glass-panelutility stays. What changes is how those pieces compose, the gradient intensity (boost), and the addition of new primitives (<StatCard>,<DailyEmberWidget>,<TopSearchBar>,<SidebarPill>). - NOT a TypeScript migration. Files stay
.jsper Gotcha #9. - NOT a new dependency. No icon library, no chart library yet — if
the right-rail spotlight ships in this convoy, charts come via SVG
or a single
rechartsinstall gated by a separate convoy. - NOT a card-detail page redesign. Sub-convoy 8 ("right-rail") only sketches the layout. A full Card Spotlight rail with real price data is a downstream convoy.
- NOT changing the canonical product features. Existing dashboard routes, queries, and content survive. This convoy re-skins the presentation; it does not rebuild the data model.
3. Hard scoping rules (inherited from liquid-glass-redesign § 3)
- Tailwind + CSS variables only; no new CSS framework.
- Theme tokens, not hex. Every new color reads from a
:rootvar (or its[data-theme="dark"]override). - Both themes ship together per sub-convoy.
prefers-reduced-motionhonored; new animations opt-in via.motion-essentialonly when functionally required.- AA contrast measured at the new gradient corner intensities — the
ember pool MUST NOT drag bg contrast below 4.5:1 against
--text-primaryin the affected viewport region. backdrop-filterfollowed the rules from PR #99's maintainer comment: literal values insideblur(), no-webkit-duplicate in source (let Lightning CSS autoprefix).- One sub-convoy per PR; visual diff baseline updated only when
necessary and only in a Linux container (per
seed-visual-baselines-on-linuxqueued convoy guidance — see.convoys/ship-readiness.md).
4. Dependency graph
┌──────────────────────────────────────────────┐
│ 1. hearth-bg-corner-embers │
│ boost gradient intensity to mockup level; │
│ light theme: visible warm-amber corners; │
│ dark theme: deep navy + ember-red pools │
└────────────────────────┬─────────────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────────┐ ┌────────────────┐
│ 2. sidebar │ │ 3. top-search- │ │ 4. stat-card- │
│ active- │ │ bar │ │ primitive │
│ pill + │ │ (replaces │ │ <StatCard> │
│ logo │ │ page- │ │ │
│ │ │ header- │ │ │
│ │ │ strip on │ │ │
│ │ │ dashboard) │ │ │
└─────┬──────┘ └────────┬───────┘ └────────┬───────┘
│ │ │
│ │ │
└────────┬───────────┴─────────┬──────────┘
│ │
▼ ▼
┌────────────────┐ ┌────────────────┐
│ 5. daily-ember │ │ 6. card-grid │
│ widget │ │ outer-glow │
│ (sidebar │ │ (CardItem │
│ footer) │ │ chrome) │
└────────┬───────┘ └────────┬───────┘
│ │
└──────────┬──────────┘
▼
┌────────────────────┐
│ 7. dashboard- │
│ rebuild │
│ (assemble the │
│ above into the │
│ mockup layout) │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ 8. right-rail- │ ← optional (scope guard)
│ spotlight │
│ (Card Spotlight │
│ sketch — no │
│ new deps) │
└────────────────────┘
Strict blockers:
- #1 must merge before #2-7 — they all live against the new gradient.
- #2, #3, #4 are independent and can run in parallel (multitask candidate; disjoint files).
- #5 is independent of #2-4 but visually relies on #1; merges any time after #1.
- #6 is independent; can run in parallel.
- #7 is the integrator and merges last in the foundation phase.
- #8 is gated by operator approval after #7 lands — it touches layout structure non-trivially.
5. Sub-convoys (seed brief — one paragraph each)
1. hearth-bg-corner-embers
Raise the body-gradient intensity in styles/globals.css from the
current 28%/18%/16% alpha radials to mockup-level visibility. Two
themes ship together. Light: amber pool ~40% alpha bottom-left,
secondary amber ~25% bottom-right, gold ~20% top-right, vertical
warm wash ramps from cool top to warm bottom. Dark: deep navy
(#0d0a18-ish) base + ember-red pool ~55% bottom-left, secondary
ember ~35% bottom-right, purple-magenta accent ~18% top-right. Add
--bg-primary dark-theme value adjustment to match the mockup's
deep-navy base. Acceptance: side-by-side screenshot against the
mockups shows recognizably the same corner-ember treatment in both
themes. Lint + vitest + build + smoke + screenshot-diff green;
visual diff baseline re-seeded ONLY for the public landing page
(tests/visual/homepage.spec.ts) since that's the only currently
baselined surface.
2. sidebar-active-pill-and-wordmark
Replace Layout.js's current sidebar active-state (thin 1px border
indicator) with a bold rounded-pill that has an ember-orange gradient
fill, white icon + label, and a soft outer ember glow. Inactive
items remain transparent / hover-only. Replace the "DH" monogram +
"Deck Hearth" text header with: gradient flame logomark (SVG, ember
gradient) on the left + "Deck" + "Hearth" wordmark where "Hearth"
uses the gradient-text-flame utility so the two-tone word reads
like the mockup. Acceptance: sidebar visually matches the mockup's
active-pill + wordmark treatment in both themes; the existing 5
Layout regression-lock vitest assertions still pass (Sign-in CTA
when null user, no maintainer email leak, etc.).
3. top-search-bar
Add a new <TopSearchBar> component that renders a full-width
horizontal bar with: (a) prominent search input with magnifier icon
and Cmd+K hint pill on the right, (b) notification bell with red
badge (number from user.unreadNotifications or static "3" for
demo until the real query lands), (c) mail icon, (d) avatar + name
- level chip + dropdown caret. On
/dashboardonly, replace the current<header>(lines 824-855 of Layout.js with the search box whenshowSearch=true) with this primitive. Keep.page-header-glassfor non-dashboard pages — the two patterns coexist. Acceptance: dashboard top edge matches mockup (search bar dominant, right side has the three icons + avatar block).
4. stat-card-primitive
Add components/ui/StatCard.js exporting <StatCard> that renders:
glass-panel container, a 48×48 rounded-2xl tile on the left with a
gradient background (prop: accent="gold" | "purple" | "blue" | "red"), a white icon (children or icon prop), large number, label,
and an optional delta indicator (delta="+12.5%" or delta="-2.1%")
with up/down arrow + color. Used by sub-convoy #7 on the dashboard
(4 cards in a row). Acceptance: new component test in
test/components/StatCard.test.js covering: renders all 4 accent
gradients, renders delta in green when positive and red when
negative, renders without delta when prop omitted, escapes label as
text not HTML. The 4 accent colors get new :root tokens
(--stat-accent-gold, --stat-accent-purple, --stat-accent-blue,
--stat-accent-red) so dark/light variants are clean.
5. daily-ember-widget
Add components/DailyEmberWidget.js exporting <DailyEmberWidget>:
glass-panel container, flame icon top-left, "Daily Ember" label,
"N / M" current/max display, ember-gradient horizontal progress bar,
"Collect 20 embers for bonus XP!" helper text below. Wired to a
new (mocked-for-now) hook useDailyEmber() in lib/use-daily-ember.js
that returns { current, max, multiplier }. Real backend wiring is
out of scope; the hook returns hardcoded { current: 16, max: 20 }
matching the mockup until a separate convoy adds the API. Used by
sub-convoy #7 (mounted in the Layout sidebar above the user
menu/footer block). Acceptance: visually matches mockup, vitest
covers the hook returning a valid object shape and the component
rendering with hook data.
6. card-grid-outer-glow
Adjust components/CardItem.js's outer container to add a warm
soft outer glow that matches the mockup's card treatment (the cards
in the Featured Collection grid appear to "glow" gently from a warm
light source). Implementation: box-shadow: 0 0 24px -4px rgba(255, 128, 0, 0.18) on the card root, intensified on hover.
Must NOT touch the rarity-color glow logic (existing
gradient-text-gold etc.). Per the prior epic's hard scoping rule
("card grids may NOT use glass on every card"), the glow stays as a
single cheap box-shadow per card. Acceptance: visual matches mockup,
no scroll-jank on long card grids.
7. dashboard-rebuild
Rewrite pages/dashboard.js to assemble the new primitives into the
mockup layout. Structure:
- Layout shell unchanged
- Replace
<header>/.page-header-glasswith<TopSearchBar> - Row 1: 4×
<StatCard>(Total Cards, Rare Cards, Decks Built, Wishlist Items — the metric names from mockup) - Row 2:
<FeaturedCollectionGrid>(new component, used only by dashboard, internally is a 4×2<CardItem>grid with the mockup's title bar + filters) - Row 3:
<RecentActivityFeed>(new component, list with avatar- text + timestamp rows — wire-mocked from existing
/api/collections/recentor static if no endpoint yet)
- text + timestamp rows — wire-mocked from existing
- The right-rail Card Spotlight is OUT OF SCOPE for this sub-convoy (it's #8)
- Layout's sidebar gets
<DailyEmberWidget>mounted above the user-menu footer Existing dashboard logic (router, auth, data fetching) is preserved; only the JSX structure and component composition changes. Acceptance: deckhearth.com/dashboard side-by-side with the mockup is "recognizably the same product" (operator gate, not a CI gate).
8. right-rail-spotlight (optional follow-up)
Sketch the right-rail Card Spotlight panel from the mockup: selected card image, metadata table (Rarity, Set, Collector #, Condition), market value + delta, two charts (price trend line + market overview area). Charts via inline SVG until a charting library convoy lands. Watchlist below charts. This is a SCOPE GUARD: the data wiring (real market-value API, real watchlist) is out of scope; component ships with hardcoded demo data and a clearly-marked TODO comment. Acceptance gate: operator explicit "ship #8" approval before kicking off — easy to defer to a follow-up convoy if turn budget runs short.
6. What gets rewritten / replaced from the prior epic
Honest list of regressions from PRs #95-#101 this convoy reverses or significantly modifies:
.page-header-glassutility (PR #100) — used by /my-cards, /cards, /collections, /community/collections, /collection/[id], NOT by dashboard after #3 lands. The class stays; dashboard.js stops using it.- Dashboard's current "stat cards" (PR #97) — replaced by
<StatCard>primitive in #4 → #7. The current dashboard surfaces (.glass-panel rounded-2xl p-6) become old-shape after #7 merges. No CSS removal; just call-site replacement. - Body hearth gradient values (PR #101) — boosted to mockup intensity in #1. The composition (3 radials + linear wash) stays; the alphas roughly double.
- Sidebar active-state border-left + DH monogram (Layout.js) — replaced wholesale by #2's gradient pill + wordmark.
- Top header
<header>block whenshowSearch=true(Layout.js lines 824-855) — replaced by<TopSearchBar>on dashboard. Other pages keep the existing header (or fall through to no header). pages/dashboard.jsJSX structure — rewritten in #7. Data hooks (useAuth, query for owned cards count, etc.) preserved.
CI grep gate updates needed:
- None expected. The
forbidden-modal-shell-without-primitiveandforbidden-deprecated-color-aliasesgates from #96 remain. No new gate added; the mockup-matching is operator-judged, not CI-judged.
7. Operator decisions (locked 2026-06-04)
- Stat card metrics:
Total Cards/Rare Cards/Collection Value/Wishlist Items. Use real product data where available; placeholders (0 / N/A) where the concept doesn't yet exist (Wishlist Items has no schema today — show as 0 with a small "coming soon" subtitle until the wishlist feature ships). Cmd+Kshortcut: wired in this convoy.<TopSearchBar>ships with a global keyboard handler that opens a search modal. The modal is the minimum viable — input + 3-5 recent searches + Enter to submit. Full federated search across cards / decks / lists is a downstream convoy.- Top search bar scope: sweep to ALL authenticated pages in
this convoy. Consistent top-bar everywhere: /dashboard, /my-cards,
/cards, /collections, /community/collections, /collection/[id],
/scanner, /settings. The
.page-header-glassutility stays instyles/globals.css(it's used by other potential future pages) but no call site references it after this convoy. - Default theme: flip to dark in this convoy. The mockup's
dark variant is the visually-defining read. Light theme stays
fully supported (the toggle in the sidebar still works), but a
first-time visitor lands on dark by default. Set
[data-theme="dark"]as the initial DOM attribute inlib/theme-context.js's initial-load logic (currently defaults to system preference; change to dark unless the user has an explicit stored preference). <FeaturedCollectionGrid>data: show the user's most-recent 8 owned cards (from the existinguser_cardsquery). If the user has <8, fill with a clear "Add cards to populate this grid" CTA in the empty slots. Hardcoded demos are NOT shipped (the operator wants real data, not fake polish).- Right-rail #8: in scope. Ship the sketch with hardcoded demo data and a clearly-marked TODO comment for the real market-value API. Charts via inline SVG.
8. Roles invoked
role-conductor(this file)role-design-system-auditor— sub-convoy #1 (gradient values, contrast check at higher intensities) + #2 (active-pill contrast/glow tuning) + #4 (stat card accent token palette)role-architect— every sub-convoyrole-implementer— every sub-convoyrole-reviewer— every sub-convoy (multitask candidate after implementer ships draft)role-a11y-auditor— sub-convoys #1 (corner contrast), #2 (active-pill focus ring), #3 (top-bar tab order)role-ux-reviewer— sub-convoys #2, #3, #5, #7 (interaction patterns)
9. Status
Shipped 2026-06-04. All 8 sub-convoys merged to main in five PRs:
| Sub-convoy | PR | Squash commit | Notes |
|---|---|---|---|
| #1 hearth-bg-corner-embers + dark default | #102 | dd5ddce |
Boosted gradient ~50%; dark base shifted #1a0f0a → #0d0e1a |
| #2 sidebar pill + wordmark | #103 | ceb041b |
Bundled with #5 |
| #5 Daily Ember widget | #103 | ceb041b |
Mocked hook; backend in follow-up |
| #4 StatCard primitive | #104 | 3d11ef1 |
4 accent gradients; dashboard 4-up wired |
| #3 TopSearchBar + Cmd+K + sweep | #105 | e6e7780 |
6 page-header-glass call sites swept |
| #6 card-grid outer-glow | #106 | ea21b01 |
Single-axis shadow per perf budget |
| #7 dashboard rebuild | #107 | 7acee45 |
Bundled with #8 |
| #8 right-rail Card Spotlight | #107 | 7acee45 |
Sketch tier; demo data + inline SVG charts |
Follow-up convoys queued (out of scope for this epic, tracked here so the next agent doesn't re-discover them):
daily-ember-backend— wireuseDailyEmber()to a real/api/user/daily-emberendpoint that derives the current/max fromcollection_activity+scan_activityday-bucketed sums.rarity-aggregation— populate the StatCard "Rare Cards" tile with a real count (currently 0 + "Coming soon"). Requiresuser_cards.raritycolumn to be populated by the import jobs.wishlist-feature— populate the StatCard "Wishlist Items" tile. Requires a newwishlisttable + API.user-activity-feed— replace<DashboardRecentActivity>'s demo rows with rows from a new/api/user/activityendpoint (aggregates across collection_activity + scan_activity + trade_activity).market-data— replace<DashboardCardSpotlight>'s static demo with real market-value + price-history + watchlist APIs. Decide whether to add a charting library at that time (current sketch uses inline SVG per umbrella § 2 "No new dependency").featured-collection-filters— wire the "All Sets" filter dropdown + grid/list toggle in<DashboardFeaturedCollection>.command-palette-federated-search— extend<CommandPaletteModal>from input-then-submit to live federated results across cards / decks / lists / users. The current "Quick actions" pattern is the minimum viable.page-header-glass-css-cleanup—.page-header-glassutility instyles/globals.csshas zero call sites after sub-convoy #3 (umbrella § 7.3 contract). Remove the rule itself in a small housekeeping convoy.topbar-user-menu-dropdown— the user-menu chip in<TopSearchBar>currently routes to/settingson click. A follow-up can add a real dropdown (Settings, Profile, Theme Toggle, Sign Out) if the operator wants the full pattern.