# Frontend Redesign Plan — Aligning with `docs/design` Mockups

This plan describes how to evolve `packages/web` from the current minimal Tailwind UI to match the editorial, warm-neutral design defined in `docs/design/MeshiTrack.html` and the screenshots under `docs/design/screenshots/`.

The mockups are a React (UMD + Babel) prototype using a CSS-token system. We will port the **visual language and information architecture** into the existing **Next.js App Router + Tailwind v4** project, without dragging the prototype's runtime (React UMD, global `window.*` modules, inline data) into production.

---

## 1. Goals & Non-Goals

### Goals

- Match the visual language of the mockups: typography (Fraunces / Inter Tight / JetBrains Mono), warm-neutral palette, sage brand, generous whitespace, soft shadows, rounded cards.
- Reproduce the **app shell**: persistent left sidebar with grouped navigation + sticky topbar with title/subtitle, search, theme toggle, notifications.
- Reproduce the **page archetypes** shown in the mockups: editorial "hero" header, multi-card grid with consistent `mt-card` style, status pills, supply bars, mini SVG charts.
- Support light/dark themes and an accent switcher (sage / cobalt / terracotta / graphite) via CSS custom properties.
- Keep accessibility, responsive layout, and SSR-friendliness intact.

### Non-Goals

- Do not import the prototype's `data.jsx` mock data into production.
- Do not adopt the prototype's `window.*` global module pattern or Babel-in-browser runtime.
- Do not redesign data flows or API contracts; only the presentation layer changes.
- Do not block on building every page in the mockup; food-domain pages (Phases 5-9) will reuse the system once the medicine pages are migrated.

---

## 2. Gap Analysis

| Area                                                                                                   | Current state (`packages/web`)              | Target (mockups)                                                                                                    |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| Theme tokens                                                                                           | Tailwind v4 `@theme` with a green ramp only | Full token set: warm neutrals, brand sage, status, viz palette, radii, shadows, fonts; light + dark                 |
| Typography                                                                                             | System sans only                            | Fraunces (display), Inter Tight (UI), JetBrains Mono (numerics/keys), tabular-nums utility                          |
| Sidebar                                                                                                | Flat list, 3 links, no groups, no badges    | Grouped (`Medicines` section), icons, active state, badges, footer with avatar/role                                 |
| TopBar                                                                                                 | Household chip + avatar                     | Breadcrumbs, title + subtitle, search with `⌘K`, notifications, theme toggle                                        |
| Cards                                                                                                  | Ad-hoc Tailwind cards                       | Reusable `Card`, `CardHeader`, `Pill`, `Button` (`primary`/`ghost`), supply bar, ring chart, sparkbar               |
| Dashboard                                                                                              | 2 link cards                                | Hero greeting + ring, Today's schedule, Running low, Spending bars, Days-of-supply, Pending orders, Recent activity |
| Cabinet / Schedule / Regimens / Organizer / Library / Refills / Purchases / Prices / Stores / Activity | Mostly placeholder grids/tables             | Editorial layouts with status chips, swatches, supply bars (see screenshots)                                        |
| Theming                                                                                                | None                                        | `data-theme="light                                                                                                  | dark"`on`<html>`, accent CSS vars |
| Icons                                                                                                  | None defined centrally                      | Inline SVG icon set (`Icon.jsx` in mockup)                                                                          |

---

## 3. Target Architecture

### 3.1 Design tokens (Tailwind v4 `@theme` + CSS vars)

- Replace the current `@theme` block in [packages/web/src/styles/globals.css](packages/web/src/styles/globals.css) with the full token set from [docs/design/styles/tokens.css](docs/design/styles/tokens.css):
  - Color tokens exposed both as CSS vars (`--bg`, `--ink`, `--brand`, ...) **and** as Tailwind theme colors (`--color-bg`, `--color-ink`, ...) so utilities like `bg-bg`, `text-ink`, `border-border` work.
  - Radii (`--r-xs`..`--r-xl`) and shadows (`--shadow-sm/md/lg`).
  - Font family vars + load Fraunces / Inter Tight / JetBrains Mono via `next/font/google` in [packages/web/src/app/layout.tsx](packages/web/src/app/layout.tsx) and bind them to the `--font-*` vars.
