64 KiB
Session log
This file tracks work completed across Claude Code sessions. Every agent MUST read this file before starting work and update it after completing work.
Format
Each entry follows this structure:
### Session [date] — [brief description]
**Agent(s):** [which agents were active]
**Work completed:**
- [bullet points of what was done]
**Decisions made:**
- [any design/architecture decisions with brief rationale]
**Open questions:**
- [anything unresolved that needs human input]
**Next steps:**
- [what should happen next]
Sessions
Session 2026-03-26e — FuneralFinder v2 polish + consistency fixes
Agent(s): Claude Opus 4.6 (1M context)
Work completed:
- Fixed location input styling to match select fields (border color, hover, disabled, error states)
- Added
activeprop to StepCircle — step 1 uses brand-500 primary fill by default - Aligned Input with full selectSx overrides (bgcolor, disabled opacity+dashed, error border)
- Investigated systemic Input vs Select visual differences — confirmed issue is component-local overrides, not theme
Decisions made:
- Custom field styling kept within FuneralFinderV2 (intentional divergence from theme for this component's design)
- Step 1 circle uses primary fill since it's always active — visual "start here" signal
Next steps:
- v2 is feature-complete and polished — ready for user review in Storybook
- Decision pending: v1 vs v2 for production
- If v2 chosen: add location autocomplete, write flow logic reference doc
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.jsonwith 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.mdformat with YAML frontmatter - Fixed critical Style Dictionary v4 config: converted from CommonJS to ESM (
StyleDictionaryclass API) - Changed
build:tokensscript fromstyle-dictionary build --config ...tonode style-dictionary/config.js - Added
"type": "module"to package.json for ESM support - Changed SD output from
tokens.tstotokens.js(Style Dictionary v4 generates JS, not TS) - Registered
@storybook/addon-designsin.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.shto check for.storybook/dir instead ofnode_modules/@storybook - Verified
npm run build:tokensruns successfully (empty output expected — no tokens yet) - Verified Storybook runs at http://localhost:6006
Decisions made:
- Skills use
.claude/skills/<name>/SKILL.mdformat (not.claude/commands/) - Style Dictionary v4 config is a standalone ESM script run via
node, not CLI - British spelling for filenames (
colours.json), standardcolornamespace for token paths
Open questions:
- Slash commands
/create-tokensetc. 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 workingBegin Step 1:✓ Done/create-tokenswith brand colours, fonts, and reference material
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: trueflag (required for DTCG format CSS generation) - Generated outputs:
- CSS: 245 custom properties in
src/theme/generated/tokens.csswithvar()references for semantic tokens - JS: 258 named exports in
src/theme/generated/tokens.js - JSON: flat export in
tokens/export/tokens-flat.json
- CSS: 245 custom properties in
- 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: truedefault prop - Custom
xssize 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 optionalunderlineprop, 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-materialover 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
softvariant 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 baselineBuild Typography atom✓ DoneAdd 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.htmlandindex.html - Created Typography component (
src/components/atoms/Typography/Typography.tsx):- Thin wrapper around MUI Typography with React.forwardRef
- Custom prop:
maxLinesfor 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-describedbyconnection 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)
interactiveprop: hover shadow lift (shadow.lg), pointer cursor, focus-visible outlinepaddingprop: "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
selectedprop: 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✓ ApprovedBuild 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
iconprop 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
/auditskill — technical quality scoring (0-20) across 5 dimensions, adapted for FA - Created
/critiqueskill — 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
selectedprop: 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
filledvariant with soft/tonal colours (matching Badge soft and Button soft patterns) — NOT MUI's default opaque fill - Only
defaultandprimarycolours 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✓ ApprovedConsider 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✓ ApprovedBegin 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"tosize="medium"for visibility. - Capability badge: Bumped to
size="medium". Added trailingInfoOutlinedIconand newcapabilityDescriptionprop — 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
capabilityDescriptiontooltips 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: helpwhen tooltip active
Token changes:
providerCard.logo.size: 56px → 64pxproviderCard.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✓ DoneAddress P2 audit issues✓ DoneAudit 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-labelfor screen readers
- Fixed 6 P2 audit issues across atom components:
- Input:
Record<string, any>→Themetype 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
- Input:
- Ran /audit on ProviderCard v2: 17/20 (Good). Fixed 3 P2s:
- Hero image: added
role="img"+aria-labelfor screen readers - Logo shadow: hardcoded rgba →
var(--fa-shadow-sm) - Logo border: hardcoded white →
var(--fa-color-white)
- Hero image: added
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✓ ApprovedBuild next atoms (IconButton, Divider, Link)✓ Done
Session 2026-03-25n (continued) — IconButton, Divider, Link atoms
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✓ ApprovedBuild 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✓ DoneBuild AddOnOption molecule✓ DoneBuild StepIndicator molecule✓ DoneBuild 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-labelledbyconnects 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.dividerfor 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
maxDescriptionLinesprop 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:
- Added "Provider Portal" to default nav items
- Integrated real FA logo SVGs from
brandassets/brandlogo/(full wordmark desktop, short icon mobile) - Changed nav background from warm (
surface.warm/ brand.50) to grey (surface.subtle/ neutral.50) - Removed
mobileTrailingprop andMobilePriceTrackerstory — 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✓ DoneBuild 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
Session 2026-03-25p (continued) — Footer + ServiceSelector organisms
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) maxDescriptionLinespass-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✓ ApprovedBuild ArrangementFormRemoved — premature, need more building blocksBuild 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
mobileTrailingprop and MobilePriceTracker story (speculative) - Added
staticDirsto 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)✓ DoneBuild 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