Files
Parsons/docs/memory/archive/sessions-through-2026-03-26.md
Richie aa7cdeecf0 Add workflow infrastructure — ESLint, Prettier, Husky, Vitest, 7 new skills
Phase 1: Session log archived (1096→91 lines), D031 token access convention
Phase 2: ESLint v9 + Prettier + jsx-a11y, initial config and lint fixes
Phase 3: 7 new skills (polish, harden, normalize, clarify, typeset, quieter, adapt)
         + Vercel reference docs, updated audit/review-component refs
Phase 4: Husky + lint-staged pre-commit hooks, preflight updated to 8 checks
Phase 5: Vitest + Testing Library + /write-tests skill

- Badge.tsx colour maps unified to CSS variables (D031)
- 5 empty interface→type alias fixes (Switch, Radio, Divider, IconButton, Link)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:41:57 +11:00

63 KiB
Raw Blame History

Session 2026-03-26d — FuneralFinder v2 build

Agent(s): Claude Opus 4.6 (1M context)

Work completed:

  • Built FuneralFinderV2 from scratch — completely different approach from v1 (quick-form vs stepped wizard)
  • 4-step vertical form with 48px numbered circles (brand-200 default → brand-500 completed) and 3px connector lines
  • Steps: (1) Intent (3 options), (2) Planning for (conditional auto-set for arrange-now), (3) Funeral type (5 options), (4) Location
  • Sequential unlock logic: each step enables only when the previous is filled
  • Labels use brand-700 copper when active, text.disabled when locked
  • Selects match Input medium height (48px) via py: 14px
  • Display serif heading + body2 subheading with full-width divider
  • Default contained CTA (copper), disabled until location has 3+ chars
  • Trust signal "Free to use · No obligation" below CTA
  • Focus rings suppressed (subtle brand-400 border only)
  • Full accessibility: role="search", aria-required, aria-label on all fields
  • Multiple iteration rounds incorporating user feedback on sizing, alignment, colours, spacing, and layout
  • Ran /critique (33/40 Good) and /audit (18/20 Excellent) — fixed all P0/P1 issues

Decisions made:

  • v2 keeps v1 alongside — both exported from index.ts for comparison
  • Step circles use brand-200 warm fill (not neutral grey) for palette cohesion
  • "Plan a funeral for someone expected to pass soon" softened to "Plan ahead for someone who is unwell"
  • Connector lines use ::after on each StepCircle rather than container ::before (starts from circle bottom, not above)
  • Location input uses no icon, matches select styling (py: 14px, fontSize: 0.875rem)

Open questions:

  • Which version (v1 or v2) to proceed with for production? May keep both and A/B test
  • Connector line height (60px) is a magic number — works for single-line labels but would need adjustment if labels wrap

Next steps:

  • User to review in Storybook and decide on v1 vs v2 direction
  • If v2 chosen: add location autocomplete, consider progress summary state
  • Update docs/reference/ with v2 flow logic doc (similar to funeral-finder-logic.md for v1)

Session 2026-03-26c — FuneralFinder v1 refinement and completion

Agent(s): Claude Opus 4.6 (1M context)