- Add `[data-theme='dark']` overrides in `globals.css` (copy from tokens.css).
- Add small global utility classes used by the mockup: `.mono`, `.serif`, `.num` (tabular-nums) — keep names so mockup snippets can be lifted with minimal edits.

### 3.2 Theme + accent provider

- New `ThemeProvider` (client component) that:
  - Persists `theme` (`light|dark`) and `accent` (`sage|cobalt|terracotta|graphite`) in `localStorage`.
  - Sets `data-theme` on `document.documentElement` and writes the accent's `--brand`, `--brand-deep`, `--brand-soft`, `--brand-soft-ink`, `--viz-1` CSS vars (logic ported from `docs/design/MeshiTrack.html` `useEffect`).
  - Avoids FOUC by emitting a tiny inline script in `app/layout.tsx` that reads `localStorage` and applies `data-theme` before hydration.
- Expose a `useTheme()` hook for the topbar toggle.

### 3.3 Component library (`packages/web/src/components/ui/`)

Port the mockup's reusable primitives as typed React components:

- `Icon` — single component over an inline SVG map (`dashboard`, `cabinet`, `clock`, `list`, `calendar`, `pill`, `refresh`, `truck`, `tag`, `store`, `trend`, `settings`, `search`, `bell`, `sun`, `moon`, `chev`, `arrow`, `check`, `injection`, `capsule`).
- `Card`, `CardHeader` (title + sub + right-side action slot).
- `Button` with `variant: 'primary' | 'ghost' | 'danger'` and optional `size`.
- `Pill` (status chip) with `tone: 'ok' | 'warn' | 'danger' | 'info' | 'neutral'`.
- `SupplyBar`, `Ring` (SVG progress ring), `SparkBars` (monthly bars), `Sparkline`.
- `Kbd`, `IconButton`, `Avatar`, `SearchInput`, `Breadcrumbs`.

These live in `packages/web/src/components/ui/` and are pure presentational components (no data fetching, no `'use client'` unless they need state — most do not).

### 3.4 App shell

Rewrite the layout primitives:

- [packages/web/src/components/layout/Sidebar.tsx](packages/web/src/components/layout/Sidebar.tsx):
  - Brand block (logo + wordmark + household sub-line — `household.name` instead of mock "Red Panda Den").
  - Grouped nav from a `NAV` array mirroring the mockup's structure but driven by `next/navigation`'s `usePathname` for active state.
  - Footer with `Avatar` + `displayName` + role from `useApi()`.
  - Badges (e.g. low-supply count, pending refills) wired to real SWR fetchers (Phase 2 — initially render the slot but optional).
- [packages/web/src/components/layout/TopBar.tsx](packages/web/src/components/layout/TopBar.tsx):
  - Accept `title`, `subtitle`, `crumbs`, `actions` props. Provided either via a `<PageHeader>` component each route renders, **or** via a Zustand/Context "page header" store updated from each page (recommended: a server-component `PageHeader` slot rendered above the page body — simpler, no client state).
  - Search input (visual only at first; `⌘K` palette is a follow-up).
  - Theme toggle wired to `useTheme()`.
  - Notifications bell (visual only initially).
- [packages/web/src/app/(dashboard)/layout.tsx](<packages/web/src/app/(dashboard)/layout.tsx>):
  - Switch root container to the mockup's grid: `grid-template-columns: 248px 1fr; min-height: 100vh; background: var(--bg)`.
  - Inner `<main>` becomes `mt-page` with the mockup's padding (`32px` desktop, responsive down).

### 3.5 Page layout pattern

Each route renders:

```
<PageHeader title="..." subtitle="..." crumbs={[...]} actions={...} />
<PageContent>...cards / grid...</PageContent>
```

`PageHeader` is a server component that renders the topbar's middle area (title block + breadcrumbs). The sticky outer `TopBar` reads `children` via React's `slots` pattern: simplest is to make `TopBar` itself accept `title/subtitle/crumbs` and have pages set them via a thin `PageHeaderContext` (client provider) or via Next's `template.tsx` + parallel routes. Choose the **Context approach** for minimal churn.

