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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user