deckhearth/.convoys/redesign-v2-from-mockups.md
varutasu f701c4ac89
docs(convoys): mark redesign-v2-from-mockups epic shipped (8/8 sub-convoys merged) (#108)
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>
2026-06-04 11:24:34 -05:00

429 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: redesign-v2-from-mockups
classification: epic
success_metric: |
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).
skip: []
status: shipped
created: 2026-06-04
shipped: 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-panel` utility 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 `.js` per 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 `recharts` install 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 `:root` var
(or its `[data-theme="dark"]` override).
- Both themes ship together per sub-convoy.
- `prefers-reduced-motion` honored; new animations opt-in via
`.motion-essential` only 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-primary` in the affected viewport region.
- `backdrop-filter` followed the rules from PR #99's maintainer
comment: literal values inside `blur()`, 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-linux` queued 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 `/dashboard` only, replace the
current `<header>` (lines 824-855 of Layout.js with the search box
when `showSearch=true`) with this primitive. Keep `.page-header-glass`
for 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-glass` with `<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/recent` or static if no endpoint yet)
- 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-glass` utility (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 when `showSearch=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.js` JSX 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-primitive` and
`forbidden-deprecated-color-aliases` gates from #96 remain. No new
gate added; the mockup-matching is operator-judged, not CI-judged.
---
## 7. Operator decisions (locked 2026-06-04)
1. **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).
2. **`Cmd+K` shortcut**: 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.
3. **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-glass` utility stays in
`styles/globals.css` (it's used by other potential future pages)
but no call site references it after this convoy.
4. **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 in
`lib/theme-context.js`'s initial-load logic (currently defaults
to system preference; change to dark unless the user has an
explicit stored preference).
5. **`<FeaturedCollectionGrid>` data**: show the user's most-recent
8 owned cards (from the existing `user_cards` query). 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).
6. **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-convoy
- `role-implementer` every sub-convoy
- `role-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](https://github.com/varutasu/tcg-vault/pull/102) | `dd5ddce` | Boosted gradient ~50%; dark base shifted #1a0f0a #0d0e1a |
| #2 sidebar pill + wordmark | [#103](https://github.com/varutasu/tcg-vault/pull/103) | `ceb041b` | Bundled with #5 |
| #5 Daily Ember widget | [#103](https://github.com/varutasu/tcg-vault/pull/103) | `ceb041b` | Mocked hook; backend in follow-up |
| #4 StatCard primitive | [#104](https://github.com/varutasu/tcg-vault/pull/104) | `3d11ef1` | 4 accent gradients; dashboard 4-up wired |
| #3 TopSearchBar + Cmd+K + sweep | [#105](https://github.com/varutasu/tcg-vault/pull/105) | `e6e7780` | 6 page-header-glass call sites swept |
| #6 card-grid outer-glow | [#106](https://github.com/varutasu/tcg-vault/pull/106) | `ea21b01` | Single-axis shadow per perf budget |
| #7 dashboard rebuild | [#107](https://github.com/varutasu/tcg-vault/pull/107) | `7acee45` | Bundled with #8 |
| #8 right-rail Card Spotlight | [#107](https://github.com/varutasu/tcg-vault/pull/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):
1. `daily-ember-backend` wire `useDailyEmber()` to a real
`/api/user/daily-ember` endpoint that derives the current/max
from `collection_activity` + `scan_activity` day-bucketed sums.
2. `rarity-aggregation` populate the StatCard "Rare Cards" tile
with a real count (currently 0 + "Coming soon"). Requires
`user_cards.rarity` column to be populated by the import jobs.
3. `wishlist-feature` populate the StatCard "Wishlist Items" tile.
Requires a new `wishlist` table + API.
4. `user-activity-feed` replace `<DashboardRecentActivity>`'s demo
rows with rows from a new `/api/user/activity` endpoint
(aggregates across collection_activity + scan_activity +
trade_activity).
5. `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").
6. `featured-collection-filters` wire the "All Sets" filter
dropdown + grid/list toggle in `<DashboardFeaturedCollection>`.
7. `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.
8. `page-header-glass-css-cleanup` `.page-header-glass` utility
in `styles/globals.css` has zero call sites after sub-convoy #3
(umbrella § 7.3 contract). Remove the rule itself in a small
housekeeping convoy.
9. `topbar-user-menu-dropdown` the user-menu chip in
`<TopSearchBar>` currently routes to `/settings` on click. A
follow-up can add a real dropdown (Settings, Profile, Theme
Toggle, Sign Out) if the operator wants the full pattern.