Initial commit: FA 2.0 Design System foundation

Token pipeline (Style Dictionary v4, DTCG format):
- Primitive tokens: colour palettes (brand, sage, neutral, feedback),
  typography (3 font families, 21-variant type scale), spacing (4px grid),
  border radius, shadows, opacity
- Semantic tokens: text, surface, border, interactive, feedback colours;
  typography roles; layout spacing
- Component tokens: Button (4 sizes), Input (2 sizes)
- Generated outputs: CSS custom properties, JS ES6 module, flat JSON

Atoms (3 components):
- Button: contained/soft/outlined/text × primary/secondary, 4 sizes,
  loading state, underline for text variant
- Typography: 21 variants across display/heading/body/label/caption/overline,
  maxLines truncation
- Input: external label, helper text, error/success validation,
  start/end icons, required indicator, 2 sizes, multiline support

Infrastructure:
- MUI v5 theme with full token mapping
- Storybook 8 with autodocs
- Claude Code agents and skills for token/component workflows
- Design system documentation and cross-session memory

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 15:08:15 +11:00
commit 732c872576
56 changed files with 12690 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
{
"button": {
"$description": "Button component tokens — sizing, spacing, and typography per size variant. Colours use semantic interactive tokens via MUI theme palette.",
"height": {
"$type": "dimension",
"$description": "Minimum heights per button size. All values are multiples of 4px. Large (48px) meets the 44px minimum touch target for mobile.",
"xs": { "$value": "28px", "$description": "Extra-small — compact text buttons, inline actions" },
"sm": { "$value": "32px", "$description": "Small — secondary actions, toolbar buttons" },
"md": { "$value": "40px", "$description": "Medium — default size, form submissions" },
"lg": { "$value": "48px", "$description": "Large — primary CTAs, mobile touch targets (meets 44px minimum)" }
},
"paddingX": {
"$type": "dimension",
"$description": "Horizontal padding per button size.",
"xs": { "$value": "{spacing.2}", "$description": "8px — compact horizontal padding" },
"sm": { "$value": "{spacing.3}", "$description": "12px — small horizontal padding" },
"md": { "$value": "{spacing.4}", "$description": "16px — default horizontal padding" },
"lg": { "$value": "{spacing.6}", "$description": "24px — generous CTA horizontal padding" }
},
"paddingY": {
"$type": "dimension",
"$description": "Vertical padding per button size.",
"xs": { "$value": "{spacing.1}", "$description": "4px — compact vertical padding" },
"sm": { "$value": "{spacing.1}", "$description": "4px — small vertical padding" },
"md": { "$value": "{spacing.2}", "$description": "8px — default vertical padding" },
"lg": { "$value": "{spacing.3}", "$description": "12px — generous CTA vertical padding" }
},
"fontSize": {
"$type": "dimension",
"$description": "Font size per button size.",
"xs": { "$value": "{fontSize.xs}", "$description": "12px — extra-small button text" },
"sm": { "$value": "{fontSize.sm}", "$description": "14px — small button text" },
"md": { "$value": "{fontSize.sm}", "$description": "14px — default button text" },
"lg": { "$value": "{fontSize.base}", "$description": "16px — large button text" }
},
"iconSize": {
"$type": "dimension",
"$description": "Icon dimensions per button size.",
"xs": { "$value": "14px", "$description": "14px icons in extra-small buttons" },
"sm": { "$value": "16px", "$description": "16px icons in small buttons" },
"md": { "$value": "18px", "$description": "18px icons in medium buttons" },
"lg": { "$value": "20px", "$description": "20px icons in large buttons" }
},
"iconGap": {
"$type": "dimension",
"$description": "Gap between icon and label text.",
"xs": { "$value": "{spacing.1}", "$description": "4px icon-text gap" },
"sm": { "$value": "{spacing.1}", "$description": "4px icon-text gap" },
"md": { "$value": "{spacing.2}", "$description": "8px icon-text gap" },
"lg": { "$value": "{spacing.2}", "$description": "8px icon-text gap" }
},
"borderRadius": {
"$type": "dimension",
"$description": "Border radius for buttons.",
"default": { "$value": "{borderRadius.md}", "$description": "8px — standard button rounding" }
}
}
}

View File

