# T06 — Styling Guardrails + Lightweight Governance Date: 2026-03-27 Scope: `recipe-manager/frontend` ## Why this exists The styling stabilization pass established a token + primitive contract. This governance doc keeps that contract from drifting back into mixed styling modes. ## Canonical styling contract (short version) 1. **Tokens are defined in one place:** `src/styles/tokens.css` 2. **Build UI from shared primitives first:** `src/components/ui/primitives.tsx` + `ui-*` classes from `src/index.css` 3. **Use tokenized values in classes/styles:** `var(--...)` or Tailwind theme aliases mapped to tokens 4. **Do not add new raw Tailwind palette utilities** (e.g. `bg-blue-500`, `text-slate-600`) in stabilized shared surfaces 5. **Do not hardcode hex colors in `className`** (e.g. `bg-[#1f2937]`) for app UI Reference docs: - `./styling-token-contract.md` - `./ui-primitive-contract.md` - `./t05-legacy-style-debt-cleanup.md` ## Lightweight automated guardrail A scoped check is available: ```bash cd frontend npm run style:guardrails ``` Current guard scope (intentional, low-risk): - `src/App.tsx` - `src/components/MissionControlPanel.tsx` - `src/components/ui/primitives.tsx` What it flags: - direct palette utility classes (`bg-blue-*`, `text-slate-*`, etc.) - hex colors in arbitrary utility classes (`bg-[#...]`, `text-[#...]`, etc.) If violations are found in guarded files, the script exits non-zero. ## Contributor checklist (copy into PR template/comments as needed) - [ ] New UI uses `Ui*` primitives or existing `ui-*` classes where possible - [ ] Any new visual token was added to `tokens.css` first - [ ] No new hardcoded palette utility classes in stabilized shell/shared primitive areas - [ ] No new hardcoded hex colors in class utilities for app surfaces - [ ] `npm run style:guardrails` passes - [ ] `npm run lint` passes ## Review heuristics for agents/contributors When touching frontend UI, quickly answer: 1. "Can this use an existing `Ui*` primitive?" 2. "If I need a new color/radius/shadow, did I add a semantic token first?" 3. "Am I introducing a second styling path that future edits will copy?" If the answer to (3) is yes, pause and refactor to the contract. ## Intentional limitations (for now) - The guard script is **scoped**, not repo-wide, because existing pages still contain known legacy palette usage (tracked in T01/T04). - The check is intentionally simple regex-based (fast, no lint plugin churn). - This is not wired into heavy CI yet; it is run locally and can be added to future CI once high-drift pages are migrated. ## Expansion path after T04/T07 As additional pages are stabilized, add them to `frontend/scripts/style-guardrails.mjs` scope to progressively tighten enforcement without breaking current workflows.