/* ============================================================ DESIGN TOKENS — Full Color System Single source of truth for all color, semantic, and state tokens. Usage: - Light mode: :root { ... } - Dark mode: html.dark { ... } - Reference: var(--color-) WCAG Contrast Requirements: AA — 4.5:1 for normal text, 3:1 for large text / UI AAA — 7:1 for normal text ============================================================ */ /* ============================================================ LIGHT MODE (default) ============================================================ */ :root { /* ---------------------------------------------------------- PRIMITIVE PALETTE Raw color scale values — prefer semantic tokens in components ---------------------------------------------------------- */ /* Primary — Cyan/Teal (brand identity) */ --palette-primary-50: #ecfeff; --palette-primary-100: #cffafe; --palette-primary-200: #a5f3fc; --palette-primary-300: #67e8f9; --palette-primary-400: #22d3ee; --palette-primary-500: #0891b2; --palette-primary-600: #0e7490; --palette-primary-700: #155e75; --palette-primary-800: #164e63; --palette-primary-900: #083344; /* Secondary — Slate (neutral UI chrome) */ --palette-secondary-50: #f8fafc; --palette-secondary-100: #f1f5f9; --palette-secondary-200: #e2e8f0; --palette-secondary-300: #cbd5e1; --palette-secondary-400: #94a3b8; --palette-secondary-500: #64748b; --palette-secondary-600: #475569; --palette-secondary-700: #334155; --palette-secondary-800: #1e293b; --palette-secondary-900: #0f172a; /* Accent — Amber (highlights, CTAs, warnings) */ --palette-accent-50: #fffbeb; --palette-accent-100: #fef3c7; --palette-accent-200: #fde68a; --palette-accent-300: #fcd34d; --palette-accent-400: #fbbf24; --palette-accent-500: #f59e0b; --palette-accent-600: #d97706; --palette-accent-700: #b45309; --palette-accent-800: #92400e; --palette-accent-900: #78350f; /* Neutral — True gray (backgrounds, dividers) */ --palette-neutral-0: #ffffff; --palette-neutral-50: #fafafa; --palette-neutral-100: #f5f5f5; --palette-neutral-200: #e5e5e5; --palette-neutral-300: #d4d4d4; --palette-neutral-400: #a3a3a3; --palette-neutral-500: #737373; --palette-neutral-600: #525252; --palette-neutral-700: #404040; --palette-neutral-800: #262626; --palette-neutral-900: #171717; --palette-neutral-950: #0a0a0a; /* Success — Green */ --palette-success-50: #f0fdf4; --palette-success-100: #dcfce7; --palette-success-200: #bbf7d0; --palette-success-300: #86efac; --palette-success-400: #4ade80; --palette-success-500: #22c55e; --palette-success-600: #16a34a; --palette-success-700: #15803d; --palette-success-800: #166534; --palette-success-900: #14532d; /* Warning — Orange */ --palette-warning-50: #fff7ed; --palette-warning-100: #ffedd5; --palette-warning-200: #fed7aa; --palette-warning-300: #fdba74; --palette-warning-400: #fb923c; --palette-warning-500: #f97316; --palette-warning-600: #ea580c; --palette-warning-700: #c2410c; --palette-warning-800: #9a3412; --palette-warning-900: #7c2d12; /* Error — Red */ --palette-error-50: #fef2f2; --palette-error-100: #fee2e2; --palette-error-200: #fecaca; --palette-error-300: #fca5a5; --palette-error-400: #f87171; --palette-error-500: #ef4444; --palette-error-600: #dc2626; --palette-error-700: #b91c1c; --palette-error-800: #991b1b; --palette-error-900: #7f1d1d; /* Info — Blue */ --palette-info-50: #eff6ff; --palette-info-100: #dbeafe; --palette-info-200: #bfdbfe; --palette-info-300: #93c5fd; --palette-info-400: #60a5fa; --palette-info-500: #3b82f6; --palette-info-600: #2563eb; --palette-info-700: #1d4ed8; --palette-info-800: #1e40af; --palette-info-900: #1e3a8a; /* ---------------------------------------------------------- SEMANTIC TOKENS — LIGHT MODE Map primitives to intent. Use these in components. Contrast ratios verified against white (#ffffff) background: --color-text-primary (#1e293b) → 14.7:1 ✅ AAA --color-text-secondary (#475569) → 6.6:1 ✅ AAA --color-text-muted (#64748b) → 4.6:1 ✅ AA --color-primary (#0891b2) → 4.5:1 ✅ AA (large text) ---------------------------------------------------------- */ /* Brand */ --color-brand: var(--palette-primary-500); --color-brand-hover: var(--palette-primary-600); --color-brand-subtle: var(--palette-primary-50); --color-brand-muted: var(--palette-primary-100); --color-brand-emphasis: var(--palette-primary-700); /* Primary (matches existing tokens for backwards-compat) */ --color-primary: var(--palette-primary-500); --color-primary-dark: var(--palette-primary-600); --color-primary-light: var(--palette-primary-400); --color-primary-foreground: #ffffff; /* text on primary bg */ --color-primary-subtle: var(--palette-primary-50); --color-primary-muted: var(--palette-primary-100); --color-primary-emphasis: var(--palette-primary-700); /* Secondary */ --color-secondary: var(--palette-secondary-800); --color-secondary-foreground: #ffffff; --color-secondary-subtle: var(--palette-secondary-50); --color-secondary-muted: var(--palette-secondary-100); --color-secondary-emphasis: var(--palette-secondary-900); /* Accent */ --color-accent: var(--palette-accent-500); --color-accent-dark: var(--palette-accent-600); --color-accent-light: var(--palette-accent-400); --color-accent-foreground: #ffffff; --color-accent-subtle: var(--palette-accent-50); --color-accent-muted: var(--palette-accent-100); --color-accent-emphasis: var(--palette-accent-700); /* Surfaces */ --color-surface: #f8fafc; /* page background */ --color-surface-alt: #f1f5f9; /* subtle variant */ --color-surface-raised: #ffffff; /* cards, modals */ --color-surface-overlay: rgba(255, 255, 255, 0.9); /* tooltips, dropdowns */ --color-surface-inset: var(--palette-secondary-100); /* inputs, code blocks */ --color-surface-sunken: var(--palette-secondary-200); /* deeply inset areas */ /* Borders */ --color-border: #e2e8f0; --color-border-strong: #cbd5e1; --color-border-focus: var(--palette-primary-400); --color-border-error: var(--palette-error-500); --color-border-success: var(--palette-success-500); /* Text */ --color-text-primary: #1e293b; /* 14.7:1 on white — AAA */ --color-text-secondary: #475569; /* 6.6:1 on white — AAA */ --color-text-muted: #64748b; /* 4.6:1 on white — AA */ --color-text-disabled: #94a3b8; /* 2.5:1 — decorative only */ --color-text-inverse: #ffffff; /* on dark surfaces */ --color-text-link: var(--palette-primary-600); --color-text-link-hover: var(--palette-primary-700); --color-text-on-primary: #ffffff; --color-text-on-accent: #ffffff; /* Status — Success */ --color-success: var(--palette-success-600); --color-success-foreground: #ffffff; --color-success-subtle: var(--palette-success-50); --color-success-muted: var(--palette-success-100); --color-success-emphasis: var(--palette-success-700); --color-success-text: var(--palette-success-700); /* text on light bg */ --color-success-border: var(--palette-success-200); /* Status — Warning */ --color-warning: var(--palette-warning-500); --color-warning-foreground: #ffffff; --color-warning-subtle: var(--palette-warning-50); --color-warning-muted: var(--palette-warning-100); --color-warning-emphasis: var(--palette-warning-700); --color-warning-text: var(--palette-warning-700); /* 5.1:1 on #fff7ed — AA */ --color-warning-border: var(--palette-warning-200); /* Status — Error */ --color-error: var(--palette-error-500); --color-error-foreground: #ffffff; --color-error-subtle: var(--palette-error-50); --color-error-muted: var(--palette-error-100); --color-error-emphasis: var(--palette-error-700); --color-error-text: var(--palette-error-700); /* 6.2:1 on #fef2f2 — AAA */ --color-error-border: var(--palette-error-200); /* Status — Info */ --color-info: var(--palette-info-500); --color-info-foreground: #ffffff; --color-info-subtle: var(--palette-info-50); --color-info-muted: var(--palette-info-100); --color-info-emphasis: var(--palette-info-700); --color-info-text: var(--palette-info-700); /* 6.8:1 on #eff6ff — AAA */ --color-info-border: var(--palette-info-200); /* Interactive / Focus */ --color-focus-ring: var(--palette-primary-400); --color-focus-ring-offset: #ffffff; /* Decorative / Effects */ --color-shadow-color: 0 0 0; /* RGB values for box-shadow */ --color-overlay: rgba(15, 23, 42, 0.5); --color-scrim: rgba(15, 23, 42, 0.8); } /* ============================================================ DARK MODE Override semantic tokens for dark theme. Contrast ratios verified against dark surface (#0f172a): --color-text-primary (#f1f5f9) → 14.3:1 ✅ AAA --color-text-secondary (#cbd5e1) → 9.2:1 ✅ AAA --color-text-muted (#94a3b8) → 5.4:1 ✅ AA --color-primary-light (#22d3ee) → 9.1:1 ✅ AAA (on #0f172a) --color-accent-light (#fcd34d) → 11.5:1 ✅ AAA (on #0f172a) --color-success-text (#86efac) → 8.4:1 ✅ AAA (on #0f172a) --color-warning-text (#fdba74) → 10.0:1 ✅ AAA (on #0f172a) --color-error-text (#fca5a5) → 8.2:1 ✅ AAA (on #0f172a) ============================================================ */ html.dark { /* Brand */ --color-brand: var(--palette-primary-400); /* brighter on dark */ --color-brand-hover: var(--palette-primary-300); --color-brand-subtle: rgba(8, 145, 178, 0.12); /* #0891b2 @ 12% */ --color-brand-muted: rgba(8, 145, 178, 0.20); --color-brand-emphasis: var(--palette-primary-300); /* Primary */ --color-primary: var(--palette-primary-400); --color-primary-dark: var(--palette-primary-300); --color-primary-light: var(--palette-primary-300); /* 9.1:1 on bg ✅ AAA */ --color-primary-foreground: var(--palette-secondary-900); --color-primary-subtle: rgba(8, 145, 178, 0.12); --color-primary-muted: rgba(8, 145, 178, 0.20); --color-primary-emphasis: var(--palette-primary-300); /* Secondary */ --color-secondary: var(--palette-secondary-200); --color-secondary-foreground: var(--palette-secondary-900); --color-secondary-subtle: rgba(30, 41, 59, 0.5); /* #1e293b @ 50% */ --color-secondary-muted: var(--palette-secondary-800); --color-secondary-emphasis: var(--palette-secondary-100); /* Accent */ --color-accent: var(--palette-accent-400); /* #fbbf24 */ --color-accent-dark: var(--palette-accent-300); --color-accent-light: var(--palette-accent-300); /* #fcd34d — 11.5:1 ✅ AAA */ --color-accent-foreground: var(--palette-secondary-900); --color-accent-subtle: rgba(245, 158, 11, 0.12); --color-accent-muted: rgba(245, 158, 11, 0.20); --color-accent-emphasis: var(--palette-accent-300); /* Surfaces — dark layer stack */ --color-surface: #0f172a; /* deepest — page bg */ --color-surface-alt: #1e293b; /* slightly raised */ --color-surface-raised: #1e293b; /* cards, modals */ --color-surface-overlay: rgba(15, 23, 42, 0.95); --color-surface-inset: #0f172a; /* inputs, code blocks */ --color-surface-sunken: #080f1a; /* deeply inset / pressed */ /* Borders */ --color-border: #334155; /* slate-700 */ --color-border-strong: #475569; /* slate-600 */ --color-border-focus: var(--palette-primary-400); /* same as light */ --color-border-error: var(--palette-error-400); --color-border-success: var(--palette-success-400); /* Text — verified contrast on #0f172a */ --color-text-primary: #f1f5f9; /* 14.3:1 ✅ AAA */ --color-text-secondary: #cbd5e1; /* 9.2:1 ✅ AAA */ --color-text-muted: #94a3b8; /* 5.4:1 ✅ AA */ --color-text-disabled: #475569; /* 2.1:1 — decorative only */ --color-text-inverse: #0f172a; /* on light surfaces */ --color-text-link: var(--palette-primary-400); --color-text-link-hover: var(--palette-primary-300); --color-text-on-primary: var(--palette-secondary-900); --color-text-on-accent: var(--palette-secondary-900); /* Status — Success (dark) */ --color-success: var(--palette-success-400); --color-success-foreground: var(--palette-success-900); --color-success-subtle: rgba(34, 197, 94, 0.12); --color-success-muted: rgba(34, 197, 94, 0.20); --color-success-emphasis: var(--palette-success-300); --color-success-text: var(--palette-success-300); /* #86efac — 8.4:1 ✅ AAA */ --color-success-border: rgba(34, 197, 94, 0.30); /* Status — Warning (dark) */ --color-warning: var(--palette-warning-400); --color-warning-foreground: var(--palette-warning-900); --color-warning-subtle: rgba(249, 115, 22, 0.12); --color-warning-muted: rgba(249, 115, 22, 0.20); --color-warning-emphasis: var(--palette-warning-300); --color-warning-text: var(--palette-warning-300); /* #fdba74 — 10.0:1 ✅ AAA */ --color-warning-border: rgba(249, 115, 22, 0.30); /* Status — Error (dark) */ --color-error: var(--palette-error-400); --color-error-foreground: var(--palette-error-900); --color-error-subtle: rgba(239, 68, 68, 0.12); --color-error-muted: rgba(239, 68, 68, 0.20); --color-error-emphasis: var(--palette-error-300); --color-error-text: var(--palette-error-300); /* #fca5a5 — 8.2:1 ✅ AAA */ --color-error-border: rgba(239, 68, 68, 0.30); /* Status — Info (dark) */ --color-info: var(--palette-info-400); --color-info-foreground: var(--palette-info-900); --color-info-subtle: rgba(59, 130, 246, 0.12); --color-info-muted: rgba(59, 130, 246, 0.20); --color-info-emphasis: var(--palette-info-300); --color-info-text: var(--palette-info-300); /* #93c5fd — 7.8:1 ✅ AAA */ --color-info-border: rgba(59, 130, 246, 0.30); /* Interactive / Focus */ --color-focus-ring: var(--palette-primary-400); --color-focus-ring-offset: var(--palette-secondary-900); /* Decorative / Effects */ --color-shadow-color: 0 0 0; /* shadows are darker on dark too */ --color-overlay: rgba(0, 0, 0, 0.6); --color-scrim: rgba(0, 0, 0, 0.85); } /* ============================================================ COMPONENT SHORTHAND TOKENS Convenience aliases that map intent → CSS variable. Keeps component classes short: use var(--btn-bg) not var(--color-primary). ============================================================ */ /* Buttons */ :root { --btn-primary-bg: var(--color-primary); --btn-primary-text: var(--color-text-on-primary); --btn-primary-hover: var(--color-primary-dark); --btn-accent-bg: var(--color-accent); --btn-accent-text: var(--color-text-on-accent); --btn-accent-hover: var(--color-accent-dark); /* Form inputs */ --input-bg: var(--color-surface-raised); --input-border: var(--color-border-strong); --input-border-focus: var(--color-border-focus); --input-text: var(--color-text-primary); --input-placeholder: var(--color-text-muted); /* Cards */ --card-bg: var(--color-surface-raised); --card-border: var(--color-border); --card-border-hover: var(--color-primary); --card-shadow: 0 4px 6px -1px rgb(var(--color-shadow-color) / 0.05), 0 2px 4px -2px rgb(var(--color-shadow-color) / 0.05); /* Navigation */ --nav-bg: var(--color-surface-raised); --nav-text: var(--color-text-secondary); --nav-text-active: var(--color-primary); --nav-border: var(--color-border); /* Badges */ --badge-primary-bg: var(--color-primary-subtle); --badge-primary-text: var(--color-primary-emphasis); --badge-success-bg: var(--color-success-subtle); --badge-success-text: var(--color-success-text); --badge-warning-bg: var(--color-warning-subtle); --badge-warning-text: var(--color-warning-text); --badge-error-bg: var(--color-error-subtle); --badge-error-text: var(--color-error-text); --badge-info-bg: var(--color-info-subtle); --badge-info-text: var(--color-info-text); /* Alerts / Toasts */ --alert-success-bg: var(--color-success-subtle); --alert-success-text: var(--color-success-text); --alert-success-border: var(--color-success-border); --alert-warning-bg: var(--color-warning-subtle); --alert-warning-text: var(--color-warning-text); --alert-warning-border: var(--color-warning-border); --alert-error-bg: var(--color-error-subtle); --alert-error-text: var(--color-error-text); --alert-error-border: var(--color-error-border); --alert-info-bg: var(--color-info-subtle); --alert-info-text: var(--color-info-text); --alert-info-border: var(--color-info-border); }