Collapse 3 font weights (400/500/600) to 2 (400/600) per checker
requirement. Labels now use semibold (600) instead of medium (500).
Also improves CTA labels and adds focal point declaration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
phase, slug, status, shadcn_initialized, preset, created
phase
slug
status
shadcn_initialized
preset
created
7
setup-wizard
draft
true
new-york
2026-04-20
Phase 7 — UI Design Contract
Visual and interaction contract for the 3-step setup wizard. Generated by gsd-ui-researcher, verified by gsd-ui-checker.
Design System
Property
Value
Tool
shadcn (new-york style)
Preset
new-york, baseColor neutral, cssVariables true
Component library
Radix UI (via shadcn/ui)
Icon library
Lucide
Font
Inter, ui-sans-serif, system-ui, sans-serif
Spacing Scale
Declared values (must be multiples of 4):
Token
Value
Usage
xs
4px
Icon gaps, inline padding
sm
8px
Compact element spacing, checkbox-to-label gap
md
16px
Default element spacing, card internal padding
lg
24px
Section padding, stepper step gaps
xl
32px
Layout gaps, card content vertical spacing
2xl
48px
Step card top/bottom padding
3xl
64px
Page-level vertical centering offset
Exceptions: Sticky allocation bar uses 12px vertical padding (py-3) for visual compactness within the card.
Typography
Role
Size
Weight
Line Height
Body
14px
400 (regular)
1.5
Label
14px
600 (semibold)
1.4
Heading
20px
600 (semibold)
1.2
Display
28px
600 (semibold)
1.2
Only two weights are used: 400 (regular) for body text and 600 (semibold) for labels, headings, and display. No medium (500) weight exists in this contract.
Usage in wizard:
Display (28px/600): Wizard page title "Set up your budget" (step 1 heading area)
Label (14px/600): Category group headers (e.g., "Bills", "Variable Expenses"), stepper step labels, "Remaining to allocate" label, form field labels
Body (14px/400): Preset item names, amounts, helper text, step descriptions
Color
Role
Value
Usage
Dominant (60%)
oklch(0.98 0.01 260) (--background)
Page background behind wizard card
Secondary (30%)
oklch(1 0 0) (--card)
Wizard card surface, review summary card
Accent (10%)
oklch(0.55 0.15 260) (--primary)
Active stepper step indicator, primary CTA buttons, step number circles (active)
Destructive
oklch(0.6 0.2 25) (--destructive)
Negative "remaining to allocate" text, validation error text
Focal point: The primary CTA button ("Next Step" / "Complete Setup") in the bottom-right of the card is the single focal point on every step. It is the only large accent-colored element in the viewport, drawing the eye to the next action.
Accent reserved for:
Active step circle in the stepper (filled primary background)
"Next Step" and "Complete Setup" primary buttons
Income input focus ring
Completed step checkmark icon color
Additional semantic colors used (existing tokens):
--color-income (oklch(0.55 0.17 155)): Income category group header dot and badge
--color-bill (oklch(0.55 0.17 25)): Bill category group header dot and badge
--color-variable-expense (oklch(0.58 0.16 50)): Variable expense category group header dot and badge
--color-debt (oklch(0.52 0.18 355)): Debt category group header dot and badge
--color-saving (oklch(0.55 0.16 220)): Saving category group header dot and badge
--color-investment (oklch(0.55 0.16 285)): Investment category group header dot and badge
--color-on-budget (oklch(0.50 0.17 155)): Positive "remaining to allocate" text (green)
Component Inventory
New shadcn Components to Install
Component
Purpose
checkbox
Preset item selection in step 2
Existing Components Used
Component
Where
Card, CardHeader, CardContent
Wizard step container, review summary
Button
Next Step, Go Back, Skip Step, Skip setup, Complete Setup
Input
Income amount (step 1), per-item amount editing (step 2)
Badge
Category type indicators next to preset items
Label
Form field labels
Separator
Between category groups in step 2 and review step
Custom Components to Build
Component
Description
SetupWizard
Page-level orchestrator: holds wizard state, renders stepper + active step
WizardStepper
Horizontal numbered stepper bar (1-2-3) with clickable completed steps
IncomeStep
Step 1: single income input with currency indicator
RecurringItemsStep
Step 2: grouped checklist of 19 presets with editable amounts
ReviewStep
Step 3: read-only summary of selections
AllocationBar
Sticky bar showing "Remaining to allocate" with live calculation
PresetItemRow
Single checklist row: checkbox + name + category badge + amount input
CategoryGroupHeader
Section header with colored dot + category type label + item count
Layout Contract
Page Shell
Full viewport height, centered content:
- Container: flex min-h-screen items-center justify-center bg-background p-4
- No sidebar, no app nav — standalone page like login/register
- Content wrapper: w-full max-w-2xl (672px) with vertical flex layout
Stepper Bar
Position: Above the card, inside the content wrapper
Layout: flex items-center justify-center gap-8
Each step:
- Circle: 32px (w-8 h-8), centered number text (14px/600)
- Active: bg-primary text-primary-foreground
- Completed: bg-primary text-primary-foreground with Check icon (16px)
- Upcoming: bg-muted text-muted-foreground border border-border
- Connector line between steps: h-px w-16 bg-border (completed: bg-primary)
- Step label below circle: text-xs font-semibold text-muted-foreground (active: text-foreground)
Clickable: Completed steps and current step only (not future steps)
Margin below stepper: 24px (mb-6) before the card
Step Card
Card: w-full border border-border shadow-sm
CardHeader: pb-2
- Step title: heading (20px/600)
- Step description: body (14px/400) text-muted-foreground, 1 line
CardContent: space-y-6
Bottom navigation row (inside CardContent, at the bottom):
- flex justify-between items-center pt-4 border-t border-border
- Left: Go Back button (variant="ghost", hidden on step 1) + Skip Step button (variant="ghost", text-muted-foreground)
- Right: Next Step button (variant="default", primary) or Complete Setup button (step 3)
Step 1 — Income
Card content:
- Label: "Monthly net income" (14px/600)
- Input row: flex items-center gap-2
- Input: type="number", w-full, text-right, text-lg (18px), pre-filled "3000"
- Currency suffix: text-muted-foreground text-sm, shows profile currency (e.g., "EUR")
- Helper text below: "Enter your total monthly take-home pay" (14px/400, text-muted-foreground)
- Validation: if empty or <= 0 on Next Step click, show destructive text below input: "Please enter a positive income amount"
Step 2 — Recurring Items
Allocation bar (sticky):
- Position: sticky top-0 z-10, inside the card content area
- Layout: flex justify-between items-center py-3 px-4 bg-muted border-b border-border
- Left: "Remaining to allocate" (14px/600)
- Right: formatted amount (16px/600)
- Positive or zero: text-on-budget (green)
- Negative: text-destructive (red)
- Updates live on every check/uncheck and amount edit
Category groups (6 groups, ordered: income, bill, variable_expense, debt, saving, investment):
- CategoryGroupHeader: flex items-center gap-2 pt-4 pb-2
- Colored dot: w-2.5 h-2.5 (10px) circle using category color token
- Group label: label (14px/600) using categoryLabels from palette.ts
- Item count badge: text-xs text-muted-foreground "(4 items)"
- Separator below header: border-border
PresetItemRow (per item):
- Layout: flex items-center gap-3 py-2.5 px-1
- Checkbox: shadcn checkbox (16px square, sharp corners via radius-0)
- Item name: body (14px/400), flex-1
- Uses i18n key: t(`presets.${type}.${slug}`)
- Category badge: Badge variant="outline", text-xs, styled with category color border-left (3px)
- Amount input: w-24 text-right, type="number"
- Enabled only when checkbox is checked
- Disabled state: bg-muted text-muted-foreground opacity-50
- Pre-filled with preset defaultAmount
Default checked state:
- bill (4 items): ALL checked
- variable_expense (5 items): ALL checked
- income, debt, saving, investment: ALL unchecked
Step 3 — Review
Card content:
- Read-only summary, no editable fields
- Income row: flex justify-between py-2
- "Monthly income" (14px/600)
- Formatted amount (14px/600)
- Separator
- Selected items grouped by category type (same order as step 2)
- CategoryGroupHeader (same component, no checkbox)
- Per item: flex justify-between py-1.5 px-1
- Item name (14px/400)
- Amount (14px/400, text-right)
- Separator
- Totals section: space-y-1 pt-2
- "Total expenses" row: flex justify-between, 14px/600
- "Remaining" row: flex justify-between, 16px/600
- Positive: text-on-budget
- Negative: text-destructive
- If no items selected: show muted message "No items selected. You can add items to your template later."
Skip Controls
Per-step skip: Ghost button "Skip Step" in the bottom-left nav area
- Advances to next step without saving current step data
- On step 3 skip: same as "Skip setup" (exits wizard)
Global skip: "Skip setup" link/button
- Position: below the card, centered, text-sm text-muted-foreground underline
- Margin top: 16px below card
- Action: clears localStorage, sets profiles.setup_completed = true, redirects to dashboard
- No confirmation dialog (non-destructive — user can still manually set up template)
Interaction Contract
Step Navigation
Action
Behavior
Click "Next Step" (step 1)
Validate income > 0. If valid, transition to step 2. If invalid, show inline error.
Click "Next Step" (step 2)
No validation required (0 items selected is valid). Transition to step 3.
Click "Go Back"
Return to previous step. Preserve all entered data.
Click stepper circle (completed)
Navigate to that step. Preserve all data.
Click stepper circle (future)
No action. Cursor: default.
Click "Complete Setup" (step 3)
Create categories + template items via API. On success: clear localStorage, set setup_completed=true, redirect to dashboard with toast.
Click "Skip Step" (per-step)
Advance to next step without current step data. Step 1 skip: income stays at default or last entered value. Step 2 skip: uncheck all items.
Click "Skip setup" (global)
Exit wizard entirely. Clear localStorage. Mark setup_completed=true. Redirect to dashboard. No toast.
Page refresh mid-wizard
Restore wizard at the same step with all entered data from localStorage.
State Persistence (localStorage)
Key: `setup-wizard-${userId}`
Value: JSON object
{
currentStep: 1 | 2 | 3,
income: number,
selectedItems: Record<string, { checked: boolean, amount: number }>,
// keyed by preset slug
}
Cleared on: wizard completion OR skip setup
Loading & Error States
State
Behavior
Wizard loading (useFirstRunState pending)
Show centered Skeleton matching card dimensions (max-w-2xl, h-64)
Completion API in progress
"Complete Setup" button shows spinner + disabled. Go Back/Skip Step also disabled.
Completion API failure
Toast (sonner, variant destructive): "Could not save your template. Please try again." Button re-enables. Data preserved.
Partial completion failure
If categories created but template items fail: toast with "Some items could not be saved. Check your template page." Redirect to dashboard anyway.
Transitions Between Steps
No animated transitions between steps. Instant swap of step content within the card. The stepper bar updates synchronously.
Copywriting Contract
All copy must have i18n keys in both en.json and de.json. Keys live under a setup namespace.
Element
EN Copy
i18n Key
Page title (step 1)
Set up your budget
setup.title
Step 1 title
Monthly Income
setup.step1.title
Step 1 description
How much do you earn each month?
setup.step1.description
Step 1 label
Monthly net income
setup.step1.incomeLabel
Step 1 helper
Enter your total monthly take-home pay
setup.step1.helper
Step 1 validation
Please enter a positive income amount
setup.step1.validation
Step 2 title
Recurring Items
setup.step2.title
Step 2 description
Select your regular monthly expenses
setup.step2.description
Allocation bar label
Remaining to allocate
setup.step2.remaining
Step 3 title
Review
setup.step3.title
Step 3 description
Confirm your budget template
setup.step3.description
Step 3 income label
Monthly income
setup.step3.incomeLabel
Step 3 total label
Total expenses
setup.step3.totalLabel
Step 3 remaining label
Remaining
setup.step3.remainingLabel
Step 3 empty
No items selected. You can add items to your template later.
setup.step3.empty
Stepper labels
Income / Items / Review
setup.steps.1 / setup.steps.2 / setup.steps.3
Next button
Next Step
setup.next
Back button
Go Back
setup.back
Skip button
Skip Step
setup.skip
Skip setup link
Skip setup
setup.skipSetup
Complete button
Complete Setup
setup.complete
Success toast
Template created! Your first budget will appear automatically.
setup.toast.success
Error toast
Could not save your template. Please try again.
setup.toast.error
Partial error toast
Some items could not be saved. Check your template page.
setup.toast.partialError
Registry Safety
Registry
Blocks Used
Safety Gate
shadcn official
checkbox
not required
No third-party registries declared.
Accessibility Contract
Concern
Implementation
Stepper semantics
role="navigation" with aria-label="Setup progress". Each step: role="tab", aria-selected for active, aria-disabled for future.
Step content
role="tabpanel" with aria-labelledby pointing to the active step tab.
Checkbox group
Each category group is a fieldset with legend (visually styled as CategoryGroupHeader).
Income input
aria-describedby pointing to helper text and validation error (when shown).
Allocation bar
aria-live="polite" so screen readers announce remaining amount changes.
Skip links
Visible, keyboard-focusable. Not hidden behind hover.
Focus management
On step transition, focus moves to the step card heading.
Responsive Behavior
Breakpoint
Behavior
>= 768px (md)
max-w-2xl card centered, stepper horizontal with labels below circles