# T01 — Styling Inventory + Drift Map

Date: 2026-03-27  
Project: `recipe-manager/frontend`  
Task: **T01 — Styling Inventory + Drift Map**

## Scope audited
- Token sources: `src/styles/tokens.css`, `src/theme.ts`, `frontend/tailwind.config.js`
- Shared styling layer: `src/index.css` (`ui-*` primitives)
- Legacy stylesheet: `src/App.css`
- App shell + representative screens/components:
  - `src/App.tsx`
  - `src/pages/RecipeListPage.tsx`
  - `src/pages/RecipeDetailPage.tsx`
  - `src/pages/CookModePage.tsx`
  - `src/pages/ImportUrlPage.tsx`
  - `src/pages/NotFoundPage.tsx`
  - `src/components/RecipeCard.tsx`
  - `src/components/RecipeForm.tsx`
  - `src/components/TagSelector.tsx`
  - `src/components/Toast.tsx`
  - `src/components/MissionControlPanel.tsx`
  - `src/components/ErrorBoundary.tsx`

---

## 1) Where styling primitives currently live

### Canonical CSS token surface (already strong)
- **`src/styles/tokens.css`**
  - semantic color, typography, spacing, radius, shadow, focus, gradients
  - includes dark-mode token overrides

### Utility-class primitives (already present)
- **`src/index.css` @layer components** defines:
  - `.ui-page`, `.ui-section`, `.ui-card`
  - `.ui-btn`, `.ui-btn-primary`, `.ui-btn-secondary`
  - `.ui-input`, `.ui-textarea`, `.ui-select`
  - `.ui-chip`, `.ui-badge`
- Also contains global focus-visible behavior and utility legacy classes (`.card`, `.shadow-card`, `animate-slide-in`)

### Tailwind token mapping
- **`frontend/tailwind.config.js`** maps many Tailwind theme keys to CSS vars (good bridge)

### Parallel TS token layer (drift risk)
- **`src/theme.ts`** duplicates many token values from `tokens.css`
  - `colors`, `typography`, `spacing`, `radius`, `shadows`, `componentStyles`

### Legacy stylesheet
- **`src/App.css`** contains Vite/demo-era nested selectors (`#next-steps`, `.hero`, `.counter`, etc.)
- not imported by `main.tsx` or other src files in current app

---

## 2) Systems currently being mixed

1. **UI primitives + token vars** (`ui-*`, `var(--...)`)  
2. **Raw Tailwind palette utilities** (`bg-blue-*`, `text-slate-*`, `border-gray-*`, etc.)  
3. **Inline style objects via `theme.ts`** (`style={{ borderRadius: radius.lg }}`, `boxShadow: shadows.card`)  
4. **One-off arbitrary values** (`hover:[box-shadow:var(--shadow-hover)]`, `shadow-[...]`)  
5. **Legacy class debt** (`App.css`, and old helper classes in `index.css`)

Result: there is no enforced single styling path; authors can pick multiple parallel approaches in the same file.

---

## 3) Inventory by file (top-level pages + shared components)

Legend:
- **A** = ui-* primitives + var tokens (preferred direction)
- **B** = raw Tailwind palette utilities (non-tokenized drift)
- **C** = inline `theme.ts` style objects
- **D** = legacy/older pattern

### App shell
- `src/App.tsx` → **B-heavy**
  - Header/nav/footer use many `blue/slate/gray` classes and custom focus ring colors
  - Does not use `ui-page`, `ui-section`, `ui-btn` contract

### Pages
- `src/pages/RecipeListPage.tsx` → **A + C mix (plus some B)**
  - strong `ui-*` adoption
  - frequent inline radius/style injections from `theme.ts`
- `src/pages/RecipeDetailPage.tsx` → **A + B + C mixed**
  - uses many `ui-*` classes but also many non-token Tailwind palette classes and inline styles
- `src/pages/CookModePage.tsx` → **B-only (high drift)**
  - almost entirely gray/blue/green/red Tailwind palette utilities
  - no `ui-*` shell/primitives