@@ -0,0 +1,42 @@
{
"input": {
"$description": "Input component tokens — sizing and spacing per size variant. Colours use semantic tokens via MUI theme palette, consistent with Button approach.",
"height": {
"$type": "dimension",
"$description": "Input field heights. Medium matches Button large (48px) for alignment in search bars. Small matches Button medium (40px) for compact layouts.",
"sm": { "$value": "40px", "$description": "Small — compact forms, admin layouts, matches Button medium height" },
"md": { "$value": "48px", "$description": "Medium (default) — standard forms, matches Button large for alignment" }
},
"paddingX": {
"$type": "dimension",
"$description": "Horizontal padding inside the input field.",
"default": { "$value": "{spacing.3}", "$description": "12px — inner horizontal padding matching Figma design" }
},
"paddingY": {
"$type": "dimension",
"$description": "Vertical padding inside the input field per size.",
"sm": { "$value": "{spacing.2}", "$description": "8px — compact vertical padding for small size" },
"md": { "$value": "{spacing.3}", "$description": "12px — standard vertical padding for medium size" }
},
"fontSize": {
"$type": "dimension",
"$description": "Font size of the input value and placeholder text.",
"default": { "$value": "{fontSize.base}", "$description": "16px — prevents iOS auto-zoom on focus, matches Figma" }
},
"borderRadius": {
"$type": "dimension",
"$description": "Border radius for the input field.",
"default": { "$value": "{borderRadius.sm}", "$description": "4px — subtle rounding, consistent with Figma design" }
},
"gap": {
"$type": "dimension",
"$description": "Vertical gap between label, input field, and helper text.",
"default": { "$value": "{spacing.2}", "$description": "8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability" }
},
"iconSize": {
"$type": "dimension",
"$description": "Dimensions for leading/trailing icons inside the input.",
"default": { "$value": "20px", "$description": "20px — icon size inside input field, matches Figma trailing icon" }
}
}
}

View File

