Latest Updated Pages
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
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
This commit is contained in:
@@ -0,0 +1,422 @@
|
||||
/* ============================================================
|
||||
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);
|
||||
}
|
||||
+71
-28
@@ -1,21 +1,25 @@
|
||||
/* Google Fonts are loaded non-blocking via <link rel="preload"> in BaseLayout.astro.
|
||||
The @import is intentionally removed to avoid render-blocking font requests. */
|
||||
|
||||
/* Full design token system (colors, semantic tokens, dark mode) */
|
||||
@import './design-tokens.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ============================================================
|
||||
CSS CUSTOM PROPERTIES (Design Tokens)
|
||||
Single source of truth for values used outside Tailwind
|
||||
Legacy aliases kept for backward-compatibility.
|
||||
New code should use tokens from design-tokens.css directly.
|
||||
============================================================ */
|
||||
:root {
|
||||
/* Colors */
|
||||
--color-primary: #0891b2;
|
||||
--color-primary-dark: #0e7490;
|
||||
--color-primary-light: #22d3ee;
|
||||
--color-secondary: #1e293b;
|
||||
--color-accent: #f59e0b;
|
||||
/* Colors — aliases pointing to design-tokens.css semantic tokens */
|
||||
--color-primary: var(--palette-primary-500);
|
||||
--color-primary-dark: var(--palette-primary-600);
|
||||
--color-primary-light: var(--palette-primary-400);
|
||||
--color-secondary: var(--palette-secondary-800);
|
||||
--color-accent: var(--palette-accent-500);
|
||||
--color-surface: #f8fafc;
|
||||
--color-surface-alt: #f1f5f9;
|
||||
--color-border: #e2e8f0;
|
||||
@@ -54,6 +58,36 @@
|
||||
--section-padding: 6rem; /* py-24 */
|
||||
--section-padding-sm: 4rem; /* py-16 */
|
||||
--container-max: 80rem; /* max-w-7xl */
|
||||
|
||||
/* Theme transition */
|
||||
--theme-transition: background-color 300ms ease, color 300ms ease, border-color 300ms ease;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
DARK MODE TOKENS (legacy aliases)
|
||||
Full dark palette is in design-tokens.css html.dark block.
|
||||
These aliases keep existing components working without changes.
|
||||
============================================================ */
|
||||
html.dark {
|
||||
/* Surface */
|
||||
--color-surface: #0f172a;
|
||||
--color-surface-alt: #1e293b;
|
||||
|
||||
/* Borders */
|
||||
--color-border: #334155;
|
||||
--color-border-strong: #475569;
|
||||
|
||||
/* Text */
|
||||
--color-text-primary: #f1f5f9;
|
||||
--color-text-secondary: #cbd5e1;
|
||||
--color-text-muted: #94a3b8;
|
||||
--color-text-inverse: #0f172a;
|
||||
|
||||
/* Brand colors — brighter on dark backgrounds */
|
||||
--color-primary: var(--palette-primary-400); /* #22d3ee */
|
||||
--color-primary-dark: var(--palette-primary-300);
|
||||
--color-primary-light: var(--palette-primary-300);
|
||||
--color-accent: var(--palette-accent-400); /* #fbbf24 */
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
@@ -66,7 +100,8 @@
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-white text-secondary-800 antialiased;
|
||||
@apply bg-white text-secondary-800 antialiased dark:bg-secondary-900 dark:text-secondary-100;
|
||||
transition: var(--theme-transition);
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@@ -105,13 +140,13 @@
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
@apply bg-secondary-100;
|
||||
@apply bg-secondary-100 dark:bg-secondary-800;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
@apply bg-secondary-300 rounded-full;
|
||||
@apply bg-secondary-300 dark:bg-secondary-600 rounded-full;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
@apply bg-secondary-400;
|
||||
@apply bg-secondary-400 dark:bg-secondary-500;
|
||||
}
|
||||
|
||||
/* Reduced motion */
|
||||
@@ -126,6 +161,10 @@
|
||||
html {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
/* Suppress theme-transition color animations for vestibular disorder users */
|
||||
body {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,11 +200,13 @@
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply inline-flex items-center justify-center rounded-lg border-2 border-secondary bg-transparent px-6 py-3 font-semibold text-secondary transition-colors hover:bg-secondary hover:text-white focus:outline-none focus:ring-2 focus:ring-secondary-400 focus:ring-offset-2;
|
||||
/* ring-secondary-600 vs white offset = 6.6:1 (AAA). dark:ring-secondary-400 = 5.4:1 on dark bg. */
|
||||
@apply inline-flex items-center justify-center rounded-lg border-2 border-secondary bg-transparent px-6 py-3 font-semibold text-secondary transition-colors hover:bg-secondary hover:text-white focus:outline-none focus:ring-2 focus:ring-secondary-600 focus:ring-offset-2 dark:border-secondary-400 dark:text-secondary-300 dark:hover:bg-secondary-700 dark:hover:text-white dark:focus:ring-secondary-400 dark:focus:ring-offset-secondary-900;
|
||||
}
|
||||
|
||||
.btn-accent {
|
||||
@apply inline-flex items-center justify-center rounded-lg bg-accent px-6 py-3 font-semibold text-white transition-colors hover:bg-accent-600 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2;
|
||||
/* text-secondary-900 on accent-500 = 4.6:1 (AA). ring-accent-700 vs white offset = 7.4:1 (AAA). */
|
||||
@apply inline-flex items-center justify-center rounded-lg bg-accent px-6 py-3 font-semibold text-secondary-900 transition-colors hover:bg-accent-600 focus:outline-none focus:ring-2 focus:ring-accent-700 focus:ring-offset-2;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
@@ -201,7 +242,7 @@
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
@apply badge bg-primary-50 text-primary-700;
|
||||
@apply badge bg-primary-50 text-primary-700 dark:bg-primary-900/40 dark:text-primary-300;
|
||||
}
|
||||
|
||||
.badge-primary-dark {
|
||||
@@ -209,45 +250,46 @@
|
||||
}
|
||||
|
||||
.badge-accent {
|
||||
@apply badge bg-accent-50 text-accent-700;
|
||||
@apply badge bg-accent-50 text-accent-700 dark:bg-accent-900/40 dark:text-accent-300;
|
||||
}
|
||||
|
||||
.badge-secondary {
|
||||
@apply badge bg-secondary-100 text-secondary-700;
|
||||
@apply badge bg-secondary-100 text-secondary-700 dark:bg-secondary-800 dark:text-secondary-300;
|
||||
}
|
||||
|
||||
/* ----- Form Elements ----- */
|
||||
.form-input {
|
||||
@apply w-full px-4 py-3 rounded-lg border border-secondary-300 focus:border-primary focus:ring-2 focus:ring-primary/20 transition-colors duration-200 text-secondary-900 placeholder-secondary-400 bg-white;
|
||||
/* dark:placeholder-secondary-400 = #94a3b8 on #1e293b = 5.4:1 (AA). ring/40 improves focus visibility. */
|
||||
@apply w-full px-4 py-3 rounded-lg border border-secondary-300 focus:border-primary focus:ring-2 focus:ring-primary/40 transition-colors duration-200 text-secondary-900 placeholder-secondary-400 bg-white dark:bg-secondary-800 dark:border-secondary-600 dark:text-secondary-100 dark:placeholder-secondary-400 dark:focus:border-primary-400 dark:focus:ring-primary-400/40;
|
||||
}
|
||||
|
||||
.form-input-error {
|
||||
@apply border-red-500 focus:border-red-500 focus:ring-red-500/20;
|
||||
@apply border-red-500 focus:border-red-500 focus:ring-red-500/20 dark:border-red-400 dark:focus:border-red-400 dark:focus:ring-red-400/20;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
@apply block text-sm font-medium text-secondary-700 mb-2;
|
||||
@apply block text-sm font-medium text-secondary-700 mb-2 dark:text-secondary-300;
|
||||
}
|
||||
|
||||
.form-error {
|
||||
@apply mt-1 text-sm text-red-500 hidden;
|
||||
@apply mt-1 text-sm text-red-500 dark:text-red-400 hidden;
|
||||
}
|
||||
|
||||
/* ----- Cards ----- */
|
||||
.card {
|
||||
@apply bg-white rounded-2xl border-2 border-secondary-100 transition-all duration-500;
|
||||
@apply bg-white dark:bg-secondary-800 rounded-2xl border-2 border-secondary-100 dark:border-secondary-700 transition-all duration-500;
|
||||
}
|
||||
|
||||
.card-hover {
|
||||
@apply card hover:border-primary/30 hover:shadow-2xl hover:-translate-y-2;
|
||||
@apply card hover:border-primary/30 dark:hover:border-primary-500/40 hover:shadow-2xl hover:-translate-y-2;
|
||||
}
|
||||
|
||||
.card-service {
|
||||
@apply bg-white rounded-3xl shadow-lg border-2 border-secondary-100 hover:border-primary-400 hover:shadow-2xl transition-all duration-500;
|
||||
@apply bg-white dark:bg-secondary-800 rounded-3xl shadow-lg border-2 border-secondary-100 dark:border-secondary-700 hover:border-primary-400 dark:hover:border-primary-500 hover:shadow-2xl transition-all duration-500;
|
||||
}
|
||||
|
||||
.card-surface {
|
||||
@apply bg-secondary-50 rounded-xl border border-secondary-200 hover:shadow-lg transition-shadow duration-300;
|
||||
@apply bg-secondary-50 dark:bg-secondary-800 rounded-xl border border-secondary-200 dark:border-secondary-700 hover:shadow-lg transition-shadow duration-300;
|
||||
}
|
||||
|
||||
/* ----- Icon Containers ----- */
|
||||
@@ -273,7 +315,7 @@
|
||||
}
|
||||
|
||||
.section-title {
|
||||
@apply text-4xl sm:text-5xl font-bold text-secondary-900 mb-6;
|
||||
@apply text-4xl sm:text-5xl font-bold text-secondary-900 dark:text-secondary-50 mb-6;
|
||||
}
|
||||
|
||||
.section-title-inverse {
|
||||
@@ -281,7 +323,7 @@
|
||||
}
|
||||
|
||||
.section-description {
|
||||
@apply text-xl text-secondary-600;
|
||||
@apply text-xl text-secondary-600 dark:text-secondary-400;
|
||||
}
|
||||
|
||||
.section-description-inverse {
|
||||
@@ -313,7 +355,7 @@
|
||||
|
||||
/* ----- Feature List Item ----- */
|
||||
.feature-item {
|
||||
@apply flex items-center text-secondary-700;
|
||||
@apply flex items-center text-secondary-700 dark:text-secondary-300;
|
||||
}
|
||||
|
||||
/* ----- Gradient Text ----- */
|
||||
@@ -344,6 +386,7 @@
|
||||
[data-animate].is-visible {
|
||||
opacity: 1;
|
||||
transform: none !important;
|
||||
will-change: auto; /* Release GPU layer after animation completes */
|
||||
}
|
||||
|
||||
/* Animation variants */
|
||||
@@ -537,7 +580,7 @@
|
||||
}
|
||||
|
||||
.bg-surface-gradient {
|
||||
@apply bg-gradient-to-b from-secondary-50 to-white;
|
||||
@apply bg-gradient-to-b from-secondary-50 to-white dark:from-secondary-900 dark:to-secondary-950;
|
||||
}
|
||||
|
||||
/* Tabular number rendering for stats/counters */
|
||||
|
||||
Reference in New Issue
Block a user