Complete frontend rewrite from vanilla HTML/CSS/JS to React 19 + TypeScript + Tailwind CSS v4. Frontend (frontend/commander-ai-lab-ui/): - Vite + React 19 + TypeScript + Tailwind CSS v4 + React Router - 7 pages: BatchSim, Collection, Decks, AutoGen, Simulator, Coach, Training - Reusable components: Spinner, StatusBadge, CardImage, ManaSymbols, EmptyState - Full typed API client layer (8 modules matching all backend endpoints) - Recharts for mana curves, win rate charts, progress bars - Lucide icons throughout - Custom dark theme with MTG mana color tokens - Code splitting (recharts + react in separate chunks) Backend (lab_api.py): - SPA-aware static file serving with catch-all for client-side routing - Fallback to legacy ui/ folder if React dist not built - Updated startup log with SPA route list Build system: - .gitignore added (was missing - removes pyc, db, node_modules, etc.) - build-full-installer-v2.py: v23 with Node.js check + React build step - Vite build config with manual chunks for optimal loading Also includes: V3 deck generator fixes, coach improvements, DeepSeek sim modules
115 lines
3.2 KiB
CSS
115 lines
3.2 KiB
CSS
@import "tailwindcss";
|
|
|
|
/* ═══════════════════════════════════════════════════════════
|
|
Commander AI Lab — Design Tokens (Tailwind v4 CSS Theme)
|
|
Fresh dark theme with MTG-inspired accents
|
|
═══════════════════════════════════════════════════════════ */
|
|
|
|
@theme {
|
|
/* ── Backgrounds ── */
|
|
--color-bg-primary: #0f1117;
|
|
--color-bg-secondary: #161921;
|
|
--color-bg-tertiary: #1c2030;
|
|
--color-bg-elevated: #222738;
|
|
--color-bg-hover: #2a3048;
|
|
|
|
/* ── Borders ── */
|
|
--color-border-primary: #2a2f42;
|
|
--color-border-secondary: #363c54;
|
|
--color-border-accent: #4f6ef7;
|
|
|
|
/* ── Text ── */
|
|
--color-text-primary: #e8eaf0;
|
|
--color-text-secondary: #9ba1b8;
|
|
--color-text-tertiary: #6b7190;
|
|
--color-text-inverse: #0f1117;
|
|
|
|
/* ── Accents ── */
|
|
--color-accent-blue: #4f6ef7;
|
|
--color-accent-blue-hover: #6b84ff;
|
|
--color-accent-teal: #2dd4bf;
|
|
--color-accent-teal-hover: #5eead4;
|
|
--color-accent-purple: #a78bfa;
|
|
--color-accent-amber: #fbbf24;
|
|
--color-accent-red: #f87171;
|
|
--color-accent-green: #4ade80;
|
|
|
|
/* ── MTG Mana Colors ── */
|
|
--color-mana-white: #f9faf4;
|
|
--color-mana-blue: #0e67ab;
|
|
--color-mana-black: #2b2424;
|
|
--color-mana-red: #d3202a;
|
|
--color-mana-green: #00733e;
|
|
--color-mana-colorless: #706f6f;
|
|
|
|
/* ── Status ── */
|
|
--color-status-success: #4ade80;
|
|
--color-status-warning: #fbbf24;
|
|
--color-status-error: #f87171;
|
|
--color-status-info: #60a5fa;
|
|
|
|
/* ── Radius ── */
|
|
--radius-sm: 0.375rem;
|
|
--radius-md: 0.5rem;
|
|
--radius-lg: 0.75rem;
|
|
--radius-xl: 1rem;
|
|
|
|
/* ── Shadows ── */
|
|
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
--shadow-glow-blue: 0 0 20px rgba(79, 110, 247, 0.15);
|
|
--shadow-glow-teal: 0 0 20px rgba(45, 212, 191, 0.15);
|
|
}
|
|
|
|
/* ── Base Styles ── */
|
|
html {
|
|
background-color: var(--color-bg-primary);
|
|
color: var(--color-text-primary);
|
|
}
|
|
|
|
body {
|
|
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
}
|
|
|
|
/* ── Scrollbar ── */
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: var(--color-bg-secondary);
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--color-border-secondary);
|
|
border-radius: 4px;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: var(--color-text-tertiary);
|
|
}
|
|
|
|
/* ── Utility animations ── */
|
|
@keyframes fade-in {
|
|
from { opacity: 0; transform: translateY(4px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
@keyframes pulse-glow {
|
|
0%, 100% { box-shadow: 0 0 0 0 rgba(79, 110, 247, 0.2); }
|
|
50% { box-shadow: 0 0 16px 4px rgba(79, 110, 247, 0.15); }
|
|
}
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
.animate-fade-in {
|
|
animation: fade-in 0.2s ease-out;
|
|
}
|
|
.animate-pulse-glow {
|
|
animation: pulse-glow 2s infinite;
|
|
}
|
|
.animate-spin {
|
|
animation: spin 1s linear infinite;
|
|
}
|