@@ -0,0 +1,111 @@
{
"color": {
"$type": "color",
"brand": {
"$description": "Warm gold/copper palette — FA primary brand hue. Derived from Parsons brand swatches.",
"50": { "$value": "#FEF9F5", "$description": "Lightest warm tint — warm section backgrounds" },
"100": { "$value": "#F7ECDF", "$description": "Light warm — hover backgrounds, subtle fills" },
"200": { "$value": "#EBDAC8", "$description": "Warm light — secondary backgrounds, divider tones" },
"300": { "$value": "#D8C3B5", "$description": "Warm beige — from brand swatch. Surface warmth, card tints" },
"400": { "$value": "#D0A070", "$description": "Mid gold — from brand swatch. Secondary interactive, step indicators" },
"500": { "$value": "#BA834E", "$description": "Base brand gold — from brand swatch. Primary CTA colour, main interactive. 3.7:1 contrast on white" },
"600": { "$value": "#B0610F", "$description": "Rich copper — from brand swatch. Hover/emphasis on brand elements. 4.8:1 contrast on white" },
"700": { "$value": "#8B4E0D", "$description": "Deep copper — active states, strong brand text on light backgrounds. 6.7:1 contrast on white" },
"800": { "$value": "#6B3C13", "$description": "Dark brown — bold brand accents, high-contrast brand text" },
"900": { "$value": "#51301B", "$description": "Chocolate — from brand swatch. Deep emphasis, dark brand surfaces" },
"950": { "$value": "#251913", "$description": "Espresso — from brand swatch. Darkest brand tone, near-black warm" }
},
"sage": {
"$description": "Cool grey-green/slate palette — FA secondary hue. Calming, professional tone for the funeral services context.",
"50": { "$value": "#F2F5F6", "$description": "Lightest sage — subtle cool backgrounds" },
"100": { "$value": "#E3EAEB", "$description": "Light sage — hover states on cool surfaces" },
"200": { "$value": "#D7E1E2", "$description": "From brand swatch — light cool surface, soft borders" },
"300": { "$value": "#C8D4D6", "$description": "Mid-light sage — dividers, secondary borders" },
"400": { "$value": "#B9C7C9", "$description": "From brand swatch — mid sage, secondary text on dark backgrounds" },
"500": { "$value": "#8EA2A7", "$description": "Base sage — secondary content, muted icons" },
"600": { "$value": "#687D84", "$description": "Dark sage — secondary text, subtle icons" },
"700": { "$value": "#4C5B6B", "$description": "From brand swatch — strong secondary, dark accents. 6.1:1 contrast on white" },
"800": { "$value": "#4C5459", "$description": "From brand swatch — near-dark grey, supplementary text. 6.7:1 contrast on white" },
"900": { "$value": "#343C40", "$description": "Very dark sage — high-contrast secondary elements" },
"950": { "$value": "#1E2528", "$description": "Near-black cool — darkest secondary tone" }
},
"neutral": {
"$description": "True grey palette for text, borders, and UI chrome. Slight cool undertone to complement the sage palette.",
"50": { "$value": "#FAFAFA", "$description": "Lightest neutral — default page background alternative" },
"100": { "$value": "#F5F5F5", "$description": "Light neutral — subtle background differentiation" },
"200": { "$value": "#E8E8E8", "$description": "Light grey — standard borders, dividers" },
"300": { "$value": "#D4D4D4", "$description": "Mid-light grey — disabled borders, subtle separators" },
"400": { "$value": "#A3A3A3", "$description": "Mid grey — placeholder text, disabled content" },
"500": { "$value": "#737373", "$description": "Base grey — secondary body text, icons" },
"600": { "$value": "#525252", "$description": "Dark grey — body text, labels. 7.1:1 contrast on white" },
"700": { "$value": "#404040", "$description": "Strong grey — headings, emphasis text. 9.7:1 contrast on white" },
"800": { "$value": "#2C2E35", "$description": "From brand swatch — charcoal with cool tint. Primary text colour. 13.2:1 contrast on white" },
"900": { "$value": "#1A1A1C", "$description": "Near-black — maximum contrast text" },
"950": { "$value": "#0A0A0B", "$description": "Deepest neutral — use sparingly" }
},
"red": {
"$description": "Red palette for error states, destructive actions, and urgent feedback. Warm-leaning for brand cohesion.",
"50": { "$value": "#FEF2F2", "$description": "Error tint — error message backgrounds" },
"100": { "$value": "#FDE8E8", "$description": "Light error — hover on error surfaces" },
"200": { "$value": "#F9BFBF", "$description": "Light red — error borders, subtle indicators" },
"300": { "$value": "#F09898", "$description": "Mid-light red — error icon backgrounds" },
"400": { "$value": "#E56B6B", "$description": "Mid red — error indicators, badges" },
"500": { "$value": "#D64545", "$description": "Base red — form validation errors, alert accents" },
"600": { "$value": "#BC2F2F", "$description": "Strong red — error text on light backgrounds. 5.7:1 contrast on white" },
"700": { "$value": "#9B2424", "$description": "Dark red — error headings, strong alerts" },
"800": { "$value": "#7A1D1D", "$description": "Deep red — high-contrast error emphasis" },
"900": { "$value": "#5C1616", "$description": "Very dark red — use sparingly" },
"950": { "$value": "#3D0E0E", "$description": "Darkest red" }
},
"amber": {
"$description": "Amber/yellow palette for warning states, price alerts, and important notices.",
"50": { "$value": "#FFF9EB", "$description": "Warning tint — warning message backgrounds" },
"100": { "$value": "#FFF0CC", "$description": "Light amber — hover on warning surfaces" },
"200": { "$value": "#FFE099", "$description": "Light amber — warning borders" },
"300": { "$value": "#FFCC66", "$description": "Mid-light amber — warning icon backgrounds" },
"400": { "$value": "#FFB833", "$description": "Mid amber — warning badges, price alerts" },
"500": { "$value": "#F5A000", "$description": "Base amber — warning accents" },
"600": { "$value": "#CC8500", "$description": "Strong amber — warning text. 3.6:1 contrast on white (large text AA)" },
"700": { "$value": "#A36B00", "$description": "Dark amber — warning headings. 5.1:1 contrast on white" },
"800": { "$value": "#7A5000", "$description": "Deep amber — high-contrast warning emphasis" },
"900": { "$value": "#523600", "$description": "Very dark amber — use sparingly" },
"950": { "$value": "#331F00", "$description": "Darkest amber" }
},
"green": {
"$description": "Green palette for success states, confirmations, and positive feedback. Slightly muted for the sensitive context.",
"50": { "$value": "#F0F7F0", "$description": "Success tint — success message backgrounds" },
"100": { "$value": "#D8ECD8", "$description": "Light green — hover on success surfaces" },
"200": { "$value": "#B8D8B8", "$description": "Light green — success borders" },
"300": { "$value": "#8DC08D", "$description": "Mid-light green — success icon backgrounds" },
"400": { "$value": "#66A866", "$description": "Mid green — success badges, completion indicators" },
"500": { "$value": "#4A8F4A", "$description": "Base green — success accents, completed steps" },
"600": { "$value": "#3B7A3B", "$description": "Strong green — success text on light backgrounds. 4.8:1 contrast on white" },
"700": { "$value": "#2E6B2E", "$description": "Dark green — success headings" },
"800": { "$value": "#235523", "$description": "Deep green — high-contrast success emphasis" },
"900": { "$value": "#1A3F1A", "$description": "Very dark green — use sparingly" },
"950": { "$value": "#0F2A0F", "$description": "Darkest green" }
},
"blue": {
"$description": "Blue palette for informational states, supplementary info, and non-brand links.",
"50": { "$value": "#EFF6FF", "$description": "Info tint — info message backgrounds" },
"100": { "$value": "#DBEAFE", "$description": "Light blue — hover on info surfaces" },
"200": { "$value": "#BFDBFE", "$description": "Light blue — info borders" },
"300": { "$value": "#93C5FD", "$description": "Mid-light blue — info icon backgrounds" },
"400": { "$value": "#60A5FA", "$description": "Mid blue — info badges" },
"500": { "$value": "#3B82F6", "$description": "Base blue — info accents, supplementary links" },
"600": { "$value": "#2563EB", "$description": "Strong blue — info text on light backgrounds. 4.6:1 contrast on white" },
"700": { "$value": "#1D4ED8", "$description": "Dark blue — info headings" },
"800": { "$value": "#1E40AF", "$description": "Deep blue — high-contrast info emphasis" },
"900": { "$value": "#1E3A8A", "$description": "Very dark blue — use sparingly" },
"950": { "$value": "#172554", "$description": "Darkest blue" }
},
"white": {
"$value": "#FFFFFF",
"$description": "Pure white — card backgrounds, inverse text, primary surface"
},
"black": {
"$value": "#000000",
"$description": "Pure black — from brand swatch. Use sparingly; prefer neutral.800-900 for text"
}
}
}