- `src/pages/ImportUrlPage.tsx` → **B + C (high drift)**
  - heavily uses slate/blue/indigo/green palette classes
  - inline radius/progress width styles
- `src/pages/NotFoundPage.tsx` → **B-only**

### Shared components
- `src/components/RecipeForm.tsx` → **A-dominant**
- `src/components/TagSelector.tsx` → **A-dominant + tiny C**
- `src/components/RecipeCard.tsx` → **A + C mixed**
- `src/components/Toast.tsx` → **C-dominant**
  - visual appearance mostly from `theme.ts` inline styles
- `src/components/MissionControlPanel.tsx` → **B-only**
- `src/components/ErrorBoundary.tsx` → **B-only**

### Approximate drift signal (quick scan)
- Highest raw palette concentration: `CookModePage`, `ImportUrlPage`, `App.tsx`, `RecipeDetailPage`
- Highest inline-style concentration: `RecipeListPage`, `RecipeCard`, `Toast`

---

## 4) Representative drift hotspots

1. **`App.tsx` (app shell)**
   - Entire global frame (header/nav/footer) is on blue/slate palette utilities
   - creates visual disconnect from tokenized warm palette used in recipe surfaces

2. **`CookModePage.tsx`**
   - Separate visual language (blue/gray success/error blocks) and no `ui-*` primitives
   - likely to regress independently if token theme changes

3. **`ImportUrlPage.tsx`**
   - Similar drift pattern to CookModePage; raw utility palette + custom gradients

4. **`RecipeDetailPage.tsx`**
   - Mixed approach in same component: token vars + ui-* + raw palette + inline styles
   - hard to predict and maintain consistency

5. **`Toast.tsx` + `theme.ts` coupling**
   - toast visuals encoded in TS style objects instead of ui primitives/token classes

6. **`App.css` + legacy selectors in `index.css`**
   - `App.css` appears unused yet present
   - `.card` / `.shadow-card` coexist with `ui-card`, increasing ambiguity

---

## 5) Highest-risk problem areas

- **Token drift risk**: same values duplicated in `tokens.css` and `theme.ts`.
- **App-shell inconsistency risk**: `App.tsx` not on design-system primitives.
- **Page-level divergence risk**: CookMode/Import URL/NotFound/MissionControl use different style dialect than core recipe pages.
- **Maintainability risk**: inline style overrides (`borderRadius`, `boxShadow`) bypass primitive contract and encourage per-component customization.
- **Regression risk**: no guardrails prevent new raw palette utilities in future UI work.

---

## 6) First conversion targets (for stabilization wave)

1. `src/App.tsx` (global shell contract)
2. `src/components/MissionControlPanel.tsx` (small, easy, high-visibility drift)
3. `src/pages/CookModePage.tsx` (largest isolated drift surface)
4. `src/pages/ImportUrlPage.tsx` (same drift pattern as CookMode)
5. `src/components/Toast.tsx` (inline-style dependency cleanup)

---

## 7) Acceptance criteria for stabilization work (T02+)

A stabilization pass is accepted when all are true:

1. **Single token authority**
   - CSS vars in `tokens.css` are canonical.
   - `theme.ts` no longer independently defines conflicting visual token values.

2. **Primitive contract adoption**
   - app shell + major pages use shared `ui-*` primitives (or wrapper components built from them).
   - new features avoid ad-hoc color utilities outside tokenized scheme.

3. **Inline-style reduction**
   - no routine radius/shadow/color inline overrides where equivalent primitive/token class exists.

4. **Legacy debt disposition**
   - `App.css` removed or explicitly retained with documented rationale.
   - overlapping legacy helpers (`.card`, `.shadow-card`) either standardized or deprecated.

5. **Governance check**
   - lightweight styling checklist/doc exists and is referenced in workflow.

---

## 8) Suggested next task after T01

**T02 — Canonical Token Source Lock**
- lock CSS tokens as source of truth
- redefine `theme.ts` as typed accessor only (or trim to non-visual helpers)
- document token contract before broad conversion starts
