refactor: rewrite CSS foundation for Design System v4

New flat dark color tokens, remove glass/gradient utilities,
add compatibility shims for phased migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Chihlas
2026-03-22 00:19:21 -04:00
parent 6efabff090
commit 0499284679

View File

@@ -8,186 +8,104 @@
@import '@xyflow/react/dist/style.css';
@theme {
/* ── Brand tokens ─────────────────────────────────── */
--color-brand-gradient-from: oklch(0.65 0.13 195); /* #06b6d4 cyan-500 */
--color-brand-gradient-to: oklch(0.74 0.12 195); /* #22d3ee cyan-400 */
--color-brand-dark: oklch(0.145 0.013 264); /* #101114 */
--color-brand-dark-card: oklch(0.17 0.01 264); /* #14161a */
--color-brand-dark-surface: oklch(0.17 0.01 264); /* #14161a */
--color-brand-text-primary: oklch(0.98 0.005 264); /* #f8fafc */
--color-brand-text-secondary: oklch(0.63 0.02 260); /* #8891a0 */
--color-brand-text-muted: oklch(0.45 0.015 260); /* #5a6170 */
--color-brand-border: oklch(0.35 0 0 / 0.06);
/* ── Surface colors ────────────────────────────── */
--color-bg-page: #0c0d10;
--color-bg-sidebar: #0f1118;
--color-bg-card: #14161d;
--color-bg-card-hover: #191c25;
--color-bg-input: #191c25;
--color-bg-code: #0e1017;
--color-bg-elevated: #1c1f2a;
/* ── Semantic color tokens (OKLCH, direct values) ── */
--color-background: oklch(0.145 0.013 264); /* dark charcoal #101114 */
--color-foreground: oklch(0.98 0.005 264); /* near-white #f8fafc */
/* ── Text colors ───────────────────────────────── */
--color-text-heading: #f0f2f5;
--color-text-primary: #e2e5eb;
--color-text-secondary: #848b9b;
--color-text-muted: #4f5666;
--color-text-rail-label: #6b7280;
--color-card: oklch(0.178 0.008 264); /* #17191d */
--color-card-foreground: oklch(0.98 0.005 264);
/* ── Border colors ─────────────────────────────── */
--color-border-default: #1e2130;
--color-border-hover: #2a2f3d;
--color-popover: oklch(0.178 0.008 264);
--color-popover-foreground: oklch(0.98 0.005 264);
/* ── Accent (cyan) ─────────────────────────────── */
--color-accent: #22d3ee;
--color-accent-hover: #06b6d4;
--color-accent-dim: rgba(34,211,238,0.10);
--color-accent-text: #67e8f9;
--color-primary: oklch(0.65 0.13 195); /* cyan #1ea8c4 */
--color-primary-foreground: oklch(0.145 0.013 264); /* dark bg for contrast */
/* ── Semantic colors ───────────────────────────── */
--color-success: #34d399;
--color-success-dim: rgba(52,211,153,0.10);
--color-warning: #fbbf24;
--color-warning-dim: rgba(251,191,36,0.10);
--color-danger: #f87171;
--color-danger-dim: rgba(248,113,113,0.10);
--color-secondary: oklch(0.22 0.008 264); /* #212329 */
--color-secondary-foreground: oklch(0.98 0.005 264);
/* ── Tailwind semantic mappings ─────────────────── */
--color-background: #0c0d10;
--color-foreground: #e2e5eb;
--color-card: #14161d;
--color-card-foreground: #e2e5eb;
--color-popover: #14161d;
--color-popover-foreground: #e2e5eb;
--color-primary: #22d3ee;
--color-primary-foreground: #ffffff;
--color-secondary: #1c1f2a;
--color-secondary-foreground: #e2e5eb;
--color-muted: #1c1f2a;
--color-muted-foreground: #848b9b;
--color-accent-tw: #1c1f2a;
--color-accent-foreground: #e2e5eb;
--color-destructive: #f87171;
--color-destructive-foreground: #ffffff;
--color-border: #1e2130;
--color-input: #191c25;
--color-ring: #22d3ee;
--color-muted: oklch(0.22 0.008 264);
--color-muted-foreground: oklch(0.63 0.02 260); /* #8891a0 */
/* ── Radii ─────────────────────────────────────── */
--radius-sm: 5px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--color-accent: oklch(0.22 0.008 264);
--color-accent-foreground: oklch(0.98 0.005 264);
--color-destructive: oklch(0.55 0.22 15); /* rose #e63359 */
--color-destructive-foreground: oklch(0.98 0.005 264);
--color-border: oklch(0.22 0.008 264);
--color-input: oklch(0.22 0.008 264);
--color-ring: oklch(0.65 0.13 195); /* cyan, matches primary */
/* ── Radii ───────────────────────────────────────── */
--radius-sm: 0.5rem;
--radius-md: 0.625rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
/* ── Fonts ───────────────────────────────────────── */
--font-sans:
'IBM Plex Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, sans-serif;
/* ── Fonts ─────────────────────────────────────── */
--font-sans: 'IBM Plex Sans', system-ui, -apple-system, sans-serif;
--font-heading: 'Bricolage Grotesque', system-ui, sans-serif;
--font-label: 'JetBrains Mono', monospace;
--font-mono: 'JetBrains Mono', monospace;
--font-label: 'JetBrains Mono', monospace; /* deprecated alias — remove in Phase 5 */
/* ── Gradients ───────────────────────────────────── */
--background-image-gradient-brand: linear-gradient(
135deg,
oklch(0.65 0.13 195) 0%,
oklch(0.74 0.12 195) 100%
);
--background-image-gradient-brand-hover: linear-gradient(
135deg,
oklch(0.58 0.12 195) 0%,
oklch(0.65 0.13 195) 100%
);
/* ── Animations (keyframes inside @theme) ────────── */
/* ── Animations ────────────────────────────────── */
--animate-fade-in: fade-in 200ms ease-out;
--animate-fade-in-up: fade-in-up 200ms ease-out;
--animate-slide-in-left: slide-in-from-left 200ms ease-out;
--animate-slide-in-bottom: slide-in-from-bottom 200ms ease-out;
--animate-scale-in: scale-in 150ms ease-out;
--animate-slide-down: slideDown 400ms ease-out;
--animate-slide-in-right: slideInRight 300ms ease-out;
--animate-fade-in-right: fadeInRight 400ms ease-out;
--animate-breathe-glow: breatheGlow 3s ease-in-out infinite alternate;
--animate-bell-wobble: bellWobble 500ms ease-in-out;
--animate-fade: fadeIn 300ms ease forwards;
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
from { opacity: 0; } to { opacity: 1; }
}
@keyframes fade-in-up {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); }
}
@keyframes slide-in-from-left {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
from { transform: translateX(-100%); } to { transform: translateX(0); }
}
@keyframes slide-in-from-bottom {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); }
}
@keyframes scale-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); }
}
@keyframes slideDown {
from { transform: translateY(-100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes slideInRight {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes fadeInRight {
from { transform: translateX(30px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes breatheGlow {
from {
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
0 0 20px oklch(0.65 0.13 195 / 0.04);
}
to {
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
0 0 30px oklch(0.65 0.13 195 / 0.12);
}
}
@keyframes bellWobble {
0% { transform: rotate(0deg); }
20% { transform: rotate(8deg); }
40% { transform: rotate(-6deg); }
60% { transform: rotate(4deg); }
80% { transform: rotate(-2deg); }
100% { transform: rotate(0deg); }
}
@keyframes pulse-dot {
0%, 100% { box-shadow: 0 0 4px rgba(52,211,153,0.4); }
50% { box-shadow: 0 0 8px rgba(52,211,153,0.7); }
}
@keyframes stagger-fade-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); }
}
}
/* ── Root CSS variables (non-theme: glass, shadows, layout) ── */
:root {
/* App Shell tokens */
--sidebar-w: 260px;
--sidebar-bg: oklch(0.13 0.013 264);
--sidebar-hover: var(--color-secondary);
--sidebar-active: oklch(0.65 0.13 195 / 0.10);
--text-dimmed: oklch(0.42 0.015 260);
/* Glass system */
--glass-bg: oklch(0.16 0.01 264 / 0.55);
--glass-bg-hover: oklch(0.16 0.01 264 / 0.7);
--glass-border: oklch(1 0 0 / 0.06);
--glass-border-hover: oklch(1 0 0 / 0.12);
--glass-blur: blur(16px);
--glass-blur-strong: blur(20px);
--glass-blur-light: blur(12px);
/* Shadow system */
--shadow-float: 0 8px 32px rgba(0, 0, 0, 0.3);
--shadow-float-hover: 0 12px 40px rgba(0, 0, 0, 0.4), 0 0 0 1px oklch(1 0 0 / 0.08);
--shadow-cyan-glow: 0 8px 32px oklch(0.65 0.13 195 / 0.08);
/* Easing */
--sidebar-w: 72px;
--sidebar-w-pinned: 260px;
--ease-out-smooth: cubic-bezier(0.4, 0, 0.2, 1);
}
@@ -224,52 +142,91 @@
}
}
/* ── Custom utilities ────────────────────────────────── */
@utility btn-press {
@apply active:scale-[0.98] transition-transform;
}
@utility text-gradient-brand {
@apply bg-gradient-brand bg-clip-text text-transparent;
}
/* ── Deprecated shims — remove after Phase 3 sweep ── */
@utility glass-card {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: 16px;
box-shadow: var(--shadow-float);
transition:
transform 200ms var(--ease-out-smooth),
border-color 200ms var(--ease-out-smooth),
box-shadow 200ms var(--ease-out-smooth);
background: var(--color-bg-card);
border: 1px solid var(--color-border-default);
border-radius: 8px;
transition: border-color 200ms ease;
&:hover {
transform: scale(1.02);
border-color: var(--glass-border-hover);
box-shadow: var(--shadow-float-hover);
border-color: var(--color-border-hover);
}
}
@utility glass-card-static {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border);
border-radius: 16px;
box-shadow: var(--shadow-float);
background: var(--color-bg-card);
border: 1px solid var(--color-border-default);
border-radius: 8px;
}
@utility text-gradient-brand {
color: var(--color-accent-text);
}
@utility active-glow {
animation: breatheGlow 3s ease-in-out infinite alternate;
/* glow removed in v4 — kept as no-op shim */
--_active-glow: 1;
}
@utility bg-gradient-brand-hover {
&:hover { filter: brightness(1.1); }
}
@utility stagger-item {
opacity: 0;
animation: stagger-fade-in 350ms var(--ease-out-smooth) forwards;
animation: fadeIn 350ms var(--ease-out-smooth) forwards;
animation-delay: calc(var(--stagger-index, 0) * 50ms);
}
@utility btn-press {
@apply active:scale-[0.98] transition-transform;
}
/* ── New component classes (Design System v4) ───── */
@utility card-flat {
background: var(--color-bg-card);
border: 1px solid var(--color-border-default);
border-radius: 8px;
}
@utility card-interactive {
background: var(--color-bg-card);
border: 1px solid var(--color-border-default);
border-radius: 8px;
transition: border-color 200ms ease;
&:hover {
border-color: var(--color-border-hover);
}
}
@utility btn-primary-v4 {
background: var(--color-accent);
color: #ffffff;
font-weight: 550;
border-radius: 5px;
padding: 9px 16px;
font-size: 13px;
transition: filter 150ms ease;
&:hover {
filter: brightness(1.1);
}
}
@utility btn-ghost-v4 {
background: transparent;
color: var(--color-text-secondary);
border: 1px solid var(--color-border-default);
border-radius: 5px;
padding: 9px 16px;
font-size: 13px;
transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
&:hover {
background: var(--color-bg-elevated);
color: var(--color-text-primary);
border-color: var(--color-border-hover);
}
}
@utility rdp-custom {
@apply text-foreground;
& .rdp-month { @apply w-full; }
@@ -294,12 +251,16 @@
.app-shell {
display: grid;
grid-template-columns: var(--sidebar-w) 1fr;
grid-template-rows: 56px 1fr;
grid-template-rows: auto 1fr;
height: 100vh;
overflow: hidden;
transition: grid-template-columns 200ms ease;
}
.app-shell--pinned {
--sidebar-w: 260px;
}
.app-shell--collapsed {
grid-template-columns: 56px 1fr;
}
@@ -387,7 +348,7 @@
/* ── React Flow dark theme overrides ─────────────────── */
/* React Flow v12 uses --xy-* CSS custom properties for theming.
Override the defaults to match our Slate & Ice design system. */
Override the defaults to match our design system. */
.react-flow.dark {
--xy-background-color-default: transparent;
--xy-edge-stroke-default: var(--color-border);
@@ -400,7 +361,7 @@
--xy-handle-background-color-default: var(--color-border);
--xy-handle-border-color-default: var(--color-card);
--xy-minimap-background-color-default: var(--color-card);
--xy-minimap-mask-background-color-default: oklch(0.22 0.008 264 / 0.6);
--xy-minimap-mask-background-color-default: rgba(28, 31, 42, 0.6);
--xy-controls-button-background-color-default: var(--color-card);
--xy-controls-button-background-color-hover-default: var(--color-accent);
--xy-controls-button-color-default: var(--color-muted-foreground);