View File

@@ -0,0 +1,28 @@
{
"shadow": {
"$description": "Elevation shadows for layered UI. Values are CSS box-shadow shorthand strings.",
"sm": {
"$value": "0 1px 2px rgba(0,0,0,0.05)",
"$description": "Subtle lift — resting buttons, input focus subtle elevation"
},
"md": {
"$value": "0 4px 6px rgba(0,0,0,0.07)",
"$description": "Medium elevation — cards at rest, dropdowns, popovers"
},
"lg": {
"$value": "0 10px 15px rgba(0,0,0,0.1)",
"$description": "High elevation — modals, popovers, card hover states"
},
"xl": {
"$value": "0 20px 25px rgba(0,0,0,0.1)",
"$description": "Maximum elevation — elevated panels, dialog boxes"
}
},
"opacity": {
"$type": "number",
"$description": "Opacity values for interactive states and overlays.",
"disabled": { "$value": 0.4, "$description": "Disabled state — 40% opacity. Clearly diminished but still distinguishable" },
"hover": { "$value": 0.08, "$description": "Hover overlay — subtle 8% tint applied over backgrounds on hover" },
"overlay": { "$value": 0.5, "$description": "Modal/dialog backdrop — 50% black overlay behind modals" }
}
}

View File

@@ -0,0 +1,28 @@
{
"spacing": {
"$type": "dimension",
"$description": "Spacing scale based on 4px base unit. All values are multiples of 4.",
"0-5": { "$value": "2px", "$description": "Hairline — icon-to-text tight spacing, fine adjustments" },
"1": { "$value": "4px", "$description": "Tight — inline spacing, minimal gaps between related elements" },
"2": { "$value": "8px", "$description": "Small — related element gaps, compact padding, icon margins" },
"3": { "$value": "12px", "$description": "Component internal padding (small), chip padding" },
"4": { "$value": "16px", "$description": "Default component padding, form field gap, card grid gutter (mobile)" },
"5": { "$value": "20px", "$description": "Medium component spacing" },
"6": { "$value": "24px", "$description": "Card padding, section gap (small), card grid gutter (desktop)" },
"8": { "$value": "32px", "$description": "Section gap (medium), form section separation" },
"10": { "$value": "40px", "$description": "Section gap (large)" },
"12": { "$value": "48px", "$description": "Page section separation, vertical rhythm break" },
"16": { "$value": "64px", "$description": "Hero/banner vertical spacing" },
"20": { "$value": "80px", "$description": "Major page sections, large vertical spacing" }
},
"borderRadius": {
"$type": "dimension",
"$description": "Border radius scale for consistent rounding across components.",
"none": { "$value": "0px", "$description": "Square corners — tables, dividers, sharp elements" },
"sm": { "$value": "4px", "$description": "Small radius — inputs, small interactive elements, chips" },
"md": { "$value": "8px", "$description": "Medium radius — cards, buttons, dropdowns (default)" },
"lg": { "$value": "12px", "$description": "Large radius — modals, large cards" },
"xl": { "$value": "16px", "$description": "Extra large — feature cards, hero elements" },
"full": { "$value": "9999px", "$description": "Full/pill — avatars, pill buttons, circular elements" }
}
}

View File

