--- name: design-language-system description: Apply the professional Navy Blue colour scheme and design tokens. Use when styling components, charts, or ensuring colour consistency across the application. allowed-tools: Read, Edit, Grep, Glob --- # Design Language System Skill This skill documents the professional colour scheme and design tokens for SG Cars Trends, optimised for automotive data visualisation (GitHub Issue #406). ## When to Use This Skill - Styling new components with the brand colour palette - Implementing chart colours for data visualisation - Ensuring colour consistency across the application - Migrating arbitrary hex colours to design tokens - Reviewing colour usage in code reviews ## Colour Philosophy **Never use arbitrary hex colours in components.** Always use: 1. CSS variables (`var(--chart-1)`, `var(--primary)`) 2. HeroUI semantic classes (`text-foreground`, `bg-primary`, `text-default-500`) 3. Tailwind colour classes mapped to CSS variables (`text-primary`, `bg-muted`) ## Brand Colour Palette | Role | Colour | Hex | HSL | Usage | |------|--------|-----|-----|-------| | Primary | Navy Blue | `#191970` | `hsl(240, 63%, 27%)` | Headers, footers, primary buttons, key accents | | Secondary | Slate Gray | `#708090` | `hsl(210, 13%, 50%)` | Card containers, borders, secondary buttons | | Accent | Steel Blue | `#4A6AAE` | `hsl(220, 40%, 49%)` | Interactive elements, links, hover states | | Foreground | Blue-Gray | `#2D3748` | `hsl(220, 15%, 20%)` | Body text, icons | | Muted | Light Blue-Gray | `#F0F4F8` | `hsl(213, 32%, 95%)` | Backgrounds, subtle textures | | Border | Light Slate | `#E2E8F0` | `hsl(214, 32%, 91%)` | Dividers, input borders | | Success | Green | `#22C55E` | `hsl(142, 71%, 45%)` | Positive trends, success states | | Destructive | Red | `#DC2626` | `hsl(0, 72%, 51%)` | Errors, negative trends, destructive actions | ## CSS Variables ### Core Semantic Variables Defined in `apps/web/src/app/globals.css`: ```css :root { /* Primary - Navy Blue */ --primary: hsl(240 63% 27%); /* #191970 */ --primary-foreground: hsl(0 0% 100%); /* Secondary - Slate Gray */ --secondary: hsl(210 13% 50%); /* #708090 */ --secondary-foreground: hsl(0 0% 100%); /* Foreground - Blue-Gray */ --foreground: hsl(220 15% 20%); --background: hsl(0 0% 100%); /* Muted - Light Blue-Gray */ --muted: hsl(213 32% 95%); /* #F0F4F8 */ --muted-foreground: hsl(220 15% 20%); /* Accent - Steel Blue */ --accent: hsl(220 40% 49%); /* #4A6AAE */ --accent-foreground: hsl(0 0% 100%); /* Success - Green */ --success: hsl(142 71% 45%); /* #22C55E */ --success-foreground: hsl(0 0% 100%); /* Destructive - Red */ --destructive: hsl(0 72% 51%); /* #DC2626 */ --destructive-foreground: hsl(0 0% 100%); /* Border */ --border: hsl(214 32% 91%); /* #E2E8F0 */ } ``` ### Chart Colour Variables Navy Blue gradient palette for data visualisation: ```css :root { --chart-1: hsl(240 64% 27%); /* Navy Blue - Primary/Top ranking */ --chart-2: hsl(220 51% 37%); /* Medium Blue - Second ranking */ --chart-3: hsl(220 41% 49%); /* Light Blue - Third ranking */ --chart-4: hsl(210 14% 53%); /* Slate Gray - Fourth ranking */ --chart-5: hsl(215 23% 65%); /* Light Slate - Fifth ranking */ --chart-6: hsl(212 17% 76%); /* Pale Slate - Sixth ranking */ } ``` ## Usage Patterns ### Text Colours ```tsx // ✅ Good - Use semantic classes Primary body text Secondary text Muted/helper text Captions, metadata Brand emphasis // ❌ Bad - Hardcoded colours Body text Helper text ``` ### Background Colours ```tsx // ✅ Good - Use semantic classes
Primary action
Subtle background
Hover state
Card background
// ❌ Bad - Hardcoded colours
Navy background
``` ### Chart Colours ```tsx // ✅ Good - Use CSS variables
// For bar charts with multiple series {data.map((item, i) => ( ))} // For single-highlight charts // ❌ Bad - Hardcoded hex colours
``` ### Interactive States ```tsx // ✅ Good - Use semantic classes for states Navigation Item // Active/selected states Tab Label // ❌ Bad - Hardcoded state colours ``` ## Chart Implementation Guidelines ### Maximum Series Count Limit charts to **6 series maximum** to match the available `--chart-1` through `--chart-6` variables: ```tsx // ✅ Good - Within 6 series limit {data.slice(0, 5).map((item, i) => ( ))} // No modulo needed when series count is controlled colour: `var(--chart-${index + 1})` // ❌ Bad - Modulo for unlimited series (indicates design problem) colour: `var(--chart-${(index % 6) + 1})` ``` ### Single-Highlight Pattern For charts where one element is emphasised: ```tsx // Latest year highlighted, others muted {data.map((item, i, arr) => { const isLatest = i === arr.length - 1; return (
); })} ``` ### Recharts Implementation ```tsx import { Cell, Pie, PieChart } from "recharts"; // Use CSS variables for fill colours {chartData.map((entry, index) => ( ))} ``` ### Data Preparation ```tsx // Prepare chart data with CSS variable colours const chartData = data.map((item, index) => ({ name: item.name, value: item.count, fill: `var(--chart-${index + 1})`, })); ``` ## HeroUI Theme Integration The colour system is integrated with HeroUI via `apps/web/src/app/hero.ts`: ```typescript import { heroui } from "@heroui/react"; export default heroui({ themes: { light: { colors: { primary: { DEFAULT: "#191970", // Navy Blue foreground: "#FFFFFF", }, secondary: { DEFAULT: "#708090", // Slate Gray foreground: "#FFFFFF", }, success: { DEFAULT: "#008B8B", // Dark Cyan foreground: "#FFFFFF", }, foreground: "#2F4F4F", // Dark Slate Gray // ... default scale for grays }, }, }, }); ``` ### HeroUI Default Scale Use the `default` scale for UI element states: | Class | Usage | |-------|-------| | `bg-default-50` | Lightest background | | `bg-default-100` | Subtle background, hover state base | | `bg-default-200` | Muted elements, inactive bars | | `bg-default-300` | Hover state for muted elements | | `text-default-500` | Muted text, placeholders | | `text-default-600` | Secondary text | | `text-default-900` | Strong emphasis (H4 headings) | ## Migration Checklist When migrating existing code to the design system: - [ ] Replace hardcoded hex colours with CSS variables or semantic classes - [ ] Remove colour constant arrays (e.g., `CHART_COLORS`, `MARKET_SHARE_COLOURS`) - [ ] Use `var(--chart-N)` inline for chart colours - [ ] Replace `text-gray-*` with `text-default-*` - [ ] Replace `bg-gray-*` with `bg-default-*` - [ ] Ensure chart series count is 6 or fewer - [ ] Remove modulo operations if series count is controlled - [ ] Use `text-foreground` instead of `text-gray-900` for body text ## Anti-Patterns ### Colour Constant Arrays ```tsx // ❌ Bad - Don't create colour arrays const CHART_COLORS = ["#191970", "#2E4A8E", "#4A6AAE", "#708090"]; // ...later backgroundColor: CHART_COLORS[i % CHART_COLORS.length] // ✅ Good - Use CSS variables inline backgroundColor: `var(--chart-${i + 1})` ``` ### Hardcoded Hex Values ```tsx // ❌ Bad - Hardcoded hex
Text
Box
// ✅ Good - Semantic tokens
Text
Box
``` ### Arbitrary Gray Classes ```tsx // ❌ Bad - Tailwind gray scale Helper text
Background
// ✅ Good - HeroUI default scale Helper text
Background
``` ## Exceptions ### OpenGraph Images OG images require inline styles and cannot use CSS variables: ```tsx // apps/web/src/app/*/opengraph-image.tsx // Inline hex colours are acceptable here
``` ### Theme Configuration The `hero.ts` theme config uses hex values to define the source of truth: ```typescript // apps/web/src/app/hero.ts primary: { DEFAULT: "#191970", // This defines the --primary variable } ``` ## Related Files - `apps/web/src/app/globals.css` - CSS variable definitions - `apps/web/src/app/hero.ts` - HeroUI theme configuration - `apps/web/CLAUDE.md` - Colour System section - `packages/ui/src/styles/globals.css` - Shared UI package styles ## Accessibility (WCAG AA) - Normal text: Minimum 4.5:1 contrast ratio - Large text: Minimum 3:1 contrast ratio - Interactive elements: Minimum 3:1 for focus indicators - Colour alone must not convey information (use icons, text, patterns) The Navy Blue primary (`#191970`) on white background meets WCAG AAA contrast requirements.