A complete visual + tonal pass on every page. Replaces the previous shadcn
slate+emerald defaults with an Italian editorial aesthetic — refined slow-food
magazine crossed with a luxury cookbook. Mobile-first, premium, distinctly
Italian, no generic AI-wellness vibes.
Tokens:
- New palette: carta (cream parchment), ink (warm black), oliva (deep olive),
pomodoro (terracotta), oro (aged gold), rule (hairline). All exposed as
HSL CSS variables and as Tailwind colors. Dark mode = oxblood/cream.
- Type stack: Fraunces (variable, optical-sizing auto, italic + roman) for
display / Inter Tight for body / JetBrains Mono with tnum + zero for
numerals. Replaces Inter-only setup.
- Font feature settings on body and .font-display for ligatures, opsz
and stylistic alternates.
- Subtle SVG paper grain on body::before (multiply blend, 4.5% opacity).
- 2px radius default (editorial print, not soft web).
Component primitives:
- Button — mono uppercase 11px tracking-widest, sharp corners, hover
inverts ink/cream. Variants tuned for the new palette.
- Input — bottom-only hairline, Fraunces 18px text, italic placeholders.
- Label — tiny mono caps, ink-soft.
- Card — top + bottom hairlines only, no shadow; Fraunces title and italic
description; CardFooter has its own top-rule.
- Select — same hairline-bottom trigger as Input; SelectContent panel uses
a hard 6px offset shadow for an editorial print stamp feel.
New component:
- Masthead — top-of-page newspaper header with thick top-rule, KP wordmark
with terracotta dot, "ANNO I · N. 0X" issue label, today's date in Italian.
Pages:
- / — Massive Fraunces "Una keto italiana, sostenibile." with terracotta
dot, italic Fraunces tagline, right-column nav with category eyebrows
(CUCINA / PROFILO) and arrow rule. Bottom: "Tre principi" with roman
numerals I/II/III. Disclaimer in italic.
- /sign-in — "CAPITOLO II / Bentornato in cucina." split layout.
- /sign-up — "CAPITOLO III / Inizia il tuo percorso." Italian copy refresh.
- /welcome — Editor's-letter layout with the four PRD §14.3 points as a
Roman-numeral list; custom hand-drawn check icon for the consent boxes.
- /profile — 7/5 split: form on the left (anagrafica + peso group), summary
on the right with massive mono numerals (BMR, TDEE, multiplier) and italic
"kcal" units; empty-state copy until the profile is saved.
- /plan — "CAPITOLO V / Il tuo piano." Italian-formatted week range. Each
day has a Roman-numeral mark (I-VII), Fraunces day name, mono kcal total.
Each meal slot uses Roman numerals (I-IV) for the meal index.
- Cookie banner — refreshed to match (italic Fraunces, "PRIVACY" eyebrow,
outline button).
Italian copy refresh:
- Headline: "Una keto italiana, sostenibile" (was "KetoPath")
- Tagline: narrative arc instead of marketing line
- CTAs: "Iscriviti" / "Accedi" (was "Inizia gratis" / "Scopri come funziona")
- Greeting: "Buongiorno, {name}." (was "Accesso effettuato come ...")
- Profile: weight columns become Iniziale / Attuale / Obiettivo under a
"Peso (chilogrammi)" group eyebrow.
E2E updated to match: home looks for the new headline and CTA labels;
profile uses the new "Come ti chiami" / "Iniziale / Attuale / Obiettivo"
labels and asserts numeric values separately from the "kcal" unit span.
All 4 specs pass. Verified visually at 1280×900 and 375×812.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add shadcn Form helpers (Form, FormField, FormItem, FormLabel, FormControl,
FormMessage, FormDescription) on top of react-hook-form's Controller
- Add shadcn Select wrapping @radix-ui/react-select with Trigger / Content /
Item / Value, lucide chevron + check icons
- Profile form now wraps fields in <Form>...<FormField> blocks; gender and
activityLevel use the new Select with placeholder, the rest use Input;
validation errors land in <FormMessage> per field automatically
Playwright config:
- webServer is now an array — Playwright boots both api (:4000) and web (:3000)
before the suite, so server actions that proxy to API_URL work in CI/local
- profile.spec.ts updated for the new flow: post-signup goes through /welcome
to accept the medical disclaimer, then through Select primitives via
combobox click + role=option for Sesso and Livello di attività
Verified: pnpm test:e2e — 4/4 specs pass (home + 2 auth + profile).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- e2e/profile.spec.ts: fresh user signs up, opens /profile via the home CTA,
fills the Michele PRD persona values (49, MALE, 170cm, 76kg, SEDENTARY)
and asserts the summary panel shows BMR 1583 kcal and TDEE 1899 kcal
- profile-form.tsx: each Field receives an explicit `id` so <Label htmlFor>
binds correctly — Playwright's getByLabel and screen-reader navigation
both rely on this association
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Unit tests on @ketopath/auth (added to the Vitest workspace):
- readAuthEnv accepts a valid configuration
- rejects secret < 32 chars and non-URL BETTER_AUTH_URL
- preserves Google credentials when both vars are set
Playwright e2e/auth.spec.ts:
- happy path: sign-up creates a user, redirects home with welcome message,
sign-out clears session, sign-in with the same credentials restores it
- error path: invalid credentials surface a role="alert" message
- each test uses a unique generated email to avoid DB collisions
home.spec.ts: links instead of buttons (CTAs are now next/link).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vitest:
- Workspace at root (vitest.workspace.ts) running per-package configs
- packages/shared/vitest.config.ts with v8 coverage and 70% thresholds
- Root scripts: test / test:watch / test:coverage
Nutrition module in @ketopath/shared:
- calculateBmr (Mifflin-St Jeor) + calculateTdee with activity multipliers
- ACTIVITY_MULTIPLIERS constants matching CLAUDE.md domain knowledge
- 14 unit tests covering Michele/Laura PRD personas, all sex variants,
every activity level, and input validation (100% coverage on src/nutrition)
Playwright in apps/web:
- chromium-only project, webServer auto-boot of pnpm dev
- e2e/home.spec.ts smoke test asserts Italian copy and disclaimer
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>