@@ -0,0 +1,78 @@
{
"fontFamily": {
"$type": "fontFamily",
"body": {
"$value": "'Montserrat', 'Helvetica Neue', Arial, sans-serif",
"$description": "Primary font — Montserrat. Used for headings (h1-h6), body text, labels, and all UI elements"
},
"display": {
"$value": "'Noto Serif SC', Georgia, 'Times New Roman', serif",
"$description": "Display font — Noto Serif SC. Elegant serif for hero/display text only. Adds warmth and gravitas at large sizes"
},
"mono": {
"$value": "'JetBrains Mono', 'Fira Code', Consolas, monospace",
"$description": "Monospace font — for reference numbers (FA-2026-00847), tabular pricing data, and code"
}
},
"fontSize": {
"$type": "dimension",
"$description": "Font size scale. General-purpose sizes (2xs4xl) plus display-specific sizes for hero/marketing text.",
"2xs": { "$value": "0.6875rem", "$description": "11px — smallest UI text: compact captions, compact overlines" },
"xs": { "$value": "0.75rem", "$description": "12px — small text: captions, labels, overlines, body/xs" },
"sm": { "$value": "0.875rem", "$description": "14px — body small, labels, helper text" },
"base": { "$value": "1rem", "$description": "16px — default body text, heading/6, label/lg" },
"md": { "$value": "1.125rem", "$description": "18px — body large, heading/5" },
"lg": { "$value": "1.25rem", "$description": "20px — heading/4" },
"xl": { "$value": "1.5rem", "$description": "24px — heading/3" },
"2xl": { "$value": "1.875rem", "$description": "30px — heading/2" },
"3xl": { "$value": "2.25rem", "$description": "36px — heading/1" },
"4xl": { "$value": "3rem", "$description": "48px — reserved (legacy)" },
"display": {
"$description": "Display-specific sizes for hero and marketing text. Used exclusively with Noto Serif SC.",
"sm": { "$value": "2rem", "$description": "32px — display/sm, smallest display text" },
"3": { "$value": "2.5rem", "$description": "40px — display/3" },
"2": { "$value": "3.25rem", "$description": "52px — display/2" },
"1": { "$value": "4rem", "$description": "64px — display/1" },
"hero": { "$value": "5rem", "$description": "80px — display/hero, largest display text" }
},
"mobile": {
"$description": "Reduced font sizes for mobile breakpoints (< 600px). Display and headings scale down; body sizes stay constant.",
"displayHero": { "$value": "2rem", "$description": "32px — mobile display/hero (from 80px desktop)" },
"display1": { "$value": "1.75rem", "$description": "28px — mobile display/1 (from 64px desktop)" },
"display2": { "$value": "1.5rem", "$description": "24px — mobile display/2 (from 52px desktop)" },
"display3": { "$value": "1.375rem", "$description": "22px — mobile display/3 (from 40px desktop)" },
"displaySm": { "$value": "1.25rem", "$description": "20px — mobile display/sm (from 32px desktop)" },
"h1": { "$value": "1.625rem", "$description": "26px — mobile heading/1 (from 36px desktop)" },
"h2": { "$value": "1.375rem", "$description": "22px — mobile heading/2 (from 30px desktop)" },
"h3": { "$value": "1.25rem", "$description": "20px — mobile heading/3 (from 24px desktop)" },
"h4": { "$value": "1.125rem", "$description": "18px — mobile heading/4 (from 20px desktop)" },
"h5": { "$value": "1rem", "$description": "16px — mobile heading/5 (from 18px desktop)" },
"h6": { "$value": "0.875rem", "$description": "14px — mobile heading/6 (from 16px desktop)" }
}
},
"fontWeight": {
"$type": "fontWeight",
"regular": { "$value": 400, "$description": "Regular weight — captions, display text (serif carries inherent weight)" },
"medium": { "$value": 500, "$description": "Medium weight — body text, labels. Slightly bolder than regular for improved readability" },
"semibold": { "$value": 600, "$description": "Semibold — overlines, button text, navigation" },
"bold": { "$value": 700, "$description": "Bold — all headings (h1-h6)" }
},
"lineHeight": {
"$type": "number",
"$description": "Generic line-height scale. Typography variants use specific values for precise control.",
"tight": { "$value": 1.25, "$description": "Tight leading — large headings, display text" },
"snug": { "$value": 1.375, "$description": "Snug leading — sub-headings, labels, small text" },
"normal": { "$value": 1.5, "$description": "Normal leading — default body text, optimal readability" },
"relaxed": { "$value": 1.75, "$description": "Relaxed leading — large body text, long-form content" }
},
"letterSpacing": {
"$type": "dimension",
"$description": "Generic letter-spacing scale. Typography variants use specific values for precise control.",
"tighter": { "$value": "-0.02em", "$description": "Tighter tracking — large display text" },
"tight": { "$value": "-0.01em", "$description": "Tight tracking — headings" },
"normal": { "$value": "0em", "$description": "Normal tracking — body text, most content" },
"wide": { "$value": "0.02em", "$description": "Wide tracking — captions, small text" },
"wider": { "$value": "0.05em", "$description": "Wider tracking — labels, UI text" },
"widest": { "$value": "0.08em", "$description": "Widest tracking — overlines, uppercase text" }
}
}

