E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
Deploy to Production / Build & Verify (push) Failing after 13s
Ping Search Engines / Notify Search Engines (push) Successful in 3s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 1s
E2E Test Suite / Smoke Tests (P0) (push) Failing after 9m36s
E2E Test Suite / Form Interaction Tests (push) Failing after 12m6s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 11m46s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 9m31s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 11m5s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 15m24s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 6s
E2E Test Suite / Mobile Device Tests (push) Failing after 3h12m28s
Uptime Monitor / Health & Response Time (push) Successful in 5s
Uptime Monitor / SSL Certificate (push) Successful in 3s
Uptime Monitor / Send Alerts (push) Has been skipped
Uptime Monitor / Record Uptime Success (push) Successful in 2s
423 lines
17 KiB
CSS
423 lines
17 KiB
CSS
/* ============================================================
|
|
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-<token>)
|
|
|
|
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);
|
|
}
|