Skip to content

Design System

Source: Hermina 360 Design (reference: ../Hermina 360 Design/DESIGN_SYSTEM.md) Last Updated: 2026


Color System

All colors are defined in src/lib/colors.ts. Never hardcode hex values in components.

Brand Colors

ts
BRAND_GREEN = '#2D7D32'    // Hermina primary forest green
BRAND_GREEN_DARK = '#1B4332'
BRAND_TEAL = '#0891b2'     // Target lines, links, accent
BRAND_GOLD = '#F5C200'     // Secondary accent

Status Colors (Colorblind-Safe)

CRITICAL RULE: All status indicators use blue/orange — never green/red.

ts
STATUS_EXCELLENT = '#0ea5e9'  // Sky blue (≥95% of target)
STATUS_GOOD = '#3b82f6'       // Blue (80-95% of target)
STATUS_WARNING = '#f97316'    // Orange (<80% of target)
STATUS_CRITICAL = '#dc2626'   // Red — ONLY for urgent/critical alerts

Red (STATUS_CRITICAL) is reserved exclusively for:

  • BOR < 60%
  • Safety events / sentinel events
  • Urgent escalations requiring immediate action

Chart Colors (Colorblind-Safe Sequential Palette)

ts
CHART_SEQUENCE = [blue, cyan, indigo, purple, orange, amber, slate]
// #3b82f6, #06b6d4, #6366f1, #a855f7, #f97316, #f59e0b, #64748b

Use getChartColor(index) to cycle through the palette.

Status Helper

ts
import { getStatusColor, getStatusLabel } from '@/lib/colors';

const color = getStatusColor(achievementPct);  // pct = 0-100
const label = getStatusLabel(achievementPct);  // 'Excellent' | 'Good' | 'Needs Attention'

Typography

Hero card numbers:    34px, weight 700, tracking -0.02em
Supporting KPI tiles: 22px, weight 700, tracking -0.01em
Section titles:       13-14px, weight 600
Helper text:          11-12px, color textSecondary

Tabular numbers: className="tabular-nums" on all KPI values

4-Zone Layout

Every dashboard page MUST follow this structure:

Zone 1 — HERO (top)
  • 1-3 large cards answering the page's primary question
  • Height: ~130-150px
  • Use colored top border matching status color

Zone 2 — SUPPORTING KPIs
  • 3-5 compact tiles explaining hero metrics
  • Height: ~80-100px

Zone 3 — PRIMARY CHART
  • ONE main chart (most decision-useful)
  • Supporting charts in same row must match height

Zone 4 — ACTION ZONE
  • Filtered lists, branch alerts, items requiring action
  • Specific and actionable

Grid Usage

tsx
// Hero cards (3 columns)
<Row gutter={[12, 12]}>
  <Col xs={24} sm={8}><HeroCard /></Col>
</Row>

// Supporting KPIs (4-5 columns)
<Row gutter={[12, 12]}>
  <Col xs={12} sm={6} md={4}><KpiTile /></Col>
</Row>

// Charts (flexible, match heights in same row)
<Row gutter={[12, 12]}>
  <Col xs={24} lg={14}><Card><BigChart height={280} /></Card></Col>
  <Col xs={24} lg={10}><Card><SideChart height={280} /></Card></Col>
</Row>

Chart Heights

All charts in the same row MUST have matching heights.

Use caseHeight
Default side-by-side280px
Clinical / funnel300px
Large detail charts320px
Full-width bar charts360px

Chart Rules

  1. Max 12 items in a single chart — never render all 54 branches
  2. Reference lines for targets: targetValue prop on chart widgets
  3. Colorblind-safe colors: Use palette from lib/colors.ts, never ad-hoc colors
  4. Status coloring: Use getStatusColor(pct) for status-based bar colors
  5. Tabular numbers: className="tabular-nums" on all numeric displays

Delta Indicators

tsx
<span style={{ fontSize: 12, color: deltaUp === higherIsBetter ? STATUS_EXCELLENT : STATUS_WARNING }}>
  {deltaUp ? <ArrowUpOutlined /> : <ArrowDownOutlined />}
  {' '}{Math.abs(delta).toFixed(1)}% vs last month
</span>

Status Badge Pattern

tsx
<span style={{
  background: statusColor + '18',  // 18 = 10% opacity in hex
  color: statusColor,
  borderRadius: 20,
  padding: '2px 10px',
  fontSize: 12,
  fontWeight: 600,
}}>
  {achievement.toFixed(0)}% of target
</span>

Accessibility

  • WCAG AA compliant: 4.5:1 contrast ratio minimum
  • Colorblind tested: Protanopia, Deuteranopia, Tritanopia, Monochromacy
  • Touch targets ≥ 44px
  • All charts have descriptive aria-labels

Test with Chrome DevTools → Rendering → "Emulate vision deficiencies"


Dark Mode

The dark theme uses:

  • Canvas: #0a1f13 (very dark green)
  • Card surface: #122b1c
  • Border: #1e3a2b
  • Primary: #5BB585 (lighter green for dark backgrounds)

Both themes are defined in src/styles/tokens.ts (styled-components) and src/styles/theme.ts (Ant Design).