View File

@@ -0,0 +1,164 @@
{
"color": {
"$type": "color",
"text": {
"$description": "Semantic text colours — define the hierarchy and intent of text across the UI.",
"primary": {
"$value": "{color.neutral.800}",
"$description": "Primary text — body content, headings. Cool charcoal (#2C2E35) for comfortable extended reading"
},
"secondary": {
"$value": "{color.neutral.600}",
"$description": "Secondary text — helper text, descriptions, metadata, less prominent content"
},
"tertiary": {
"$value": "{color.neutral.500}",
"$description": "Tertiary text — placeholders, timestamps, attribution, meta information"
},
"disabled": {
"$value": "{color.neutral.400}",
"$description": "Disabled text — clearly diminished but still readable for accessibility"
},
"inverse": {
"$value": "{color.white}",
"$description": "Inverse text — white text on dark or coloured backgrounds (buttons, banners)"
},
"brand": {
"$value": "{color.brand.600}",
"$description": "Brand-coloured text — links, inline brand emphasis. Copper tone meets AA on white (4.8:1)"
},
"error": {
"$value": "{color.red.600}",
"$description": "Error text — form validation messages, error descriptions"
},
"success": {
"$value": "{color.green.600}",
"$description": "Success text — confirmation messages, positive feedback"
},
"warning": {
"$value": "{color.amber.700}",
"$description": "Warning text — cautionary messages. Uses amber.700 for WCAG AA compliance on white (5.1:1)"
}
},
"surface": {
"$description": "Background/surface colours for page sections, cards, and containers.",
"default": {
"$value": "{color.white}",
"$description": "Default surface — main page background, card faces"
},
"subtle": {
"$value": "{color.neutral.50}",
"$description": "Subtle surface — slight differentiation from default, alternate row backgrounds"
},
"raised": {
"$value": "{color.white}",
"$description": "Raised surface — cards, elevated containers (distinguished by shadow rather than colour)"
},
"warm": {
"$value": "{color.brand.50}",
"$description": "Warm surface — brand-tinted sections, promotional areas, upsell cards like 'Protect your plan'"
},
"cool": {
"$value": "{color.sage.50}",
"$description": "Cool surface — calming sections, information panels, FAQ backgrounds"
},
"overlay": {
"$value": "#00000080",
"$description": "Overlay surface — modal/dialog backdrop at 50% black"
}
},
"border": {
"$description": "Border colours for containers, inputs, and visual dividers.",
"default": {
"$value": "{color.neutral.200}",
"$description": "Default border — cards, containers, resting input borders"
},
"strong": {
"$value": "{color.neutral.400}",
"$description": "Strong border — emphasis borders, active input borders"
},
"subtle": {
"$value": "{color.neutral.100}",
"$description": "Subtle border — section dividers, soft separators"
},
"brand": {
"$value": "{color.brand.500}",
"$description": "Brand border — focused inputs, selected cards, brand-accented containers"
},
"error": {
"$value": "{color.red.500}",
"$description": "Error border — form fields with validation errors"
},
"success": {
"$value": "{color.green.500}",
"$description": "Success border — validated fields, confirmed selections"
}
},
"interactive": {
"$description": "Colours for interactive elements — buttons, links, form controls.",
"default": {
"$value": "{color.brand.600}",
"$description": "Default interactive — primary button fill, link colour, checkbox accent. Uses brand.600 (copper) for WCAG AA compliance (4.6:1 on white)"
},
"hover": {
"$value": "{color.brand.700}",
"$description": "Hover state — deepened copper on hover for clear visual feedback"
},
"active": {
"$value": "{color.brand.800}",
"$description": "Active/pressed state — dark brown during click/tap"
},
"disabled": {
"$value": "{color.neutral.300}",
"$description": "Disabled interactive — muted grey, no pointer events"
},
"focus": {
"$value": "{color.brand.600}",
"$description": "Focus ring colour — keyboard navigation indicator, 2px outline with 2px offset"
},
"secondary": {
"$value": "{color.sage.700}",
"$description": "Secondary interactive — grey/sage buttons, less prominent actions"
},
"secondary-hover": {
"$value": "{color.sage.800}",
"$description": "Secondary interactive hover — darkened sage on hover"
}
},
"feedback": {
"$description": "System alert and feedback colours. Each type has a strong variant (for text/icons) and a subtle variant (for backgrounds).",
"success": {
"$value": "{color.green.600}",
"$description": "Success — confirmations, completed arrangement steps, booking confirmed"
},
"success-subtle": {
"$value": "{color.green.50}",
"$description": "Success background — success message container fill, completion banners"
},
"warning": {
"$value": "{color.amber.600}",
"$description": "Warning — price change alerts, important notices, bond/insurance prompts"
},
"warning-subtle": {
"$value": "{color.amber.50}",
"$description": "Warning background — warning message container fill, notice banners"
},
"error": {
"$value": "{color.red.600}",
"$description": "Error — form validation failures, system errors, payment issues"
},
"error-subtle": {
"$value": "{color.red.50}",
"$description": "Error background — error message container fill, alert banners"
},
"info": {
"$value": "{color.blue.600}",
"$description": "Info — helpful tips, supplementary information, guidance callouts"
},
"info-subtle": {
"$value": "{color.blue.50}",
"$description": "Info background — info message container fill, tip banners"
}
}
}
}

