fix(ui): neutralise dark theme — eliminate blue-shifted grays across all surfaces
Replace blue-shifted CSS variable values with balanced neutral RGB, add comprehensive dark-mode overrides for bg-gray-*, border-gray-*, text-gray-*, and their dark: variant forms. Remove light-mode text/border overrides that leaked into both modes. Replace hardcoded rgba(255,255,255,...) in component classes with CSS variable references. Merge duplicate fadeSlideIn keyframe into fadeSlideUp. Change .app-data-table overflow to clip for sticky compat. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+183
-84
@@ -108,16 +108,16 @@
|
||||
|
||||
.dark {
|
||||
color-scheme: dark;
|
||||
--surface-page: 10 10 12;
|
||||
--surface-card: 16 17 19;
|
||||
--surface-elevated: 22 23 26;
|
||||
--surface-input: 13 14 16;
|
||||
--border-subtle: 36 38 44;
|
||||
--border-input: 54 57 66;
|
||||
--text-primary: 237 242 247;
|
||||
--text-secondary: 196 207 223;
|
||||
--text-muted: 147 161 185;
|
||||
--text-very-muted: 118 133 161;
|
||||
--surface-page: 10 10 10;
|
||||
--surface-card: 17 17 17;
|
||||
--surface-elevated: 24 24 24;
|
||||
--surface-input: 14 14 14;
|
||||
--border-subtle: 38 38 38;
|
||||
--border-input: 58 58 58;
|
||||
--text-primary: 240 241 243;
|
||||
--text-secondary: 205 207 210;
|
||||
--text-muted: 158 160 164;
|
||||
--text-very-muted: 130 132 136;
|
||||
--shadow-soft: 0 0 0 / 0.45;
|
||||
--shadow-strong: 0 0 0 / 0.75;
|
||||
}
|
||||
@@ -143,7 +143,7 @@
|
||||
background-image:
|
||||
radial-gradient(ellipse 80% 50% at 50% -10%, rgba(var(--accent-400), 0.07) 0%, transparent 60%),
|
||||
radial-gradient(circle at top left, rgb(var(--accent-600) / 0.16), transparent 26rem),
|
||||
linear-gradient(180deg, rgb(15 23 42 / 0.35), transparent 28rem);
|
||||
linear-gradient(180deg, rgb(10 10 12 / 0.35), transparent 28rem);
|
||||
}
|
||||
|
||||
h1,
|
||||
@@ -220,6 +220,26 @@
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
}
|
||||
|
||||
.dark .bg-gray-200 {
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
}
|
||||
|
||||
.dark .bg-gray-300 {
|
||||
background-color: rgb(var(--border-subtle)) !important;
|
||||
}
|
||||
|
||||
.dark .bg-gray-400 {
|
||||
background-color: rgb(var(--border-input)) !important;
|
||||
}
|
||||
|
||||
.dark .bg-gray-500 {
|
||||
background-color: rgb(80 80 80) !important;
|
||||
}
|
||||
|
||||
.dark .bg-gray-600 {
|
||||
background-color: rgb(var(--border-input)) !important;
|
||||
}
|
||||
|
||||
.dark .border-gray-100 {
|
||||
border-color: rgb(var(--border-subtle)) !important;
|
||||
}
|
||||
@@ -256,31 +276,11 @@
|
||||
color: rgb(var(--text-very-muted)) !important;
|
||||
}
|
||||
|
||||
.text-gray-900 {
|
||||
color: rgb(var(--text-primary)) !important;
|
||||
}
|
||||
|
||||
.text-gray-800,
|
||||
.text-gray-700 {
|
||||
color: rgb(var(--text-secondary)) !important;
|
||||
}
|
||||
|
||||
.text-gray-600,
|
||||
.text-gray-500 {
|
||||
color: rgb(var(--text-muted)) !important;
|
||||
}
|
||||
|
||||
.text-gray-400 {
|
||||
color: rgb(var(--text-very-muted)) !important;
|
||||
}
|
||||
|
||||
.border-gray-200 {
|
||||
border-color: rgb(var(--border-subtle)) !important;
|
||||
}
|
||||
|
||||
.border-gray-300 {
|
||||
border-color: rgb(var(--border-input)) !important;
|
||||
}
|
||||
/* Dark variant text overrides — catches className="dark:text-gray-*" */
|
||||
.dark .dark\:text-gray-100 { color: rgb(var(--text-primary)) !important; }
|
||||
.dark .dark\:text-gray-200 { color: rgb(var(--text-secondary)) !important; }
|
||||
.dark .dark\:text-gray-300 { color: rgb(var(--text-muted)) !important; }
|
||||
.dark .dark\:text-gray-400 { color: rgb(var(--text-very-muted)) !important; }
|
||||
|
||||
.dark input,
|
||||
.dark select,
|
||||
@@ -295,15 +295,13 @@
|
||||
color: rgb(var(--text-muted));
|
||||
}
|
||||
|
||||
/* Table alternating / hover */
|
||||
.dark .hover\:bg-gray-50:hover {
|
||||
/* Table row / interactive hover */
|
||||
.dark .hover\:bg-gray-50:hover,
|
||||
.dark .hover\:bg-gray-100:hover,
|
||||
.dark .hover\:bg-gray-200:hover {
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
}
|
||||
|
||||
.dark .divide-gray-100 > * + * {
|
||||
border-color: rgb(var(--border-subtle)) !important;
|
||||
}
|
||||
|
||||
/* Status badge adjustments in dark mode - keep them readable */
|
||||
.dark .bg-green-100 {
|
||||
background-color: rgb(6 78 59 / 0.4) !important;
|
||||
@@ -332,12 +330,6 @@
|
||||
.dark .text-red-700 {
|
||||
color: rgb(248 113 113) !important;
|
||||
}
|
||||
.dark .bg-gray-100 {
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
}
|
||||
.dark .text-gray-700 {
|
||||
color: rgb(var(--text-secondary)) !important;
|
||||
}
|
||||
.dark .bg-purple-100 {
|
||||
background-color: rgb(76 29 149 / 0.4) !important;
|
||||
}
|
||||
@@ -402,24 +394,141 @@
|
||||
color: rgb(var(--text-primary));
|
||||
}
|
||||
|
||||
/* Divide override for gray-50 (ChargeabilityWidget sticky headers) */
|
||||
.dark .divide-gray-50 > * + * { border-color: rgb(var(--border-subtle)) !important; }
|
||||
/* Divide overrides */
|
||||
.dark .divide-gray-50 > * + *,
|
||||
.dark .divide-gray-100 > * + *,
|
||||
.dark .dark\:divide-gray-800 > * + * { border-color: rgb(var(--border-subtle)) !important; }
|
||||
|
||||
/* Slate-* normalization — map to CSS variable surfaces */
|
||||
.dark .bg-slate-700,
|
||||
.dark .bg-slate-800 {
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
COMPREHENSIVE DARK SURFACE NORMALIZATION
|
||||
Tailwind's gray-700/800/900 and slate-* palette is blue-shifted.
|
||||
In dark mode we remap all of these to our neutral CSS variable surfaces.
|
||||
|
||||
Tailwind v3 with darkMode:"class" generates selectors like:
|
||||
.dark .dark\:bg-gray-800 { background-color: rgb(31 41 55 / ...) }
|
||||
We override them here with neutral surfaces + !important.
|
||||
|
||||
Two forms per class:
|
||||
1. Plain — matches className="bg-gray-800" (no variant)
|
||||
2. dark\: — matches className="dark:bg-gray-800" (Tailwind dark variant)
|
||||
═══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* ── Light grays: gray-50 through gray-200 → elevated surface ──────────── */
|
||||
.dark .dark\:bg-gray-50,
|
||||
.dark .dark\:bg-gray-100,
|
||||
.dark .dark\:bg-gray-200 {
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
}
|
||||
.dark .bg-slate-900,
|
||||
.dark .bg-gray-900 {
|
||||
|
||||
/* ── Mid grays: gray-300 through gray-600 → border/mid tones ──────────── */
|
||||
.dark .dark\:bg-gray-300 {
|
||||
background-color: rgb(var(--border-subtle)) !important;
|
||||
}
|
||||
.dark .dark\:bg-gray-400,
|
||||
.dark .dark\:bg-gray-600 {
|
||||
background-color: rgb(var(--border-input)) !important;
|
||||
}
|
||||
.dark .dark\:bg-gray-500 {
|
||||
background-color: rgb(80 80 80) !important;
|
||||
}
|
||||
|
||||
/* ── Elevated surface: gray-700, gray-800, slate-700, slate-800 ─────────── */
|
||||
.dark .bg-gray-700, .dark .dark\:bg-gray-700,
|
||||
.dark .bg-gray-800, .dark .dark\:bg-gray-800,
|
||||
.dark .bg-slate-700, .dark .dark\:bg-slate-700,
|
||||
.dark .bg-slate-800, .dark .dark\:bg-slate-800 {
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
}
|
||||
|
||||
/* ── Card surface: gray-900, slate-900, slate-950 ───────────────────────── */
|
||||
.dark .bg-gray-900, .dark .dark\:bg-gray-900,
|
||||
.dark .bg-slate-900, .dark .dark\:bg-slate-900,
|
||||
.dark .bg-slate-950, .dark .dark\:bg-slate-950 {
|
||||
background-color: rgb(var(--surface-card)) !important;
|
||||
}
|
||||
.dark .border-slate-800,
|
||||
.dark .border-slate-700 {
|
||||
|
||||
/* ── Opacity variants: elevated surface (/95 → /20) ────────────────────── */
|
||||
.dark .bg-gray-700\/95, .dark .dark\:bg-gray-700\/95,
|
||||
.dark .bg-gray-700\/80, .dark .dark\:bg-gray-700\/80,
|
||||
.dark .bg-gray-700\/70, .dark .dark\:bg-gray-700\/70,
|
||||
.dark .bg-gray-700\/60, .dark .dark\:bg-gray-700\/60,
|
||||
.dark .bg-gray-700\/50, .dark .dark\:bg-gray-700\/50,
|
||||
.dark .bg-gray-700\/40, .dark .dark\:bg-gray-700\/40,
|
||||
.dark .bg-gray-800\/95, .dark .dark\:bg-gray-800\/95,
|
||||
.dark .bg-gray-800\/80, .dark .dark\:bg-gray-800\/80,
|
||||
.dark .bg-gray-800\/70, .dark .dark\:bg-gray-800\/70,
|
||||
.dark .bg-gray-800\/60, .dark .dark\:bg-gray-800\/60,
|
||||
.dark .bg-gray-800\/50, .dark .dark\:bg-gray-800\/50,
|
||||
.dark .bg-gray-800\/40, .dark .dark\:bg-gray-800\/40,
|
||||
.dark .bg-gray-800\/30, .dark .dark\:bg-gray-800\/30,
|
||||
.dark .bg-slate-700\/95, .dark .dark\:bg-slate-700\/95,
|
||||
.dark .bg-slate-700\/80, .dark .dark\:bg-slate-700\/80,
|
||||
.dark .bg-slate-700\/70, .dark .dark\:bg-slate-700\/70,
|
||||
.dark .bg-slate-700\/60, .dark .dark\:bg-slate-700\/60,
|
||||
.dark .bg-slate-700\/50, .dark .dark\:bg-slate-700\/50,
|
||||
.dark .bg-slate-800\/95, .dark .dark\:bg-slate-800\/95,
|
||||
.dark .bg-slate-800\/80, .dark .dark\:bg-slate-800\/80,
|
||||
.dark .bg-slate-800\/70, .dark .dark\:bg-slate-800\/70,
|
||||
.dark .bg-slate-800\/60, .dark .dark\:bg-slate-800\/60,
|
||||
.dark .bg-slate-800\/50, .dark .dark\:bg-slate-800\/50 {
|
||||
background-color: rgb(var(--surface-elevated) / 0.9) !important;
|
||||
}
|
||||
|
||||
/* ── Opacity variants: card surface (/95 → /20) ─────────────────────────── */
|
||||
.dark .bg-gray-900\/95, .dark .dark\:bg-gray-900\/95,
|
||||
.dark .bg-gray-900\/70, .dark .dark\:bg-gray-900\/70,
|
||||
.dark .bg-gray-900\/60, .dark .dark\:bg-gray-900\/60,
|
||||
.dark .bg-gray-900\/50, .dark .dark\:bg-gray-900\/50,
|
||||
.dark .bg-gray-900\/40, .dark .dark\:bg-gray-900\/40,
|
||||
.dark .bg-gray-900\/30, .dark .dark\:bg-gray-900\/30,
|
||||
.dark .bg-gray-900\/25, .dark .dark\:bg-gray-900\/25,
|
||||
.dark .bg-gray-900\/20, .dark .dark\:bg-gray-900\/20,
|
||||
.dark .bg-slate-900\/95, .dark .dark\:bg-slate-900\/95,
|
||||
.dark .bg-slate-900\/70, .dark .dark\:bg-slate-900\/70,
|
||||
.dark .bg-slate-900\/60, .dark .dark\:bg-slate-900\/60,
|
||||
.dark .bg-slate-900\/50, .dark .dark\:bg-slate-900\/50,
|
||||
.dark .bg-slate-900\/40, .dark .dark\:bg-slate-900\/40,
|
||||
.dark .bg-slate-900\/30, .dark .dark\:bg-slate-900\/30,
|
||||
.dark .bg-slate-950\/95, .dark .dark\:bg-slate-950\/95,
|
||||
.dark .bg-slate-950\/70, .dark .dark\:bg-slate-950\/70,
|
||||
.dark .bg-slate-950\/60, .dark .dark\:bg-slate-950\/60,
|
||||
.dark .bg-slate-950\/40, .dark .dark\:bg-slate-950\/40 {
|
||||
background-color: rgb(var(--surface-card) / 0.9) !important;
|
||||
}
|
||||
|
||||
/* ── Hover state overrides ──────────────────────────────────────────────── */
|
||||
.dark .hover\:bg-gray-700:hover, .dark .dark\:hover\:bg-gray-700:hover,
|
||||
.dark .hover\:bg-gray-800:hover, .dark .dark\:hover\:bg-gray-800:hover,
|
||||
.dark .hover\:bg-slate-700:hover, .dark .dark\:hover\:bg-slate-700:hover,
|
||||
.dark .hover\:bg-slate-800:hover, .dark .dark\:hover\:bg-slate-800:hover {
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
}
|
||||
.dark .hover\:bg-gray-900:hover, .dark .dark\:hover\:bg-gray-900:hover,
|
||||
.dark .hover\:bg-slate-900:hover, .dark .dark\:hover\:bg-slate-900:hover {
|
||||
background-color: rgb(var(--surface-card)) !important;
|
||||
}
|
||||
|
||||
/* ── Hover opacity variants ────────────────────────────────────────────── */
|
||||
.dark .dark\:hover\:bg-gray-800\/50:hover,
|
||||
.dark .dark\:hover\:bg-gray-800\/30:hover,
|
||||
.dark .dark\:hover\:bg-gray-700\/50:hover {
|
||||
background-color: rgb(var(--surface-elevated) / 0.5) !important;
|
||||
}
|
||||
|
||||
/* ── Border normalization ───────────────────────────────────────────────── */
|
||||
.dark .border-gray-600, .dark .dark\:border-gray-600,
|
||||
.dark .border-gray-700, .dark .dark\:border-gray-700,
|
||||
.dark .border-gray-800, .dark .dark\:border-gray-800,
|
||||
.dark .border-slate-600, .dark .dark\:border-slate-600,
|
||||
.dark .border-slate-700, .dark .dark\:border-slate-700,
|
||||
.dark .border-slate-800, .dark .dark\:border-slate-800 {
|
||||
border-color: rgb(var(--border-subtle)) !important;
|
||||
}
|
||||
.dark .hover\:bg-slate-800:hover {
|
||||
background-color: rgb(var(--surface-elevated)) !important;
|
||||
|
||||
/* Border opacity variants */
|
||||
.dark .dark\:border-gray-700\/60,
|
||||
.dark .dark\:border-gray-700\/40 {
|
||||
border-color: rgb(var(--border-subtle) / 0.6) !important;
|
||||
}
|
||||
|
||||
/* Sidebar panel — overrides the hardcoded hex values in AppShell */
|
||||
@@ -496,7 +605,8 @@
|
||||
}
|
||||
|
||||
.app-data-table {
|
||||
@apply overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-sm;
|
||||
@apply rounded-2xl border border-gray-200 bg-white shadow-sm;
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
.app-data-table table {
|
||||
@@ -548,28 +658,28 @@
|
||||
|
||||
:is(.dark) .app-surface {
|
||||
background-color: rgb(var(--surface-card));
|
||||
background-image: linear-gradient(135deg, rgba(255,255,255,0.045) 0%, rgba(255,255,255,0.015) 100%);
|
||||
background-image: linear-gradient(135deg, rgb(var(--text-primary) / 0.045) 0%, rgb(var(--text-primary) / 0.015) 100%);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border-color: rgba(255,255,255,0.09);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.05), inset 0 1px 0 rgba(255,255,255,0.07);
|
||||
border-color: rgb(var(--border-subtle));
|
||||
box-shadow: 0 2px 8px rgb(0 0 0 / 0.4), 0 0 0 1px rgb(var(--border-subtle) / 0.5), inset 0 1px 0 rgb(var(--text-primary) / 0.07);
|
||||
}
|
||||
|
||||
:is(.dark) .app-surface-strong {
|
||||
background-color: rgb(var(--surface-card));
|
||||
background-image: linear-gradient(135deg, rgba(255,255,255,0.055) 0%, rgba(255,255,255,0.018) 100%);
|
||||
background-image: linear-gradient(135deg, rgb(var(--text-primary) / 0.055) 0%, rgb(var(--text-primary) / 0.018) 100%);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-color: rgba(255,255,255,0.10);
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.06), inset 0 1px 0 rgba(255,255,255,0.08);
|
||||
border-color: rgb(var(--border-subtle));
|
||||
box-shadow: 0 4px 16px rgb(0 0 0 / 0.5), 0 0 0 1px rgb(var(--border-subtle) / 0.6), inset 0 1px 0 rgb(var(--text-primary) / 0.08);
|
||||
}
|
||||
|
||||
:is(.dark) .app-toolbar {
|
||||
background: rgb(16 17 19 / 0.82);
|
||||
background: rgb(var(--surface-card) / 0.82);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-color: rgba(255,255,255,0.08);
|
||||
box-shadow: 0 1px 0 rgba(255,255,255,0.04);
|
||||
border-color: rgb(var(--border-subtle) / 0.6);
|
||||
box-shadow: 0 1px 0 rgb(var(--text-primary) / 0.04);
|
||||
}
|
||||
|
||||
:is(.dark) .app-input {
|
||||
@@ -616,7 +726,7 @@
|
||||
}
|
||||
|
||||
:is(.dark) .app-data-table thead tr {
|
||||
background: rgba(255,255,255,0.04);
|
||||
background-color: rgb(var(--surface-elevated));
|
||||
}
|
||||
|
||||
:is(.dark) .app-data-table th {
|
||||
@@ -716,25 +826,14 @@
|
||||
}
|
||||
|
||||
:is(.dark) .shimmer-skeleton {
|
||||
background: linear-gradient(90deg, rgba(255,255,255,0.04) 0%, rgba(255,255,255,0.09) 50%, rgba(255,255,255,0.04) 100%);
|
||||
background: linear-gradient(90deg, rgb(var(--text-primary) / 0.04) 0%, rgb(var(--text-primary) / 0.09) 50%, rgb(var(--text-primary) / 0.04) 100%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ─── Table row stagger entrance ─────────────────────────────────────────── */
|
||||
@keyframes fadeSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(6px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── Table row stagger entrance (reuses fadeSlideUp keyframes) ──────────── */
|
||||
.animate-row-enter {
|
||||
animation: fadeSlideIn 0.12s ease-out both;
|
||||
animation: fadeSlideUp 0.12s ease-out both;
|
||||
}
|
||||
|
||||
/* ─── Subtle hover lift for cards and table rows ─────────────────────────── */
|
||||
|
||||
Reference in New Issue
Block a user