---

## 4. Page-by-Page Mapping

For each route, port the layout from the mockup's JSX while replacing mock data with the existing service hooks.

| Route                  | Current file                                                                | Mockup source                                                      | Notes                                                                                                                                                                                                 |
| ---------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/dashboard`           | [dashboard/page.tsx](<packages/web/src/app/(dashboard)/dashboard/page.tsx>) | [Dashboard.jsx](docs/design/src/Dashboard.jsx)                     | Hero + Ring, Today's schedule, Running low, Spending, Supply, Pending orders, Activity. Many cards depend on data we don't yet expose; render skeletons / "Coming soon" states for missing endpoints. |
| `/medicines/cabinet`   | `medicines/cabinet/`                                                        | [Cabinet.jsx](docs/design/src/Cabinet.jsx)                         | Grid of medicine cards with swatch, supply bar, status pill.                                                                                                                                          |
| `/medicines/regimens`  | `medicines/regimens/`                                                       | `RegimensPage` in [OtherPages.jsx](docs/design/src/OtherPages.jsx) | Per-regimen rows with schedule chips.                                                                                                                                                                 |
| `/medicines/organizer` | `medicines/organizer/`                                                      | [Schedule.jsx](docs/design/src/Schedule.jsx) `OrganizerPage`       | 7-day x slots grid.                                                                                                                                                                                   |
| `/medicines/library`   | `medicines/library/`                                                        | `LibraryPage`                                                      | Filterable medicine table.                                                                                                                                                                            |
| `/medicines/activity`  | `medicines/activity/`                                                       | `ActivityPage`                                                     | Activity feed + spend summary.                                                                                                                                                                        |
| `/refills` (new)       | —                                                                           | `RefillsPage`                                                      | Add route under `(dashboard)/refills/`.                                                                                                                                                               |
| `/purchases`           | `purchases/`                                                                | `PurchasesPage`                                                    | List with status pills.                                                                                                                                                                               |
| `/medicine-prices`     | `medicine-prices/`                                                          | `PricesPage`                                                       | Per-store price comparison.                                                                                                                                                                           |
| `/stores`              | `stores/`                                                                   | `StoresPage`                                                       | Store cards.                                                                                                                                                                                          |
| `/settings`            | `settings/`                                                                 | `SettingsPage`                                                     | Household + account sections.                                                                                                                                                                         |

Also add a **Schedule & Log** page (`/schedule` or `/medicines/schedule`) per mockup — currently missing.

Update [medicines/page.tsx](<packages/web/src/app/(dashboard)/medicines/page.tsx>) (and [dashboard/page.tsx](<packages/web/src/app/(dashboard)/dashboard/page.tsx>) if kept) to use `Card`/`CardHeader` instead of ad-hoc Tailwind classes.

---

## 5. Phased Rollout

Treat this as 5 PR-sized increments, each independently shippable.

### Phase A — Foundations (no visible page changes yet)

1. Port tokens.css into `globals.css` (CSS vars + Tailwind v4 `@theme` mappings + dark overrides).
2. Wire fonts via `next/font/google` in `app/layout.tsx`; bind to `--font-*` vars.
3. Add `ThemeProvider` + FOUC-safe inline script.
4. Add `Icon` component and the icon set.
5. Add UI primitives: `Card`, `CardHeader`, `Button`, `Pill`, `IconButton`, `Avatar`, `Kbd`, `SearchInput`, `Breadcrumbs`, `Ring`, `SupplyBar`, `SparkBars`.
6. Vitest unit tests + RTL smoke tests for each primitive.

### Phase B — App shell

1. Rewrite `Sidebar` with grouped nav, icons, active-route detection via `usePathname`, footer.
2. Rewrite `TopBar` with title/subtitle/crumbs slots, search, theme toggle, notifications.
3. Add `PageHeaderContext` (or a header slot mechanism) so pages can set the topbar content.
4. Update `(dashboard)/layout.tsx` grid + `<main>` styling.
5. Snapshot/RTL tests for shell.

### Phase C — Dashboard

1. Re-implement `/dashboard` with hero + ring + cards using real data where available, skeletons elsewhere.
2. Wire "Running low" to existing cabinet endpoint; "Pending orders" to purchases; "Activity" to activity endpoint.
3. Tests: render with seeded SWR cache.

### Phase D — Medicine pages

1. Port Cabinet, Library, Regimens, Organizer, Activity, Schedule & Log one at a time.
2. Each PR: lift JSX from the mockup, replace mock data with `services/*` SWR hooks, add tests.

### Phase E — Commerce + settings

1. Port Refills (new route), Purchases, Prices, Stores, Settings.
2. Add accent picker UI in Settings.

---

## 6. Tailwind v4 Token Mapping (concrete snippet)

In [packages/web/src/styles/globals.css](packages/web/src/styles/globals.css):

```css
@import 'tailwindcss';

@theme {
  --font-sans: 'Inter Tight', ui-sans-serif, system-ui, sans-serif;
  --font-display: 'Fraunces', ui-serif, Georgia, serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;

  --color-bg: var(--bg);
  --color-bg-elev: var(--bg-elev);
  --color-bg-inset: var(--bg-inset);
  --color-border: var(--border);
  --color-border-strong: var(--border-strong);
  --color-ink: var(--ink);
  --color-ink-strong: var(--ink-strong);
  --color-ink-muted: var(--ink-muted);
  --color-ink-faint: var(--ink-faint);
  --color-brand: var(--brand);
  --color-brand-deep: var(--brand-deep);
  --color-brand-soft: var(--brand-soft);
  --color-danger: var(--danger);
  --color-warn: var(--warn);
  --color-ok: var(--ok);
  --color-info: var(--info);

  --radius-xs: var(--r-xs);
  --radius-sm: var(--r-sm);
  --radius-md: var(--r-md);
  --radius-lg: var(--r-lg);
  --radius-xl: var(--r-xl);
}

:root {
  /* paste the :root block from docs/design/styles/tokens.css */
}
[data-theme='dark'] {
  /* paste the dark block */
}
```

This lets us write `bg-bg-elev text-ink-strong border-border rounded-lg shadow-md` while still being able to use the raw `var(--brand)` inside inline SVGs (matching the mockup's pattern).

---

## 7. Risks & Mitigations

| Risk                                                      | Mitigation                                                                                                                                      |
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| FOUC on theme switch / SSR mismatch                       | Inline script in `<head>` reads `localStorage` and sets `data-theme` before React hydrates. Mark theme-dependent UI as client-only when needed. |
| Mockup uses inline `style={{...var(--viz-X)...}}` heavily | Keep that pattern in components; tokens are CSS vars so this works fine.                                                                        |
| Real data shape differs from mock data                    | For each card, define a small typed view-model and a transformer from API DTO; render skeletons when data is unavailable.                       |
| Tailwind v4 `@theme` + custom CSS vars interplay          | Verified above: declare CSS vars in `:root`/`[data-theme=dark]`, then map them to `--color-*` inside `@theme` so utilities pick them up.        |
| Test snapshots churn                                      | Co-locate component tests, prefer RTL queries by role/text over snapshots; use snapshots only for the icon set.                                 |
| Scope creep                                               | Strictly follow the phased rollout; each phase is independently mergeable.                                                                      |

---

## 8. Out-of-Scope Follow-ups

- `⌘K` command palette (search input is visual-only initially).
- Real notification feed.
- Per-user accent persistence in DB (initially `localStorage` only).
- Mobile drawer for the sidebar (mockup is desktop-first; add a `< 900px` breakpoint that collapses to a top hamburger).
- Animations beyond the existing CSS transitions.

---

## 9. Definition of Done (per phase)

- All new components have unit tests; coverage for `packages/web` does not regress.
- `npm run lint` and `npm run typecheck` pass at the workspace root.
- Visual parity verified against the relevant screenshot in `docs/design/screenshots/`.
- No usage of `any`; all view-models typed; all client-only files marked `'use client'`.
- No regressions in existing E2E tests.