View File

@@ -0,0 +1,22 @@
{
"spacing": {
"component": {
"$type": "dimension",
"$description": "Component-level spacing — internal padding and gaps within components.",
"xs": { "$value": "{spacing.1}", "$description": "4px — tight gaps: icon margins, chip internal padding" },
"sm": { "$value": "{spacing.2}", "$description": "8px — small padding: badge padding, inline element gaps" },
"md": { "$value": "{spacing.4}", "$description": "16px — default padding: button padding, input padding, form field gap" },
"lg": { "$value": "{spacing.6}", "$description": "24px — large padding: card padding (desktop), modal padding" }
},
"layout": {
"$type": "dimension",
"$description": "Layout-level spacing — structural gaps between sections and page elements.",
"gutter": { "$value": "{spacing.4}", "$description": "16px — grid gutter on mobile, card grid gap" },
"gutter-desktop": { "$value": "{spacing.6}", "$description": "24px — grid gutter on desktop" },
"section": { "$value": "{spacing.12}", "$description": "48px — vertical gap between page sections" },
"page": { "$value": "{spacing.16}", "$description": "64px — major page section separation, hero spacing" },
"page-padding": { "$value": "{spacing.4}", "$description": "16px — horizontal page padding on mobile" },
"page-padding-desktop": { "$value": "{spacing.8}", "$description": "32px — horizontal page padding on desktop" }
}
}
}

View File