Work completed:

  • Redesigned FuneralFinder from a "dump everything in step 3" pattern to a full stepped conversational flow
  • Every decision is now its own step with CompletedRow collapse (intent → planning-for → type+preferences → service → location+CTA)
  • CTA ("Find funeral providers") and location input are always visible at the bottom — not gated behind steps
  • Implemented smart defaults: minimum search requirements are intent + location; type/service/themes default to "show all"
  • Added funeral type options: Cremation, Burial, Water Burial (QLD only), Explore All (as a proper TypeCard)
  • Added service preference step (conditional): With a service / No service / I'm flexible
  • Added theme preferences (eco-friendly, budget-friendly, religious specialisation) as optional sub-option within type step
  • Created StepHeading sub-component (bodyLg, centered) for clear hierarchy vs card labels (body1/body2)
  • Added loading prop for CTA button, location validation (3+ chars with error state)
  • Added Divider under subheading, h2 display heading, generous CompletedRow spacing (py: 1.5)
  • Fixed accessibility: aria-label on Change links, role="alert" on intent prompt, 44px touch targets on all chips
  • Removed "Take your time" empathetic message per user preference
  • Renamed "ceremony" → "service" throughout, "Without (direct)" → "No service"
  • Removed TypeCard descriptions for standard types (Cremation, Burial don't need them)
  • Multiple audit/critique cycles: final scores Audit 14/20 (Good), Critique 29/40 (Good)

Decisions made:

  • CTA always visible with smart defaults — users can skip optional steps and search with just intent + location
  • Stepped flow continues through ALL decisions (not just steps 1-2 like the previous version)
  • Theme preferences belong in the type step as a sub-option, not in the location step
  • "Where are you looking?" (not "located") to allow searching outside own area
  • Step headings use bodyLg centered for visual hierarchy distinct from card labels

Open questions:

  • Progress indicator (Step X of Y) — flagged by critique as P2, deferred. Variable step count makes implementation non-trivial.
  • Roving tabindex for radiogroups — flagged by audit as P0, deferred. Requires arrow-key handler + tabindex management.
  • Location autocomplete — flagged by critique as P2, deferred. Would need suburb/postcode API integration.
  • CSS var vs MUI theme accessor consistency — flagged by audit, deferred. Architectural choice to address system-wide.

Next steps:

  • FuneralFinder v1 is complete and approved
  • Consider building the homepage hero composition as a standalone organism or page template
  • ArrangementForm organism is next planned organism (multi-step wizard with StepIndicator)

Session 2026-03-24 — Project scaffold setup and hygiene

Agent(s): Manual (no agents invoked — setup phase)

Work completed:

  • Fixed missing .storybook/ directory (main.ts + preview.tsx with MUI ThemeProvider)
  • Created .gitignore (was missing entirely)
  • Created .mcp.json with Figma remote MCP config
  • Removed malformed {.claude/agents,.claude/...} directory tree (bash brace expansion bug)
  • Created 3 agent definitions: token-architect, component-builder, story-writer
  • Created 8 slash commands: create-tokens, build-atom, build-molecule, build-organism, write-stories, sync-tokens, status, review-component
  • Migrated commands from .claude/commands/ to .claude/skills/<name>/SKILL.md format with YAML frontmatter
  • Fixed critical Style Dictionary v4 config: converted from CommonJS to ESM (StyleDictionary class API)
  • Changed build:tokens script from style-dictionary build --config ... to node style-dictionary/config.js
  • Added "type": "module" to package.json for ESM support
  • Changed SD output from tokens.ts to tokens.js (Style Dictionary v4 generates JS, not TS)
  • Registered @storybook/addon-designs in .storybook/main.ts (was installed but not configured)
  • Added CSS token import to .storybook/preview.tsx
  • Added Card and Link to CLAUDE.md atom list (were missing)
  • Fixed broken Penpot/Storybook MCP references in docs/reference/mcp-setup.md
  • Improved agent instructions with pre-flight dependency checks, story checklist enforcement, token validation steps, and MUI theme mapping guide
  • Created src/components/{atoms,molecules,organisms}/ directories
  • Fixed bootstrap.sh to check for .storybook/ dir instead of node_modules/@storybook
  • Verified npm run build:tokens runs successfully (empty output expected — no tokens yet)
  • Verified Storybook runs at http://localhost:6006

Decisions made:

  • Skills use .claude/skills/<name>/SKILL.md format (not .claude/commands/)
  • Style Dictionary v4 config is a standalone ESM script run via node, not CLI
  • British spelling for filenames (colours.json), standard color namespace for token paths

Open questions:

  • Slash commands /create-tokens etc. showing "Unknown skill" — may need Claude Code restart to discover newly created skills. User should test after restarting.

Next steps:

  • Verify slash commands work after Claude Code restart ✓ Skills working
  • Begin Step 1: /create-tokens with brand colours, fonts, and reference material ✓ Done

Session 2025-03-25 — Token creation (Step 1)

Agent(s): token-architect (via /create-tokens skill)

Work completed:

  • Extracted brand colours from user-provided swatch image (12 colours across 3 palettes)
  • Reviewed 5 Parsons FA 1.0 Figma screens for colour application context
  • Reviewed 2 FA 2.0 Design System Template screens (buttons + inputs)
  • Created complete primitive tokens:
    • Colour scales (50-950): brand (warm gold), sage (cool grey-green), neutral, red, amber, green, blue + white/black
    • Typography: 3 font families (Montserrat, Noto Serif SC, JetBrains Mono), font size scale (xs-4xl + mobile), weights, line heights, letter spacing
    • Spacing: 4px-based scale (2px-80px), border radius scale
    • Effects: 4 shadow levels, 3 opacity values
  • Created complete semantic tokens:
    • Colour mappings: text (9 variants), surface (6), border (6), interactive (7), feedback (8)
    • Typography roles: display, h1-h4, bodyLarge, body, bodySmall, caption, label, overline — each with font family, size, weight, line height, letter spacing + mobile size overrides
    • Spacing: component (xs-lg), layout (gutter, section, page, padding) with mobile/desktop variants
  • Fixed Style Dictionary v4.4.0 CSS output: added usesDtcg: true flag (required for DTCG format CSS generation)
  • Generated outputs:
    • CSS: 245 custom properties in src/theme/generated/tokens.css with var() references for semantic tokens
    • JS: 258 named exports in src/theme/generated/tokens.js
    • JSON: flat export in tokens/export/tokens-flat.json
  • Updated MUI theme (src/theme/index.ts):
    • All palette colours mapped from token imports
    • All typography variants mapped (h1-h6, body1, body2, subtitle1/2, caption, overline, button)
    • 3 custom typography variants added: display, bodyLarge, label (with TS module declarations)
    • Responsive font sizes via @media queries for display, h1, h2, h3
    • Component overrides for Button and Card border radius
  • Updated docs/design-system.md with actual brand colours, palettes, and font stacks
  • Updated docs/memory/decisions-log.md with 8 design decisions (D001-D008)
  • Updated docs/memory/token-registry.md with complete token reference

Decisions made:

  • D001: Primary brand colour is #BA834E (warm gold from swatch)
  • D002: Primary text colour is #2C2E35 (charcoal, not pure black)
  • D003: Brand link colour uses #B0610F (copper, meets WCAG AA)
  • D004: Sage palette as secondary (calming contrast to warm primary)
  • D005: Noto Serif SC for display/H1-H2, Montserrat for H3+ and body
  • D006: Warning text uses amber.700 for AA compliance
  • D007: Style Dictionary requires usesDtcg: true for CSS output
  • D008: Responsive typography via explicit @media queries in MUI theme

Open questions:

  • Font name confirmation: user wrote "Not Serif SC" — interpreted as "Noto Serif SC" (Google Font). Needs confirmation.
  • brand.500 (#BA834E) has 3.7:1 contrast on white — AA for large text only. Primary buttons use white text on this background, which works for button-sized text. Should we darken the primary CTA colour for better accessibility, or is the current value acceptable?
  • Token collision warning: benign collision on $type: "color" set in both primitives and semantic colour files. Doesn't affect output.

Next steps:

  • Confirm display font name (Noto Serif SC vs something else)
  • Begin Step 2: Build first atom component (Button recommended as it exercises the most tokens) ✓ Done
  • Consider adding Google Fonts import for Montserrat and Noto Serif SC to index.html or Storybook preview

Session 2026-03-25 — Button atom (Step 2)

Agent(s): Claude Opus (via conversation)

Work completed:

  • Reviewed 3 Figma component sets: Icons (29:54), Button (28:50), Text Button (32:1361)
  • Created button component tokens (tokens/component/button.json): height, paddingX, paddingY, fontSize, iconSize, iconGap, borderRadius for xs/sm/md/lg sizes
  • Rebuilt token pipeline — 25 new button tokens generated across CSS/JS/JSON outputs
  • Updated MUI theme (src/theme/index.ts) with comprehensive MuiButton overrides:
    • 4 sizes: xs (28px), small (32px), medium (40px), large (48px)
    • Contained, outlined, text variants for primary and secondary colours
    • Hover backgrounds using brand.100 and sage.100 for outlined/text variants
    • Focus-visible outline (2px solid interactive.focus, 2px offset)
    • Disabled elevation via disableElevation: true default prop
    • Custom xs size via MUI variant system + module augmentation
  • Created Button component (src/components/atoms/Button/Button.tsx):
    • Wraps MUI Button with React.forwardRef
    • Custom props: loading (spinner + disabled), underline (text-decoration for text variant)
    • Accepts all MUI ButtonProps (variant, color, size, startIcon, endIcon, fullWidth, etc.)
  • Created barrel export (src/components/atoms/Button/index.ts)
  • Created comprehensive Storybook stories (Button.stories.tsx): 16 stories covering Default, Variants (primary/secondary), AllSizes, Icons, Disabled, Loading, TextWithUnderline, FullWidth, LongContent, CompleteMatrix
  • Storybook builds successfully with Button stories

Decisions made:

  • D009: Merge Text Button into Button atom — text buttons are variant="text" with optional underline prop, not a separate component
  • D010: Button sizes adjusted for touch targets — xs: 28px, sm: 32px, md: 40px, lg: 48px (lg meets 44px minimum)
  • D011: Use @mui/icons-material over Font Awesome — native MUI integration, no adapter needed, tree-shakeable
  • D012: Responsive sizing is a composition concern — Button size is an explicit prop, not responsive by default. Layouts choose the right size per breakpoint.

Open questions:

  • primary.main maps to brand.600 (copper #B0610F) for AA compliance, but Figma designs show brand.500 (warm gold #BA834E) as primary button fill. Should we adjust? Current mapping prioritises accessibility.
  • Google Fonts import still needed for Montserrat and Noto Serif SC in Storybook
  • Icon approach confirmed as @mui/icons-material — should we create any custom SvgIcon components for FA-specific icons?

Next steps:

  • User to review Button in Storybook and provide feedback on colours/sizing ✓ Feedback received
  • Build Typography atom
  • Add Google Fonts to Storybook preview
  • Log D009-D012 in decisions-log.md ✓ Done

Session 2026-03-25b — Button refinements from user review

Agent(s): Claude Opus (via conversation)

Work completed:

  • Fetched Figma Secondary/Brand and Secondary/Grey button details — discovered they are soft-filled (tonal) buttons, not outlined
  • Added custom variant="soft" to MUI Button — tonal/muted fill treatment
    • Primary soft: brand.200 bg (#EBDAC8), brand.700 text (#8B4E0D), brand.300 hover
    • Secondary soft: neutral.200 bg (#E8E8E8), neutral.700 text (#404040), neutral.300 hover
  • Changed MUI secondary palette from sage to neutral grey (neutral.600 main, neutral.700 dark, neutral.300 light)
  • Updated all secondary button overrides (outlined, text) from sage to neutral
  • Moved loading spinner from left to right side of button text
  • Updated stories: added FigmaMapping story, soft variant stories, LoadingToSuccess pattern story
  • Logged D013-D015 in decisions log

Decisions made:

  • D013: Added soft variant for tonal buttons — maps to Figma Secondary/Brand and Secondary/Grey
  • D014: Secondary palette changed from sage to neutral grey
  • D015: Loading spinner positioned on right

Open questions:

  • primary.main maps to brand.600 (copper #B0610F) for AA compliance, but Figma designs show brand.500 (warm gold #BA834E) as primary button fill. Should we adjust?
  • Google Fonts import still needed for Montserrat and Noto Serif SC in Storybook
  • Icon approach confirmed as @mui/icons-material — should we create any custom SvgIcon components for FA-specific icons?
  • Sage palette no longer used for buttons — consider if it should be re-introduced as a custom colour later

Next steps:

  • User to re-review Button in Storybook ✓ Approved as good baseline
  • Build Typography atom ✓ Done
  • Add Google Fonts to Storybook preview ✓ Done

Session 2026-03-25c — Typography atom + housekeeping

Agent(s): Claude Opus (via conversation)

Work completed:

  • Added Google Fonts loading: Montserrat (400/500/600/700) + Noto Serif SC (600/700) in .storybook/preview-head.html and index.html
  • Created Typography component (src/components/atoms/Typography/Typography.tsx):
    • Thin wrapper around MUI Typography with React.forwardRef
    • Custom prop: maxLines for CSS line-clamp truncation
    • All MUI Typography props passed through (variant, color, align, component, gutterBottom, etc.)
  • Created barrel export (src/components/atoms/Typography/index.ts)
  • Created comprehensive Storybook stories (9 stories): Default, HeadingHierarchy, BodyVariants, UIText, Colours, SemanticHTML, MaxLines, RealisticContent, FontFamilies
  • Added "Future enhancements" tracking table to component-registry.md — deferred items (IconButton, destructive colours, link-as-button) tracked with triggers for when to address them
  • Logged D016 (primary colour confirmed as copper brand.600) in decisions-log.md
  • Storybook builds successfully

Decisions made:

  • D016: Primary button colour confirmed as copper (brand.600) — user approved
  • Typography atom is a thin wrapper + maxLines — no over-engineering

Open questions:

  • Icon approach confirmed as @mui/icons-material — should we create any custom SvgIcon components for FA-specific icons?
  • Sage palette no longer used for buttons — consider if it should be re-introduced as a custom colour later

Next steps:

  • User to review Typography in Storybook
  • Build next atom (Input or Card recommended — Input for forms, Card for service listings)
  • Consider building FormField molecule next if Input is done (label + input + helper text)

Session 2026-03-25d — Typography expansion (21 variants)

Agent(s): Claude Opus (via conversation)

Work completed:

  • Reviewed user's FA 2.0 Figma type scale (node 23:30) — 21 variants across 6 categories, 3 responsive breakpoints
  • Expanded primitive typography tokens: added fontSize.2xs (11px), fontSize.display.* sub-group (hero 80px through sm 32px), mobile overrides for all display and heading sizes
  • Rewrote semantic typography tokens: 21 variants with specific line-heights and letter-spacing per variant
  • Rewrote MUI theme typography section: refactored to wildcard import (import * as t), added all 21 variants with module augmentations, responsive scaling via @media queries
  • Updated Google Fonts: added Noto Serif SC weight 400 (Regular) for display text
  • Updated Typography component JSDoc with full variant guide
  • Rewrote Typography stories: 10 stories including CompleteScale (all 21 variants matching Figma layout)
  • Key font changes: headings now Montserrat Bold (not serif), display now Regular 400 (not Bold), body now Medium 500 (not Regular)

Decisions made:

  • D017: Headings use Montserrat Bold, not Noto Serif SC (supersedes D005)
  • D018: Display weight is Regular 400, not Bold
  • D019: Body weight is Medium 500 (user preference, 450 not available)
  • D020: 21 typography variants across 6 categories

Next steps:

  • User to review expanded type scale in Storybook
  • Fine-tune heading sizes if they don't match Figma exactly (h2-h6 were estimated)
  • Build next atom (Input or Card) ✓ Input done

Session 2026-03-25e — Input atom

Agent(s): Claude Opus (via conversation)

Work completed:

  • Reviewed FA 2.0 Figma Input Field design (node 39:713) — 9 states × 4 toggle properties = ~90 variants
  • Analysed Figma design and provided feedback: identified 7 improvements (leading icons, size variation, required indicator, select vs input naming, multiline, character count, error icon treatment)
  • Created Input component tokens (tokens/component/input.json): height (sm/md), paddingX, paddingY (sm/md), fontSize, borderRadius, gap, iconSize — 9 tokens total
  • Rebuilt token pipeline — 9 new input tokens generated across CSS/JS/JSON outputs
  • Updated MUI theme (src/theme/index.ts) with comprehensive MuiOutlinedInput overrides:
    • Border colours per state: neutral.300 default, neutral.400 hover, brand.500 focus, error/success for validation
    • Focus ring: double box-shadow (2px white gap + 4px brand.500) matching Figma's elevation-special/focus-ring effect
    • Error + focus ring: error-coloured ring
    • Disabled background: neutral.100
    • Two sizes via minHeight: medium (48px), small (40px)
    • Icon sizing: 20px via InputAdornment
    • Notch legend hidden for external label pattern
    • Multiline padding normalisation
  • Created Input component (src/components/atoms/Input/Input.tsx):
    • Composes FormControl + InputLabel + OutlinedInput + FormHelperText
    • External label pattern (InputLabel with position:static, no floating)
    • Custom props: label, helperText, success, startIcon, endIcon, fullWidth
    • Label stays neutral on error/focus/success (per Figma design)
    • Required asterisk on label (via MUI InputLabel)
    • Success state: green border + green helper text (not a native MUI state)
    • Error helper text has role="alert" for screen readers
    • aria-describedby connection between input and helper text
    • Supports multiline via multiline + rows/minRows/maxRows
  • Created barrel export (src/components/atoms/Input/index.ts)
  • Created comprehensive Storybook stories (11 stories): Default, FigmaMapping, AllStates, Required, Sizes, SizeAlignment, WithIcons, PasswordToggle, Multiline, ValidationFlow, ArrangementForm, CompleteMatrix
  • Logged D021-D025 in decisions log
  • Updated component registry (Input → review)
  • Storybook builds successfully

Decisions made:

  • D021: External label pattern, not MUI floating label
  • D022: Two sizes — medium 48px (matches Button large), small 40px (matches Button medium)
  • D023: Focus ring uses brand.500 warm gold (Figma spec), not brand.600
  • D024: Label stays neutral on error/success (calmer for FA audience)
  • D025: Added startIcon/endIcon convenience props and success validation state

Open questions:

  • Should error+focus ring be error-coloured or brand-coloured? Currently error-coloured (reinforces the validation state during keyboard navigation)
  • FormField molecule may now be unnecessary — Input already includes label + helper text. Consider repurposing FormField as a layout/validation wrapper instead.
  • Should we add a character count feature? (Useful for textarea fields like special instructions)

Next steps:

  • User to review Input in Storybook
  • Build next atom (Card, Badge, or Chip recommended) ✓ Card done
  • Consider whether FormField molecule is still needed given Input's built-in label/helperText

Session 2026-03-25f — Card atom

Agent(s): Claude Opus (via conversation)

Work completed:

  • Created card component tokens (tokens/component/card.json): borderRadius, padding (default 24px / compact 16px), shadow (default md / hover lg), border, background — 7 tokens total
  • Rebuilt token pipeline — 7 new card tokens generated across CSS/JS/JSON outputs
  • Updated MUI theme (src/theme/index.ts) with MuiCard overrides:
    • Root: card token border radius, background, resting shadow (shadow.md), smooth transition
    • Outlined variant: no shadow, card border colour
  • Created Card component (src/components/atoms/Card/Card.tsx):
    • Two visual variants: elevated (shadow, default) and outlined (border)
    • interactive prop: hover shadow lift (shadow.lg), pointer cursor, focus-visible outline
    • padding prop: "default" (24px), "compact" (16px), "none" (raw children for full-bleed)
    • Uses CardContent internally for padded variants; raw children when none
    • Thin wrapper pattern consistent with Button and Typography
  • Created barrel export (src/components/atoms/Card/index.ts)
  • Created 8 Storybook stories: Default, Variants, Interactive, PaddingPresets, PriceCardPreview, ServiceOptionPreview, WithImage, RichContent
  • Preflight passed all 5 checks
  • Committed and pushed to Gitea

Decisions made:

  • Card uses MUI spacing units (p: 4/6) for padding presets rather than CSS variables — consistent with MUI-first approach
  • Elevation set to 0 on MuiCard; box-shadow applied directly from card tokens for precise control
  • Interactive hover uses CSS variable (var(--fa-card-shadow-hover)) for shadow.lg
  • No new design decisions needed — Card follows existing token/design conventions from design-system.md

Open questions:

  • Should interactive cards have a subtle border-colour change on hover in addition to shadow lift?
  • Should we add a "selected" state for ServiceOption-style cards (e.g., brand border + brand.50 background)?

Next steps:

  • User to review Card in Storybook ✓ Feedback received — add selected + hover bg

Session 2026-03-25g — Card selected state + hover background

Agent(s): Claude Opus (via conversation)

Work completed:

  • Reviewed FA 1.0 Figma designs for card usage patterns:
    • ListItemPurchaseOption (2349:39505): selectable cards with 4 states × 2 viewports
    • ListItemAddItem (2350:40658): toggle/switch pattern — deferred to future Toggle component
  • Added selected prop: brand border (2px, warm gold #BA834E) + warm background (brand.50 #FEF9F5)
  • Added hover background fill: interactive cards now fill with neutral.50 on hover (matching Figma's inactive→hover pattern)
  • Hover on selected cards preserves warm background instead of switching to neutral
  • Elevated interactive cards still get shadow lift on hover; outlined ones only get bg fill
  • Added 3 new card tokens: border.selected, background.hover, background.selected
  • Added 4 new stories: Selected, OptionSelect (single-select with radio semantics), MultiSelect (checkbox toggle), OnDifferentBackgrounds (white vs grey surface)
  • Replaced ServiceOptionPreview story with the more complete OptionSelect and MultiSelect patterns
  • Preflight passed all 5 checks
  • Committed and pushed to Gitea

Decisions made:

  • Selected state uses 2px brand border (not 1.5px from Figma 1.0) — 2px aligns with our focus ring width and sits on the 2px sub-grid
  • Selected background uses brand.50 (warm tint) not neutral.50 (grey) — warm tint reinforces the brand connection and distinguishes selected from hovered
  • Hover bg fill uses neutral.50 (not brand.50) for unselected cards — keeps hover subtle and neutral
  • Toggle/switch pattern from Figma (ListItemAddItem) is a separate component concern, not Card

Next steps:

  • User to review Card selected/hover states in Storybook ✓ Approved
  • Build Badge or Chip atom next ✓ Badge done

Session 2026-03-25h — Badge atom

Agent(s): Claude Opus (via conversation)

Work completed:

  • Searched FA 2.0 and Parsons 1.0 Figma files for badge/chip/tag components — none found, designed from conventions
  • Created badge component tokens (tokens/component/badge.json): height, paddingX, fontSize, iconSize, iconGap, borderRadius for sm/md — 10 tokens total
  • Built Badge component (src/components/atoms/Badge/Badge.tsx):
    • Pill-shaped, display-only status indicator (not interactive)
    • 6 colour intents: default, brand, success, warning, error, info
    • 2 variants: soft (tonal bg + coloured text, default) and filled (solid bg + white text)
    • 2 sizes: small (22px) and medium (26px)
    • Optional leading icon prop for contextual icons
    • All soft colours use CSS variables from token system — no hardcoded hex
    • Warning text uses amber.700 for WCAG AA compliance
  • Created 10 Storybook stories including realistic compositions (InPriceCard, ServiceStatus)
  • Preflight passed all 5 checks
  • Committed and pushed to Gitea

Decisions made:

  • Badge defaults to soft variant — calmer, more appropriate for FA's sensitive context. Filled variant for high-priority emphasis only.
  • Badge uses Box (span) not MUI Chip — keeps it simple, display-only, no interactive baggage
  • Pill shape (borderRadius.full) distinguishes badges from rectangular UI elements
  • Brand soft colours match Button soft (brand.200 bg, brand.700 text) for visual consistency

Next steps:

  • User to review Badge in Storybook ✓ Approved (large size added)

Session 2026-03-25i — Impeccable integration

Agent(s): Claude Opus (via conversation)

Work completed:

  • Researched pbakaus/impeccable (Apache 2.0) — 21 skills for frontend design quality
  • Assessed fit for FA project — identified overlaps/conflicts, recommended selective integration
  • Downloaded 14 reference files to docs/reference/impeccable/:
    • 7 design guides (typography, colour, spatial, motion, interaction, responsive, ux-writing)
    • 3 critique references (cognitive-load, heuristics-scoring, personas)
    • 4 skill references (audit, critique, polish, frontend-design anti-patterns)
  • Created /audit skill — technical quality scoring (0-20) across 5 dimensions, adapted for FA
  • Created /critique skill — UX review using Nielsen's 10 heuristics (0-40), with FA-specific persona checks
  • Updated /review-component — added interactive states checklist (8 checks) and design anti-patterns checklist (8 checks)
  • Updated /preflight — added visual QA spot-check section (advisory, non-blocking)
  • All changes are skill/docs only — zero code changes to existing components

Decisions made:

  • Selective integration over wholesale install — only /audit, /critique, reference material, and anti-patterns merged
  • Removed impeccable's dependency chain (/frontend-design → /teach-impeccable) — FA already has CLAUDE.md + docs/memory/ for design context
  • Replaced impeccable's command recommendations with FA's available skills
  • Critique adapted with FA-specific personas (bereaved family member, arrangement planner)
  • OKLCH recommendation noted in reference but not adopted — FA uses hex-based DTCG tokens

Component status at end of session:

  • Done (5): Button, Typography, Input, Card, Badge
  • Planned (5 atoms): IconButton, Icon, Avatar, Divider, Chip, Link
  • Planned (5 molecules): FormField, PriceCard, ServiceOption, SearchBar, StepIndicator
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • Review Badge in Storybook (large size was added per user request)
  • Build Chip atom (interactive tags — clickable, deletable, with icon support) ✓ Done
  • Consider running /audit or /critique on completed atoms to establish baseline scores
  • Begin PriceCard molecule once Chip is done (depends on Card + Badge + Typography + Button)

Session 2026-03-25j — Chip atom

Agent(s): Claude Opus (via conversation)

Work completed:

  • Created chip component tokens (tokens/component/chip.json): height, paddingX, fontSize, iconSize, deleteIconSize, iconGap, borderRadius for sm/md — 12 tokens total
  • Rebuilt token pipeline — 12 new chip tokens generated across CSS/JS/JSON outputs
  • Updated MUI theme (src/theme/index.ts) with MuiChip overrides:
    • Pill-shaped borderRadius from token
    • Two sizes: small (28px), medium (32px)
    • Filled variant: neutral.200 bg for default, brand.200 bg for primary (soft/tonal, matching Badge and Button soft)
    • Outlined variant: neutral.300 border for default, brand.400 border for primary
    • Hover states per variant × colour
    • Delete icon hover colour change
    • Focus-visible outline (brand.500, 2px offset)
  • Created Chip component (src/components/atoms/Chip/Chip.tsx):
    • Wraps MUI Chip with React.forwardRef
    • Custom selected prop: promotes colour to primary, outlined selected gets brand border + warm bg
    • Two variants: filled (tonal, default), outlined (border)
    • Two colours: default (neutral), primary (brand)
    • Interactive modes: clickable (via onClick), deletable (via onDelete), both, or static
    • All MUI ChipProps passed through
  • Created barrel export (src/components/atoms/Chip/index.ts)
  • Created 10 Storybook stories: Default, Variants, Sizes, WithIcons, Clickable, Deletable, Selected, FilterChips (interactive toggle demo), RemovableTags (interactive dismiss demo), InServiceOption (realistic card composition), CompleteMatrix
  • Preflight passed all 5 checks

Decisions made:

  • Chip uses MUI Chip wrapper (unlike Badge which uses raw Box) — MUI Chip provides built-in keyboard navigation, delete icon, and click handling that would be complex to reimplement
  • Chip defaults to filled variant with soft/tonal colours (matching Badge soft and Button soft patterns) — NOT MUI's default opaque fill
  • Only default and primary colours initially — secondary/error/etc. added when needed (YAGNI)
  • Selected state auto-promotes to primary colour unless colour is explicitly set — mirrors Card's selected brand treatment
  • No new design decision IDs needed — Chip follows established conventions

Component status at end of session:

  • Done (5): Button, Typography, Input, Card, Badge
  • Review (1): Chip
  • Planned (4 atoms): IconButton, Icon, Avatar, Divider, Link
  • Planned (5 molecules): FormField, PriceCard, ServiceOption, SearchBar, StepIndicator
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • User to review Chip in Storybook ✓ Approved
  • Consider running /audit or /critique on completed atoms to establish baseline scores ✓ Done
  • Begin PriceCard molecule (depends on Card + Badge + Typography + Button + Chip)

Session 2026-03-25k — Audit, P1 fixes, Switch + Radio atoms

Agent(s): Claude Opus (via conversation)

Work completed:

  • Ran /audit on all 5 completed atoms (Button, Typography, Input, Card, Badge)
    • Average score: 18/20 (Excellent)
    • 2 P1 issues identified and fixed, 7 P2s documented, 5 P3s noted
  • Fixed P1: Button loading state now announces to screen readers (aria-busy + visually-hidden text)
  • Fixed P1: Card interactive now has tabIndex={0} and role="button" for keyboard operability
  • Fixed P2: Card Record<string, any> → Theme type for type safety
  • Reviewed Parsons 1.0 Figma "Toggles" board (node 2322:42538) — identified 4 new atoms: Switch, Radio, ColourToggle, Slider
  • Added all 4 to component registry (ColourToggle and Slider deferred)
  • Created switch component tokens (tokens/component/switch.json): track width/height/borderRadius, thumb size — 4 tokens
  • Created radio component tokens (tokens/component/radio.json): size, dotSize — 2 tokens
  • Updated MUI theme with MuiSwitch overrides: bordered pill track, brand.500 active fill, focus-visible ring
  • Updated MUI theme with MuiRadio overrides: neutral.400 unchecked, brand.500 checked, hover states
  • Created Switch component — thin MUI wrapper with forwardRef
  • Created Radio component — thin MUI wrapper with forwardRef
  • Created Switch stories (4): Default, States, ServiceAddOns (interactive add-on toggle demo), WithLabels
  • Created Radio stories (5): Default, States, RadioGroup, CardSelection (interactive card + radio demo), PaymentMethod
  • Preflight passed all 5 checks

Decisions made:

  • Switch implements Figma "Style One" (bordered pill) only — other styles deferred as variants if needed
  • Switch/Radio are ultra-thin wrappers — all styling via MUI theme overrides, no component-level sx
  • ColourToggle and Slider deferred until their consuming organisms are built

Component status at end of session:

  • Done (5): Button, Typography, Input, Card, Badge
  • Review (3): Chip, Switch, Radio
  • Planned (6 atoms): IconButton, Icon, Avatar, Divider, ColourToggle, Slider, Link
  • Planned (5 molecules): FormField, PriceCard, ServiceOption, SearchBar, StepIndicator
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • User to review Switch and Radio in Storybook ✓ Approved
  • Begin PriceCard molecule ✓ Replaced with ProviderCard (see below)
  • Address P2 audit issues in a future cleanup pass

Session 2026-03-25l — ProviderCard molecule (first molecule)

Agent(s): Claude Opus (via conversation)

Work completed:

  • Reviewed 3 Figma designs: Provider Cards (5503:44422), Service Venue (2997:83018), Map Pin Card (5369:140263)
  • Captured business context: verified vs unverified providers, Parsons partner strategy, map + list layout
  • Replaced generic "PriceCard" in registry with 3 specific molecules: ProviderCard, VenueCard, MapCard
  • Saved business context to auto-memory (project_listing_cards.md)
  • Created plan via /plan mode — component API, card structure, token plan, story plan
  • Created providerCard component tokens (tokens/component/providerCard.json): image.height, logo.size, footer.background/paddingX/paddingY, content.padding/gap — 7 tokens
  • Built ProviderCard molecule (src/components/molecules/ProviderCard/ProviderCard.tsx):
    • Composes Card (interactive, padding="none") + Badge + Typography
    • Verified variant: hero image (CSS bg-image cover), logo overlay (48px circle, absolute positioned, overlaps content), "Trusted Partner" badge (filled brand), capability badge
    • Unverified variant: text-only, same content area + footer
    • Footer bar: warm brand.100 bg, "Packages from $X" + ChevronRight
    • Accessibility: aria-label on reviews, aria-hidden on decorative icons, alt text on logo
    • All values from token CSS variables, no hardcoded hex
  • Created 9 Storybook stories: Default, VerifiedProvider, UnverifiedProvider, ListLayout (mixed), CapabilityVariants, EdgeCases, Responsive, OnDifferentBackgrounds, InteractiveDemo
  • Preflight passed all 5 checks
  • Logged D026-D030 in decisions log

Decisions made:

  • D026: Molecules compose atoms via sx — no MUI theme overrides
  • D027: Image as URL string (CSS bg-image), logo as URL string ()
  • D028: Logo 48px (not 75px Figma) for card width proportion
  • D029: Footer built in via startingPrice prop, not a slot
  • D030: verified is explicit boolean, not derived from imageUrl

Component status at end of session:

  • Done (7): Button, Typography, Input, Card, Badge, Chip, Switch, Radio
  • Review (1 molecule): ProviderCard
  • Planned (7 atoms): IconButton, Icon, Avatar, Divider, ColourToggle, Slider, Link
  • Planned (5 molecules): VenueCard, MapCard, ServiceOption, SearchBar, StepIndicator, FormField
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • User to review ProviderCard in Storybook ✓ Feedback received, iterated in session 25m

Session 2026-03-25m — ProviderCard v2 refinements from user feedback

Agent(s): Claude Opus (via conversation)

Work completed:

  • Iterated on ProviderCard based on 5 feedback items from user review
  • Logo: circle → 64px rounded rectangle (8px radius, borderRadius.md). Positioned fully inside image area (absolute, bottom-left) with white border + shadow. Eliminates dead space — name sits directly below image.
  • Footer removed: "View packages >" bar was redundant (whole card is clickable, price already in content). Removed 3 footer tokens (footer.background, .paddingX, .paddingY).
  • Price typography: Split into "Packages from" (body2, 14px, secondary) + price (h6, 16px, weight 500, primary). Lighter, streamlined ecommerce feel vs old blocky labelLg/700.
  • Verified badge: Bumped from size="small" to size="medium" for visibility.
  • Capability badge: Bumped to size="medium". Added trailing InfoOutlinedIcon and new capabilityDescription prop — wraps badge in MUI Tooltip on hover/focus for plain-language definitions of industry jargon.
  • Unverified card differentiation: 3px borderTop (neutral.200) as visual anchor. ListLayout story now on neutral.50 background.
  • Caption weight fix (system-wide): Caption and CaptionSm bumped from fontWeight 400 (Regular) → 500 (Medium) in semantic typography tokens. Aligns with D019 — user found Regular too light for Montserrat.
  • Meta row: Location/reviews dropped from body2 (14px) → caption (12px) with 14px icons for clearer tertiary hierarchy.
  • Updated all stories with capabilityDescription tooltips for 3 capability types
  • Preflight passed all 5 checks

Decisions made:

  • Logo positioned fully inside image (no overlap into content) — tried flex-row overlap approach first but it "dug into" the photo and pushed the name sideways
  • Footer removal: card's interactive hover + price in content are sufficient affordance
  • Caption weight 500: extends D019 (body weight = Medium) to all Montserrat text variants. Only display (Noto Serif SC) stays at 400 per D018.
  • Info icon for capability badges: trailing position (after label), cursor: help when tooltip active

Token changes:

  • providerCard.logo.size: 56px → 64px
  • providerCard.logo.borderRadius: new, → {borderRadius.md} (8px)
  • providerCard.footer.*: 3 tokens removed (footer eliminated)
  • typography.caption.fontWeight: {fontWeight.regular}{fontWeight.medium}
  • typography.captionSm.fontWeight: {fontWeight.regular}{fontWeight.medium}

Component status at end of session:

  • Done (8): Button, Typography, Input, Card, Badge, Chip, Switch, Radio
  • Review (1 molecule): ProviderCard (v2, user approved direction)
  • Planned (6 atoms): IconButton, Icon, Avatar, Divider, ColourToggle, Slider, Link
  • Planned (5 molecules): VenueCard, MapCard, ServiceOption, SearchBar, StepIndicator, FormField
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • Build VenueCard molecule ✓ Done
  • Address P2 audit issues ✓ Done
  • Audit ProviderCard v2 ✓ Done (17/20, P2s fixed)

Session 2026-03-25n — VenueCard molecule, P2 fixes, ProviderCard audit

Agent(s): Claude Opus (via conversation)

Work completed:

  • Reviewed Figma venue card design (node 2997:83018) — photo + name + location + capacity + price
  • Created venueCard component tokens (tokens/component/venueCard.json): image.height (180px), content.padding (spacing.3), content.gap (spacing.1) — 3 tokens
  • Built VenueCard molecule (src/components/molecules/VenueCard/VenueCard.tsx):
    • Composes Card (interactive, padding="none") + Typography
    • Hero image with role="img" + aria-label for screen readers
    • Meta row: location (pin icon) + capacity with "guests" suffix for clarity
    • Price with "From" qualifier (split typography like ProviderCard)
    • No verification tiers, no logo, no badges — simpler than ProviderCard
  • Created 6 Storybook stories: Default, ListLayout, EdgeCases, Responsive, OnDifferentBackgrounds, InteractiveDemo
  • Ran /critique on VenueCard: 33/40 (Good). Applied P2 fixes before commit:
    • Capacity: bare number → "X guests" for visible context
    • Price: bare "$900" → "From $900" for transparency
    • Image: added role="img" + aria-label for screen readers
  • Fixed 6 P2 audit issues across atom components:
    • Input: Record<string, any>Theme type on boxShadow accessor
    • Button: documented aria-label requirement for icon-only usage
    • Badge: documented aria-label for icon-only badges
    • Switch: strengthened a11y docs with FormControlLabel example
    • Radio: strengthened a11y docs with RadioGroup + FormControlLabel example
    • Chip: documented aria-label for icon-only deletable chips
  • Ran /audit on ProviderCard v2: 17/20 (Good). Fixed 3 P2s:
    • Hero image: added role="img" + aria-label for screen readers
    • Logo shadow: hardcoded rgba → var(--fa-shadow-sm)
    • Logo border: hardcoded white → var(--fa-color-white)

Decisions made:

  • VenueCard follows same token structure as ProviderCard (image.height, content.padding, content.gap) for visual consistency in list views
  • Capacity shows "X guests" suffix — bare number was confusing in critique
  • Price shows "From $X" — matches ProviderCard's "Packages from" pattern for transparency

Component status at end of session:

  • Done (8): Button, Typography, Input, Card, Badge, Chip, Switch, Radio
  • Review (2 molecules): ProviderCard (v2, audit 17/20), VenueCard (critique 33/40)
  • Planned (6 atoms): IconButton, Icon, Avatar, Divider, ColourToggle, Slider, Link
  • Planned (4 molecules): MapCard, ServiceOption, SearchBar, StepIndicator, FormField
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • User to review VenueCard in Storybook ✓ Approved
  • Build next atoms (IconButton, Divider, Link) ✓ Done

Agent(s): Claude Opus (via conversation)

Work completed:

  • Built IconButton atom — wraps MUI IconButton with FA theme overrides:
    • 3 sizes reusing Button height tokens (sm 32px, md 40px, lg 48px)
    • Rounded rect shape (borderRadius.md), brand hover colours, focus ring
    • 4 colour options: default, primary, secondary, error
    • 5 stories including CommonUseCases (card toolbar, dialog close, nav toggle)
  • Built Divider atom — wraps MUI Divider with FA border token:
    • Horizontal/vertical orientation, fullWidth/inset/middle variants
    • Text children support (MUI built-in)
    • 6 stories including InContent and NavigationList patterns
  • Built Link atom — wraps MUI Link with FA brand tokens:
    • Copper colour (brand.600, 4.8:1 contrast) by default
    • Underline on hover, focus-visible ring, fontWeight 500
    • 7 stories including Inline (body text), Navigation, FooterLinks
  • Added MuiIconButton, MuiDivider, MuiLink overrides to theme

Decisions made:

  • IconButton uses rounded rect (borderRadius.md) not circle — consistent with Button. Circle can be achieved with sx if needed.
  • Link defaults to underline="hover" — always-underlined links feel heavy in FA's clean aesthetic, but the underline is important for discoverability so it appears on hover.
  • No new component tokens — IconButton reuses Button tokens, Divider uses palette.divider, Link uses palette colours.

Component status at end of session:

  • Done (8): Button, Typography, Input, Card, Badge, Chip, Switch, Radio
  • Review (3 atoms): IconButton, Divider, Link
  • Review (2 molecules): ProviderCard (v2, audit 17/20), VenueCard (critique 33/40)
  • Planned (3 atoms): Icon, Avatar, ColourToggle, Slider
  • Planned (4 molecules): MapCard, ServiceOption, SearchBar, StepIndicator, FormField
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • User to review IconButton, Divider, Link in Storybook ✓ Approved
  • Build ServiceOption molecule ✓ Done

Session 2026-03-25n (continued) — ServiceOption molecule

Agent(s): Claude Opus (via conversation)

Work completed:

  • Reviewed 2 Figma components: ListItemPurchaseOption (2349:39505) and ListItemAddItem (2350:40658)
    • ListItemPurchaseOption: click-to-select card with 4 states (inactive, hover, active, active hover)
    • ListItemAddItem: toggle with Switch — deferred as a future AddOnOption molecule
  • Built ServiceOption molecule (src/components/molecules/ServiceOption/ServiceOption.tsx):
    • Composes Card (interactive, selected) + Typography
    • Heading row: name (h6) + optional price (h6, brand colour, right-aligned, nowrap)
    • Optional description below (body2, text.secondary)
    • Selected state via Card's built-in brand border + warm bg
    • Disabled state with opacity token (--fa-opacity-disabled) + pointer-events: none
    • role="radio" + aria-checked for proper single-select group semantics
    • Uses card.padding.compact (16px) for content padding
  • Created 7 stories: Default, Selected, ServiceTypeSelection (interactive radiogroup), CoffinSelection (interactive 4-option), WithoutPrice, Disabled, EdgeCases
  • No new tokens — ServiceOption reuses Card tokens (padding.compact, border.selected, etc.)

Decisions made:

  • ServiceOption uses role="radio" + aria-checked — correct for single-select groups within a radiogroup. Parent wraps in role="radiogroup".
  • Price right-aligned in heading row — natural scanning pattern (name on left, cost on right, like a menu)
  • No component-specific tokens needed — Card's existing tokens handle all visual states
  • AddOnOption (ListItemAddItem with Switch) deferred — will compose Card + Switch when arrangement form organisms are built

Component status at end of session:

  • Done (8): Button, Typography, Input, Card, Badge, Chip, Switch, Radio
  • Review (3 atoms): IconButton, Divider, Link
  • Review (3 molecules): ProviderCard, VenueCard, ServiceOption
  • Planned (3 atoms): Icon, Avatar, ColourToggle, Slider
  • Planned (3 molecules): MapCard, SearchBar, StepIndicator, FormField
  • Planned (5 organisms): ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer

Next steps:

  • Build SearchBar molecule ✓ Done
  • Build AddOnOption molecule ✓ Done
  • Build StepIndicator molecule ✓ Done
  • Build Navigation organism ✓ Done

Session 2026-03-25o — SearchBar, AddOnOption, StepIndicator molecules + Navigation organism

Agent(s): Claude Opus (via conversation)

Work completed:

  • Built SearchBar molecule (src/components/molecules/SearchBar/):
    • Composes Input (with search icon) + optional Button for provider/venue search
    • Enter-to-submit, progressive clear button (appears when text present), inline loading spinner
    • Guards empty submissions (value.trim()), refocuses input after clear
    • role="search" landmark, two sizes aligned with Input/Button
    • Critique: 35/40 (Good). P2 fixes applied before commit.
    • 8 stories: Default, WithButton, SmallSize, WithPreloadedValue, Loading, Disabled, ProviderSearch, VenueSearch
  • Built AddOnOption molecule (src/components/molecules/AddOnOption/):
    • Composes Card (interactive, selected) + Typography + Switch
    • Maps to Figma ListItemAddItem (2350:40658) — toggle for optional extras
    • Heading + optional price + description + Switch right-aligned
    • Click anywhere on card toggles the switch (stopPropagation on switch itself)
    • aria-labelledby connects switch to heading text
    • 7 stories: Default, Checked, ServiceAddOns (interactive list with running total), WithoutPrice, WithoutDescription, Disabled, EdgeCases
  • Built StepIndicator molecule (src/components/molecules/StepIndicator/):
    • Maps to Figma Progress Bar - Steps (2375:47468) — horizontal segmented bar
    • Brand gold for completed/current steps, grey (divider) for upcoming
    • Responsive bar height (10px desktop, 6px mobile), responsive labels
    • Current step label bolded, role="navigation" + aria-current="step"
    • 7 stories: Default, AllStates, TwoSteps, ManySteps, Interactive (nav demo), Completed, NarrowContainer
  • Built Navigation organism (src/components/organisms/Navigation/):
    • First organism in the design system
    • Maps to Figma Main Nav (14:108) + Mobile Header (2391:41508)
    • Desktop: sticky AppBar, logo left, nav Link items right, optional CTA Button
    • Mobile: hamburger IconButton + Drawer with nav list, CTA, Divider, help footer with phone
    • Warm surface background (brand.50), border bottom
    • Composes AppBar, Link, IconButton, Button, Divider, Drawer, Typography
    • 6 stories: Default, WithCTA, WithPageContent (sticky scroll demo), Minimal, ExtendedNavigation, MobilePriceTracker
  • All 4 components: TypeScript compiles, Storybook builds, committed and pushed

Decisions made:

  • SearchBar guards empty submissions and disables button when empty — prevents wasted requests
  • AddOnOption uses click-anywhere-to-toggle pattern (stopPropagation on Switch to avoid double-toggle)
  • StepIndicator uses palette.divider for incomplete steps — grey/sage from theme, not hardcoded
  • Navigation uses var(--fa-color-surface-warm) background — matches Figma's warm grey #F4F3EF
  • Navigation nav link colour uses brand.900 (#51301B) — matches Figma "Brown Two" token
  • No new component tokens needed for any of the 4 components — all reuse existing tokens

Component status at end of session:

  • Done (8): Button, Typography, Input, Card, Badge, Chip, Switch, Radio
  • Review (3 atoms): IconButton, Divider, Link
  • Review (6 molecules): ProviderCard, VenueCard, ServiceOption, SearchBar, AddOnOption, StepIndicator
  • Review (1 organism): Navigation
  • Planned (3 atoms): Icon, Avatar, ColourToggle, Slider
  • Planned (2 molecules): MapCard, FormField
  • Planned (4 organisms): ServiceSelector, PricingTable, ArrangementForm, Footer

Post-review fixes (same session):

  • SearchBar: button height aligned via explicit CSS var height, icon-to-text gap tightened (adornment mr: 0.5), focus ring gap increased (gap 6px → 10px)
  • AddOnOption: price moved to own row below heading, heading row centre-aligned so short headings (no description) align with switch, heading-to-price margin removed
  • AddOnOption + ServiceOption: added optional maxDescriptionLines prop with CSS line-clamp + "View more"/"View less" toggle (caption size, text.secondary, weight 400). Omit prop for no limit.

Next steps:

  • Build Footer organism (next)
  • Build ServiceSelector organism (next)
  • Consider FormField molecule (next)
  • Remaining P3s (next)

Session 2026-03-25p — Review completion + Navigation fixes

Agent(s): Claude Opus (via conversation)

Work completed:

  • Completed review of all components — user approved all atoms + molecules with no changes
  • Applied 4 Navigation fixes from user feedback:
    1. Added "Provider Portal" to default nav items
    2. Integrated real FA logo SVGs from brandassets/brandlogo/ (full wordmark desktop, short icon mobile)
    3. Changed nav background from warm (surface.warm / brand.50) to grey (surface.subtle / neutral.50)
    4. Removed mobileTrailing prop and MobilePriceTracker story — speculative feature not in design
  • Added staticDirs: ['../brandassets'] to Storybook config for logo serving
  • Updated component-registry.md: promoted 11 atoms + 6 molecules + 1 organism from "review" to "done"
  • TypeScript compiles, Storybook builds

Decisions made:

  • Nav background is grey (neutral.50) not warm (brand.50) — per user's Figma reference
  • "Log in" label kept as-is — universally understood, user confirmed
  • mobileTrailing prop removed entirely — was over-reading Figma's mobile header

Component status at end of session:

  • Done (11 atoms): Button, Typography, Input, Card, Badge, Chip, Switch, Radio, IconButton, Divider, Link
  • Done (6 molecules): ProviderCard, VenueCard, ServiceOption, SearchBar, AddOnOption, StepIndicator
  • Done (1 organism): Navigation
  • Planned (3 atoms): Icon, Avatar, ColourToggle, Slider
  • Planned (2 molecules): MapCard, FormField
  • Planned (4 organisms): ServiceSelector, PricingTable, ArrangementForm, Footer

Next steps:

  • Build Footer organism ✓ Done
  • Build ServiceSelector organism ✓ Done
  • Consider FormField molecule if Input's built-in label/helperText proves insufficient
  • Remaining P3s: InfoOutlinedIcon sizing in ProviderCard, image loading placeholder, accent bar 3px→4px

Agent(s): Claude Opus (via conversation)

Work completed:

  • Built Footer organism (src/components/organisms/Footer/):
    • Dark espresso (brand.950) surface with inverse white text
    • Logo + tagline + contact info (phone/email with tel:/mailto: links) in left column
    • Configurable link group columns with heading + <ul> list
    • Bottom legal bar: copyright + legal links (Privacy, Terms, Accessibility)
    • Semantic HTML: <footer>, <nav aria-label> per link group, <ul> for link lists
    • Responsive: stacks to single column on mobile, side-by-side on desktop
    • 5 stories: Default, Minimal, WithContactOnly, TwoColumns, FullPage (Nav + content + Footer)
    • Critique: 38/40 (Excellent). P2 fixes applied: legal links bumped from 11px → 12px, nav landmarks added
  • Built ServiceSelector organism (src/components/organisms/ServiceSelector/):
    • Single-select panel composing Typography + ServiceOption × n + Button
    • Heading + optional subheading + radiogroup of ServiceOption cards + optional continue button
    • Continue button auto-disables when nothing selected (overridable via continueDisabled)
    • maxDescriptionLines pass-through to ServiceOption for truncation
    • 7 stories: Default, PreSelected, Interactive, CoffinSelection, WithTruncatedDescriptions, WithoutContinue, WithDisabledOptions, InArrangementFlow (with StepIndicator)
  • No new tokens needed — both organisms reuse existing token system
  • TypeScript compiles, Storybook builds

Decisions made:

  • Footer uses brand.950 (espresso) background — darkest brand tone for maximum contrast with white text, warm but professional
  • Footer link groups get individual <nav aria-label> landmarks — better screen reader navigation
  • ServiceSelector is a controlled component: parent manages selectedId + onSelect. Keeps state lifting simple for arrangement flow.
  • Continue button defaults to disabled when nothing selected — prevents empty submissions without explicit error messages

Component status at end of session:

  • Done (11 atoms): Button, Typography, Input, Card, Badge, Chip, Switch, Radio, IconButton, Divider, Link
  • Done (6 molecules): ProviderCard, VenueCard, ServiceOption, SearchBar, AddOnOption, StepIndicator
  • Done (1 organism): Navigation
  • Review (2 organisms): Footer (critique 38/40), ServiceSelector
  • Planned (3 atoms): Icon, Avatar, ColourToggle, Slider
  • Planned (2 molecules): MapCard, FormField
  • Planned (2 organisms): PricingTable, ArrangementForm

Next steps:

  • User to review Footer + ServiceSelector ✓ Approved
  • Build ArrangementForm Removed — premature, need more building blocks
  • Build Package Select page components ✓ Done

Session 2026-03-26a — Reviews, Navigation fixes, Package Select page components

Agent(s): Claude Opus (via conversation)

Work completed:

  • Completed review of all 10 "review" components — all approved to done
  • Navigation fixes from user feedback:
    • Added "Provider Portal" to nav items
    • Integrated real FA logo SVGs from brandassets/brandlogo/
    • Changed nav background from warm (brand.50) → grey (neutral.50 / surface.subtle)
    • Removed mobileTrailing prop and MobilePriceTracker story (speculative)
    • Added staticDirs to Storybook for brand asset serving
  • Built Footer organism (critique 38/40):
    • Dark espresso bg, logo + tagline + contact + link columns + legal bar
    • P2 fixes: extracted overline sx, used overlineSm variant, bumped legal links to 12px
  • Built ServiceSelector organism:
    • Single-select panel with radiogroup, continue button auto-disables
    • WithLineLimit story for description truncation
  • Built and removed ArrangementForm organism (premature — user flagged)
  • Analysed Package Select page from Figma (5405:181955):
    • Identified gaps: LineItem, ProviderCardCompact, PackageDetail
    • Recommended Chip filter bar for funeral type switching
  • Built LineItem molecule (audit 19/20):
    • Name + info tooltip + optional price, allowance asterisk, total variant
    • Font weight 500 (D019), prices text.secondary for readability hierarchy
    • aria-label on info icon for screen readers
  • Built ProviderCardCompact molecule:
    • Horizontal layout: image left, name + location + rating right
  • Built PackageDetail organism (audit 19/20):
    • Warm header band with "Package" overline, name, price in brand colour
    • sections (before total) + total + extras (after total with subtext)
    • compareLoading prop for Compare button spinner
    • T&C grey footer, responsive button stacking
    • Section headings h6 (16px/600) vs LineItem body2 (14px/500) for hierarchy
    • Full PackageSelectPage story with filter chips, ServiceOption list, sticky detail
  • Multiple audit + review iterations with user feedback applied

Decisions made:

  • Navigation background is grey (surface.subtle), not warm — per user
  • "Make Arrangement" is the FA term for selecting/committing to a package
  • PackageDetail structure: sections → total → extras. Total separates included content from additional-cost items. Business-critical distinction.
  • LineItem prices use text.secondary — name reads first, price supports. Total row stays prominent.
  • Chip filter bar for funeral type switching — visible, discoverable, matches existing Chip component
  • Always audit before presenting to user — saved as feedback memory

Component status at end of session:

  • Done (11 atoms): Button, Typography, Input, Card, Badge, Chip, Switch, Radio, IconButton, Divider, Link
  • Done (10 molecules): ProviderCard, VenueCard, ServiceOption, SearchBar, AddOnOption, StepIndicator, LineItem, ProviderCardCompact
  • Done (4 organisms): Navigation, Footer, ServiceSelector, PackageDetail
  • Planned (3 atoms): Icon, Avatar, ColourToggle, Slider
  • Planned (2 molecules): MapCard, FormField
  • Planned (2 organisms): PricingTable, ArrangementForm

Next steps:

  • Review next key page (Package Select) ✓ Done
  • Build homepage FuneralFinder organism ✓ Done (v2 — conversational redesign)

Session 2026-03-26b — FuneralFinder organism + further PackageDetail refinements

Agent(s): Claude Opus (via conversation)

Work completed:

  • PackageDetail review refinements from user feedback:
    • Section headings bumped from label (14px) to h6 (16px/600) — now stand out against line items
    • Added Divider + subtext before Extras ("These items can be added at additional cost")
    • T&C line height reduced 1.5 → 1.3
    • Item spacing increased 12px → 16px
    • Warm header band (surface.warm) with "Package" overline, name, price in brand colour
    • Compare button loading state (compareLoading prop)
    • Complimentary items now correctly shown before total
    • Total row padding balanced (top matched to bottom)
    • Audit: 19/20 (Excellent)
  • Built FuneralFinder organism — homepage hero search widget:
    • v1: Literal translation of marketing reference — numbered steps, uppercase overlines, cramped options. User feedback: "looks like a government form, not gentle guidance"
    • v2 (current): Complete conversational redesign:
      • Warm questions: "How can we help you today?" not "I'M HERE TO"
      • ChoiceCards: generous padding, descriptions, check icon on selection
      • TypePills: pill-shaped buttons for dynamic funeral type list
      • CompletedRow: "I'm here to Arrange a funeral now · Change"
      • One question at a time — true progressive disclosure
      • CTA only appears at location step — no disabled button staring at you
      • No step numbers or badges
    • Flow: Intent → Planning For (conditional) → Funeral Type → Location → CTA
    • Audit: 17/20 (Good). P1/P2 fixes applied: aria-labels, radiogroup semantics, edit affordance
    • 5 stories: Default, FewerTypes, CustomHeading, InHeroDesktop, InHeroMobile

Decisions made:

  • "Make Arrangement" is FA's term for selecting/committing to a package
  • PackageDetail structure: sections → total → extras (business-critical distinction)
  • LineItem prices use text.secondary for readability hierarchy
  • FuneralFinder uses conversational approach, not procedural/form-like
  • Funeral types are prop-driven (dynamic from API)
  • Pre-plan "for someone else" affects the arrangement journey
  • Location needs a reusable Autocomplete atom (future work)
  • "Find funeral directors" is the CTA text (not "Find providers")

Component status at end of session:

  • Done (11 atoms): Button, Typography, Input, Card, Badge, Chip, Switch, Radio, IconButton, Divider, Link
  • Done (10 molecules): ProviderCard, VenueCard, ServiceOption, SearchBar, AddOnOption, StepIndicator, LineItem, ProviderCardCompact
  • Done (4 organisms): Navigation, Footer, ServiceSelector, PackageDetail
  • Review (1 organism): FuneralFinder (v2 conversational — user wants further changes)
  • Planned (3 atoms): Icon, Avatar, ColourToggle, Slider
  • Planned (2 molecules): MapCard, FormField, Autocomplete
  • Planned (2 organisms): PricingTable, ArrangementForm

Next steps:

  • User to continue refining FuneralFinder — further UX changes planned
  • Homepage redesign — FuneralFinder is one organism on the page, full homepage composition next
  • Build Autocomplete atom for location search (reusable pattern for other areas)
  • P3 cleanup: inverse logo SVG, InfoOutlinedIcon sizing in ProviderCard, image placeholder, accent bar 3px→4px