Agent skill
design-language-system
Apply the professional Navy Blue colour scheme and design tokens. Use when styling components, charts, or ensuring colour consistency across the application.
Install this agent skill to your Project
npx add-skill https://github.com/sgcarstrends/sgcarstrends/tree/main/.claude/skills/design-language-system
SKILL.md
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:
- CSS variables (
var(--chart-1),var(--primary)) - HeroUI semantic classes (
text-foreground,bg-primary,text-default-500) - 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:
: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:
: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
// ✅ Good - Use semantic classes
<span className="text-foreground">Primary body text</span>
<span className="text-default-600">Secondary text</span>
<span className="text-default-500">Muted/helper text</span>
<span className="text-muted-foreground">Captions, metadata</span>
<span className="text-primary">Brand emphasis</span>
// ❌ Bad - Hardcoded colours
<span className="text-[#2F4F4F]">Body text</span>
<span style={{ color: "#708090" }}>Helper text</span>
Background Colours
// ✅ Good - Use semantic classes
<div className="bg-primary text-primary-foreground">Primary action</div>
<div className="bg-content1">Card/panel background</div>
<div className="bg-default-100">Subtle background</div>
<div className="bg-default-200">Hover state</div>
// ❌ Bad - Hardcoded colours
<div className="bg-[#191970]">Navy background</div>
<div className="bg-white">Not theme-adaptive</div>
Chart Colours
// ✅ Good - Use CSS variables
<div style={{ backgroundColor: `var(--chart-${index + 1})` }} />
<div className="bg-[var(--chart-1)]" />
// For bar charts with multiple series
{data.map((item, i) => (
<Bar
key={item.name}
style={{ fill: `var(--chart-${i + 1})` }}
/>
))}
// For single-highlight charts
<Bar
className={isHighlighted ? "fill-[var(--chart-1)]" : "fill-default-200"}
/>
// ❌ Bad - Hardcoded hex colours
<div style={{ backgroundColor: "#191970" }} />
<Bar fill="#708090" />
Interactive States
// ✅ Good - Use semantic classes for states
<button className="bg-primary text-primary-foreground hover:bg-primary/90">
Primary Button
</button>
<Link className="text-default-500 hover:bg-default-100">
Navigation Item
</Link>
// Active/selected states
<Tab className={isActive ? "bg-primary text-primary-foreground" : "text-default-500"}>
Tab Label
</Tab>
// ❌ Bad - Hardcoded state colours
<button className="bg-[#191970] hover:bg-[#14145A]">Button</button>
Chart Implementation Guidelines
Maximum Series Count
Limit charts to 6 series maximum to match the available --chart-1 through --chart-6 variables:
// ✅ Good - Within 6 series limit
{data.slice(0, 5).map((item, i) => (
<Bar style={{ fill: `var(--chart-${i + 1})` }} />
))}
// 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:
// Latest year highlighted, others muted
{data.map((item, i, arr) => {
const isLatest = i === arr.length - 1;
return (
<div
className={isLatest ? "bg-[var(--chart-1)]" : "bg-default-200 hover:bg-default-300"}
/>
);
})}
Recharts Implementation
import { Cell, Pie, PieChart } from "recharts";
// Use CSS variables for fill colours
<Pie data={chartData} dataKey="value">
{chartData.map((entry, index) => (
<Cell
key={`cell-${entry.name}`}
fill={entry.fill} // fill comes from data with var(--chart-N)
/>
))}
</Pie>
Data Preparation
// 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:
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) |
Dark Mode
Dark CSS variables are fully defined in apps/web/src/app/globals.css (.dark block) and packages/ui/src/styles/globals.css. Dark mode activation is deferred until after HeroUI v3 migration (#714, blocked by #587).
Dark mode readiness guidelines:
- Use
bg-content1instead ofbg-whitefor card/panel backgrounds (HeroUI semantic, theme-adaptive) - Use
bg-backgroundfor page-level backgrounds (already in use) - All CSS variable-based colours (
--primary,--chart-N, etc.) automatically adapt to dark mode - shadcn/ui and HeroUI components using semantic classes already support dark mode
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-*withtext-default-* - Replace
bg-gray-*withbg-default-* - Replace
bg-whitewithbg-content1for card/panel backgrounds - Ensure chart series count is 6 or fewer
- Remove modulo operations if series count is controlled
- Use
text-foregroundinstead oftext-gray-900for body text
Anti-Patterns
Colour Constant Arrays
// ❌ 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
// ❌ Bad - Hardcoded hex
<div className="text-[#2F4F4F]">Text</div>
<div style={{ backgroundColor: "#191970" }}>Box</div>
// ✅ Good - Semantic tokens
<div className="text-foreground">Text</div>
<div className="bg-primary">Box</div>
Arbitrary Gray Classes
// ❌ Bad - Tailwind gray scale
<span className="text-gray-600">Helper text</span>
<div className="bg-gray-100">Background</div>
// ✅ Good - HeroUI default scale
<span className="text-default-600">Helper text</span>
<div className="bg-default-100">Background</div>
Exceptions
OpenGraph Images
OG images require inline styles and cannot use CSS variables:
// apps/web/src/app/*/opengraph-image.tsx
// Inline hex colours are acceptable here
<div style={{ backgroundColor: "#191970" }}>
Theme Configuration
The hero.ts theme config uses hex values to define the source of truth:
// apps/web/src/app/hero.ts
primary: {
DEFAULT: "#191970", // This defines the --primary variable
}
Related Files
apps/web/src/app/globals.css- CSS variable definitionsapps/web/src/app/hero.ts- HeroUI theme configurationapps/web/CLAUDE.md- Colour System sectionpackages/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.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
component-tester
Run Vitest tests for a specific component with coverage. Use when making changes to React components to ensure tests pass and coverage is maintained.
cache-components
Ensure 'use cache' is used strategically to minimize CPU usage and ISR writes. Use when creating/modifying queries to verify caching decisions align with data update patterns and cost optimization.
ui-design-system
Enforce modern dashboard UI patterns with pill-shaped design, professional colour scheme, and typography standards. Use when building or reviewing UI components for the web application.
typography-spacing-enforcer
Enforce Typography system and modern spacing conventions. Use when implementing new UI components to ensure design consistency with project standards.
conventional-commits
Format commit messages following project conventions with commitlint validation. Use when committing changes, writing PR descriptions, or preparing releases.
dependency-upgrade
Upgrade dependencies safely using pnpm catalog, checking for breaking changes, and testing upgrades. Use when updating packages, applying security patches, upgrading major versions, resolving dependency conflicts, or modernizing tech stack.
Didn't find tool you were looking for?