@@ -0,0 +1,198 @@
{
"typography": {
"$description": "Typography role definitions — 21 variants across 6 categories. Display uses Noto Serif SC (serif, Regular). All other text uses Montserrat. Line-height and letter-spacing use specific values per variant for precise control.",
"displayHero": {
"$description": "Hero display — largest marketing/hero text. Noto Serif SC Regular.",
"fontFamily": { "$value": "{fontFamily.display}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.display.hero}", "$type": "dimension", "$description": "80px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.displayHero}", "$type": "dimension", "$description": "32px mobile" },
"fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight", "$description": "400 — serif carries inherent weight at large sizes" },
"lineHeight": { "$value": 1.05, "$type": "number" },
"letterSpacing": { "$value": "-1.5px", "$type": "dimension" }
},
"display1": {
"$description": "Display level 1 — major marketing headings. Noto Serif SC Regular.",
"fontFamily": { "$value": "{fontFamily.display}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.display.1}", "$type": "dimension", "$description": "64px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.display1}", "$type": "dimension", "$description": "28px mobile" },
"fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.078, "$type": "number" },
"letterSpacing": { "$value": "-1px", "$type": "dimension" }
},
"display2": {
"$description": "Display level 2 — section hero text. Noto Serif SC Regular.",
"fontFamily": { "$value": "{fontFamily.display}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.display.2}", "$type": "dimension", "$description": "52px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.display2}", "$type": "dimension", "$description": "24px mobile" },
"fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.096, "$type": "number" },
"letterSpacing": { "$value": "-0.5px", "$type": "dimension" }
},
"display3": {
"$description": "Display level 3 — prominent section titles. Noto Serif SC Regular.",
"fontFamily": { "$value": "{fontFamily.display}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.display.3}", "$type": "dimension", "$description": "40px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.display3}", "$type": "dimension", "$description": "22px mobile" },
"fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.15, "$type": "number" },
"letterSpacing": { "$value": "-0.25px", "$type": "dimension" }
},
"displaySm": {
"$description": "Display small — smallest display text, pull quotes. Noto Serif SC Regular.",
"fontFamily": { "$value": "{fontFamily.display}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.display.sm}", "$type": "dimension", "$description": "32px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.displaySm}", "$type": "dimension", "$description": "20px mobile" },
"fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.1875, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"h1": {
"$description": "Heading 1 — page titles. Montserrat Bold.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.3xl}", "$type": "dimension", "$description": "36px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.h1}", "$type": "dimension", "$description": "26px mobile" },
"fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.194, "$type": "number" },
"letterSpacing": { "$value": "-0.5px", "$type": "dimension" }
},
"h2": {
"$description": "Heading 2 — section titles. Montserrat Bold.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.2xl}", "$type": "dimension", "$description": "30px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.h2}", "$type": "dimension", "$description": "22px mobile" },
"fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.267, "$type": "number" },
"letterSpacing": { "$value": "-0.25px", "$type": "dimension" }
},
"h3": {
"$description": "Heading 3 — sub-section titles. Montserrat Bold.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.xl}", "$type": "dimension", "$description": "24px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.h3}", "$type": "dimension", "$description": "20px mobile" },
"fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.292, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"h4": {
"$description": "Heading 4 — minor headings. Montserrat Bold.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.lg}", "$type": "dimension", "$description": "20px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.h4}", "$type": "dimension", "$description": "18px mobile" },
"fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.35, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"h5": {
"$description": "Heading 5 — small headings. Montserrat Bold.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.md}", "$type": "dimension", "$description": "18px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.h5}", "$type": "dimension", "$description": "16px mobile" },
"fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.389, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"h6": {
"$description": "Heading 6 — smallest heading. Montserrat Bold.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.base}", "$type": "dimension", "$description": "16px desktop" },
"fontSizeMobile": { "$value": "{fontSize.mobile.h6}", "$type": "dimension", "$description": "14px mobile" },
"fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.375, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"bodyLg": {
"$description": "Body large — lead paragraphs, introductions. Montserrat Medium.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.md}", "$type": "dimension", "$description": "18px" },
"fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.611, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"body": {
"$description": "Body default — main content text. Montserrat Medium.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.base}", "$type": "dimension", "$description": "16px" },
"fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.625, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"bodySm": {
"$description": "Body small — helper text, secondary content. Montserrat Medium.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.sm}", "$type": "dimension", "$description": "14px" },
"fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.571, "$type": "number" },
"letterSpacing": { "$value": "0px", "$type": "dimension" }
},
"bodyXs": {
"$description": "Body extra-small — fine print, compact content. Montserrat Medium.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.xs}", "$type": "dimension", "$description": "12px" },
"fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.5, "$type": "number" },
"letterSpacing": { "$value": "0.1px", "$type": "dimension" }
},
"labelLg": {
"$description": "Label large — prominent form labels, section labels. Montserrat Medium.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.base}", "$type": "dimension", "$description": "16px" },
"fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.3125, "$type": "number" },
"letterSpacing": { "$value": "0.1px", "$type": "dimension" }
},
"label": {
"$description": "Label default — form labels, UI text. Montserrat Medium.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.sm}", "$type": "dimension", "$description": "14px" },
"fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.286, "$type": "number" },
"letterSpacing": { "$value": "0.15px", "$type": "dimension" }
},
"labelSm": {
"$description": "Label small — compact labels, tag text. Montserrat Medium.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.xs}", "$type": "dimension", "$description": "12px" },
"fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.333, "$type": "number" },
"letterSpacing": { "$value": "0.2px", "$type": "dimension" }
},
"caption": {
"$description": "Caption default — fine print, timestamps, metadata. Montserrat Regular.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.xs}", "$type": "dimension", "$description": "12px" },
"fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.417, "$type": "number" },
"letterSpacing": { "$value": "0.2px", "$type": "dimension" }
},
"captionSm": {
"$description": "Caption small — compact metadata, footnotes. Montserrat Regular. Min 11px for accessibility.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.2xs}", "$type": "dimension", "$description": "11px — accessibility floor" },
"fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.364, "$type": "number" },
"letterSpacing": { "$value": "0.2px", "$type": "dimension" }
},
"overline": {
"$description": "Overline default — section overlines, category labels. Montserrat SemiBold, uppercase.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.xs}", "$type": "dimension", "$description": "12px" },
"fontWeight": { "$value": "{fontWeight.semibold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.333, "$type": "number" },
"letterSpacing": { "$value": "1.5px", "$type": "dimension" }
},
"overlineSm": {
"$description": "Overline small — compact section labels, tab overlines. Montserrat SemiBold, uppercase. Min 11px for accessibility.",
"fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" },
"fontSize": { "$value": "{fontSize.2xs}", "$type": "dimension", "$description": "11px — accessibility floor" },
"fontWeight": { "$value": "{fontWeight.semibold}", "$type": "fontWeight" },
"lineHeight": { "$value": 1.273, "$type": "number" },
"letterSpacing": { "$value": "1.5px", "$type": "dimension" }
}
}
}