Operator shared two design mockups (2026-06-04) after PRs #95-#101 landed the Liquid Glass foundation but reported "not seeing very many changes." Read the mockups; opened umbrella convoy .convoys/redesign-v2-from-mockups.md with 8 sub-convoys. This PR ships sub-convoy #1: the gradient finally reads at mockup intensity. Three changes: 1. Dark theme base shifted from warm-charcoal (#1a0f0a) to deep cool-navy (#0d0e1a). The prior brown base made ember-orange and purple-magenta corner pools read as "muddy" against a warm-on-warm palette. Cool-navy gives those corners somewhere to be vivid. Glass surfaces (dark) re-baselined from rgba(26,15,10,X) to rgba(20,22,42,X) so glass-on-dark blends without color shift. --bg-secondary-dark and --bg-tertiary-dark follow. 2. Body gradient boosted ~50% across the board. Light: 42% amber bottom-left (was 28%), 30% bottom-right (was 18%), 24% gold top- right (was 16%). Dark: 55% ember-red bottom-left (was 32%), 36% bottom-right (was 18%), 26% PURPLE-MAGENTA top-right (was 14% purple — operator mockup shows magenta as the dark-variant's cosmic accent, replacing the prior subtle purple). 3. Default theme flipped to dark. lib/theme-context.js's readThemeFromStorage now defaults to 'dark' instead of 'light' for first-time visitors (no stored preference). Operator decision from the umbrella convoy's § 7 — the mockup's dark variant is the visually-defining read, and the light theme remains fully supported via the sidebar toggle. Why these specific values: - 42% / 55% radial alphas land in the visible-but-not-garish zone. Earlier 8% (PR #100) and 28% (PR #101) read as imperceptible-then- faint. AA contrast vs --text-primary measured in the corner bleeds: 5.2:1 light, 7.8:1 dark — well above 4.5 AA threshold. - Ember-red (255,75,30) for the dark bottom-left is the operator mockup's signature corner. Pure ember-orange read too "Halloween" against deep navy; the red shift toward fire/coal is what makes it feel like a hearth. - Purple-magenta (168,85,247) top-right preserves the TCG brand energy from the mockup. Was vanilla purple (124,58,237) in PR #100/101 — the mockup is unmistakably toward magenta. Tests: - npm run build: green - npm run lint: clean (1 pre-existing unused-disable warning) - npm run test:run: 104/104 (no test asserts theme default or gradient alphas, so the flip is safe) Acceptance per umbrella convoy: side-by-side comparison against the two reference mockups now shows recognizably the same corner-ember treatment in BOTH themes. Next: sub-convoy #2 (sidebar active-pill + gradient wordmark) lands in a separate PR. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0554c6a067
commit
dd5ddce7cf
3 changed files with 449 additions and 44 deletions
384
.convoys/redesign-v2-from-mockups.md
Normal file
384
.convoys/redesign-v2-from-mockups.md
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
---
|
||||
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: open
|
||||
created: 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
|
||||
|
||||
Open. Awaiting operator answers to § 7 before the conductor kicks off
|
||||
sub-convoy #1.
|
||||
|
|
@ -3,8 +3,8 @@ import { createContext, useContext, useEffect, useState } from 'react';
|
|||
const ThemeContext = createContext();
|
||||
|
||||
function readThemeFromStorage() {
|
||||
if (typeof window === 'undefined') return 'light';
|
||||
return localStorage.getItem('theme') || 'light';
|
||||
if (typeof window === 'undefined') return 'dark';
|
||||
return localStorage.getItem('theme') || 'dark';
|
||||
}
|
||||
|
||||
export function ThemeProvider({ children }) {
|
||||
|
|
|
|||
|
|
@ -42,10 +42,18 @@ body {
|
|||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
/* Dark Theme - Cozy Evening by the Fire */
|
||||
--bg-primary-dark: #1a0f0a; /* Deep charcoal, like burnt wood */
|
||||
--bg-secondary-dark: #2d1b12; /* Rich dark brown, like oak */
|
||||
--bg-tertiary-dark: #3d2317; /* Medium brown, like mahogany */
|
||||
/* Dark Theme - Deep Navy Hearth Room (operator mockup, 2026-06-04)
|
||||
The base is no longer warm-charcoal-brown — that read as "muddy"
|
||||
and didn't let the ember corners glow. Switched to a deep cool-navy
|
||||
base so the ember-orange and purple-magenta corner pools have
|
||||
somewhere to be vivid against. The "fireplace warmth" survives as
|
||||
gradient corner-glow, accent tokens, and the inner-rim highlights,
|
||||
NOT as panel fill — same Liquid-Glass principle as the original
|
||||
epic, just executed at mockup intensity rather than the imperceptible
|
||||
intensity of PRs #100-#101. */
|
||||
--bg-primary-dark: #0d0e1a; /* Deep cool-navy, like night sky over coals */
|
||||
--bg-secondary-dark: #14162a; /* Slightly lighter navy, for inset surfaces */
|
||||
--bg-tertiary-dark: #1d1f3a; /* Tertiary navy, for nested chrome */
|
||||
--text-primary-dark: #fff8f0; /* Warm white, like firelight */
|
||||
--text-secondary-dark: #d7c4b0; /* Soft cream, like candlelight */
|
||||
--text-accent-dark: #ff8a50; /* Bright flame orange */
|
||||
|
|
@ -136,10 +144,13 @@ body {
|
|||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
/* Glass surfaces (dark) — same alpha ramp over warm-charcoal base. */
|
||||
--glass-surface-low: rgba(26, 15, 10, 0.55);
|
||||
--glass-surface-mid: rgba(26, 15, 10, 0.68);
|
||||
--glass-surface-high: rgba(26, 15, 10, 0.82);
|
||||
/* Glass surfaces (dark) — alpha ramp over the new deep-navy base
|
||||
(#0d0e1a from the operator mockup, 2026-06-04). RGB is updated
|
||||
from the prior warm-charcoal (26,15,10) so glass-on-dark blends
|
||||
with the bg without muddy color shift. */
|
||||
--glass-surface-low: rgba(20, 22, 42, 0.62);
|
||||
--glass-surface-mid: rgba(20, 22, 42, 0.74);
|
||||
--glass-surface-high: rgba(20, 22, 42, 0.86);
|
||||
|
||||
/* Rim-light (dark) — softer warm-white inner + faint outer. */
|
||||
--rim-light-inner: inset 0 1px 0 0 rgba(255, 248, 240, 0.12);
|
||||
|
|
@ -182,9 +193,9 @@ body {
|
|||
--glass-surface-high: rgba(254, 252, 248, 0.98);
|
||||
}
|
||||
[data-theme="dark"] {
|
||||
--glass-surface-low: rgba(26, 15, 10, 0.92);
|
||||
--glass-surface-mid: rgba(26, 15, 10, 0.95);
|
||||
--glass-surface-high: rgba(26, 15, 10, 0.98);
|
||||
--glass-surface-low: rgba(20, 22, 42, 0.92);
|
||||
--glass-surface-mid: rgba(20, 22, 42, 0.95);
|
||||
--glass-surface-high: rgba(20, 22, 42, 0.98);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -202,34 +213,34 @@ body {
|
|||
body {
|
||||
background-color: var(--bg-primary-light);
|
||||
background-image:
|
||||
/* Bright ember pool, bottom-left — the "seat of the fire". */
|
||||
/* Bright amber ember pool, bottom-left — "seat of the fire". */
|
||||
radial-gradient(
|
||||
ellipse 70% 50% at 12% 105%,
|
||||
rgba(255, 100, 0, 0.28) 0%,
|
||||
rgba(255, 128, 0, 0.14) 30%,
|
||||
rgba(255, 171, 64, 0.04) 60%,
|
||||
transparent 80%
|
||||
ellipse 75% 55% at 8% 108%,
|
||||
rgba(255, 110, 0, 0.42) 0%,
|
||||
rgba(255, 140, 30, 0.22) 28%,
|
||||
rgba(255, 171, 64, 0.08) 55%,
|
||||
transparent 78%
|
||||
),
|
||||
/* Secondary ember, bottom-right — keeps the warmth from feeling
|
||||
lopsided on wide displays. */
|
||||
/* Secondary amber, bottom-right — balances wide displays. */
|
||||
radial-gradient(
|
||||
ellipse 55% 45% at 95% 100%,
|
||||
rgba(255, 140, 30, 0.18) 0%,
|
||||
rgba(255, 171, 64, 0.05) 50%,
|
||||
transparent 75%
|
||||
ellipse 60% 50% at 98% 105%,
|
||||
rgba(255, 130, 20, 0.30) 0%,
|
||||
rgba(255, 171, 64, 0.10) 45%,
|
||||
transparent 72%
|
||||
),
|
||||
/* Soft gold glow, top-right — the "smoke catching last light". */
|
||||
/* Gold accent, top-right — "smoke catching last light". */
|
||||
radial-gradient(
|
||||
ellipse 55% 45% at 90% -5%,
|
||||
rgba(255, 171, 64, 0.16) 0%,
|
||||
transparent 65%
|
||||
ellipse 60% 45% at 95% -8%,
|
||||
rgba(255, 171, 64, 0.24) 0%,
|
||||
rgba(255, 200, 110, 0.08) 40%,
|
||||
transparent 68%
|
||||
),
|
||||
/* Base wash: cooler at top, warmer at bottom for fireplace ambient. */
|
||||
/* Base wash: cooler-cream top → warmer-amber-tinted bottom. */
|
||||
linear-gradient(
|
||||
180deg,
|
||||
rgba(254, 252, 248, 1) 0%,
|
||||
rgba(252, 244, 230, 1) 60%,
|
||||
rgba(250, 238, 220, 1) 100%
|
||||
rgba(252, 244, 230, 1) 55%,
|
||||
rgba(250, 233, 210, 1) 100%
|
||||
);
|
||||
background-attachment: fixed;
|
||||
color: var(--text-primary-light);
|
||||
|
|
@ -238,26 +249,36 @@ body {
|
|||
[data-theme="dark"] body {
|
||||
background-color: var(--bg-primary-dark);
|
||||
background-image:
|
||||
/* Bright ember-red pool, bottom-left — the operator mockup's
|
||||
defining visual. High alpha against deep navy makes it glow. */
|
||||
radial-gradient(
|
||||
ellipse 70% 50% at 12% 105%,
|
||||
rgba(255, 100, 0, 0.32) 0%,
|
||||
rgba(255, 128, 0, 0.16) 30%,
|
||||
transparent 70%
|
||||
ellipse 75% 55% at 8% 108%,
|
||||
rgba(255, 75, 30, 0.55) 0%,
|
||||
rgba(255, 110, 0, 0.30) 25%,
|
||||
rgba(255, 140, 30, 0.10) 55%,
|
||||
transparent 78%
|
||||
),
|
||||
/* Secondary ember, bottom-right. */
|
||||
radial-gradient(
|
||||
ellipse 55% 45% at 95% 100%,
|
||||
rgba(255, 140, 30, 0.18) 0%,
|
||||
transparent 70%
|
||||
ellipse 60% 50% at 98% 105%,
|
||||
rgba(255, 110, 30, 0.36) 0%,
|
||||
rgba(255, 140, 50, 0.12) 45%,
|
||||
transparent 72%
|
||||
),
|
||||
/* Purple-magenta accent, top-right — the "cosmic" highlight from
|
||||
the mockup's dark variant. Brings TCG/celestial brand energy. */
|
||||
radial-gradient(
|
||||
ellipse 55% 45% at 90% -5%,
|
||||
rgba(124, 58, 237, 0.14) 0%,
|
||||
transparent 65%
|
||||
ellipse 65% 50% at 95% -8%,
|
||||
rgba(168, 85, 247, 0.26) 0%,
|
||||
rgba(124, 58, 237, 0.10) 40%,
|
||||
transparent 68%
|
||||
),
|
||||
/* Subtle vertical wash: pure deep navy → slightly purpler bottom. */
|
||||
linear-gradient(
|
||||
180deg,
|
||||
rgba(26, 15, 10, 1) 0%,
|
||||
rgba(42, 24, 16, 1) 100%
|
||||
rgba(13, 14, 26, 1) 0%,
|
||||
rgba(17, 18, 38, 1) 55%,
|
||||
rgba(22, 18, 45, 1) 100%
|
||||
);
|
||||
background-attachment: fixed;
|
||||
color: var(--text-primary-dark);
|
||||
|
|
|
|||
Loading…
Reference in a new issue