Flat dark theme migration plan: CSS foundation, icon rail sidebar, ~130 file component sweep, landing page updates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
11 KiB
Design System v4 Migration — Flat Dark Theme
Goal: Migrate ResolutionFlow's frontend from glassmorphism/gradient aesthetic to a flat, high-contrast dark theme (Sentry/PostHog-inspired) with an icon rail sidebar, as defined in DESIGN-SYSTEM.md.
Scope
~130 files across 15+ directories use old design patterns (glass-card, bg-gradient-brand, text-gradient-brand, backdrop-filter: blur(), ambient orbs). All must be updated to the new flat dark system.
Approach
Foundation first, then sweep. Three phases:
- Phase 1: CSS Foundation — Rewrite
index.csstokens, remove old utilities, add new variables - Phase 2: Layout Shell — Icon rail sidebar + app layout restructure
- Phase 3: Component Sweep — Update all 132 files directory-by-directory
Each phase produces deployable commits. The app will look inconsistent during Phase 3 but will always be functional.
Phase 1: CSS Foundation
index.css @theme Block
Rewrite the @theme block with new color tokens matching DESIGN-SYSTEM.md:
Page background: #0c0d10 → --bg-page
Sidebar background: #0f1118 → --bg-sidebar
Card background: #14161d → --bg-card
Card hover: #191c25 → --bg-card-hover
Input background: #191c25 → --bg-input
Code background: #0e1017 → --bg-code
Elevated surface: #1c1f2a → --bg-elevated
Text heading: #f0f2f5 → --text-heading
Text primary: #e2e5eb → --text-primary
Text secondary: #848b9b → --text-secondary
Text muted: #4f5666 → --text-muted
Border default: #1e2130 → --border-default
Border hover: #2a2f3d → --border-hover
Accent: #22d3ee → --accent
Accent hover: #06b6d4 → --accent-hover
Accent dim (10%): rgba(34,211,238,0.10) → --accent-dim
Accent text: #67e8f9 → --accent-text
Success: #34d399 + dim at 10%
Warning: #fbbf24 + dim at 10%
Danger: #f87171 + dim at 10%
Rail label: #6b7280 → --text-rail-label
Variables Structure
All colors in :root (dark is default). Light mode values prepared as comments — implementing the toggle is a future follow-up that just adds a .light class block.
Compatibility Shims (Critical)
To avoid breaking the entire app while Phase 3 sweeps components, Phase 1 keeps the old utility class names as deprecated aliases mapping to the new values:
/* Deprecated — remove after Phase 3 sweep completes */
.glass-card, .glass-card-static { @apply bg-[var(--bg-card)] border border-[var(--border-default)] rounded-lg; }
.glass-card:hover { @apply border-[var(--border-hover)]; }
These shims are removed in a final cleanup commit after Phase 3 is complete.
Remove Old Utilities
Delete from index.css (after Phase 3 sweep — shims keep the app functional until then):
.glass-card,.glass-card-static,.glass-stat,.glass-card-glow.active-glow,.breatheGlowkeyframesbg-gradient-brand,text-gradient-brand,bg-gradient-brand-hover--glass-bg,--glass-border,--glass-blurvariables--shadow-float,--shadow-float-hover,--shadow-cyan-glowshadow variables- Atmosphere orb styles (
.atmosphere-orb) - Orchestrated page-load animation keyframes (slideDown, slideInLeft, fadeInUp, fadeInRight)
Rename
--font-label→--font-mono(JetBrains Mono, same font, clearer name)
Keep
- Google Fonts imports (same three fonts)
- React Flow import
- Tailwind v4
@themeapproach - Base animation keyframes:
fade-in,fade-in-up,slide-in-from-left,slide-in-from-bottom— all others removed (nobreatheGlow,bellWobble,slideDown, orchestrated page-load sequence)
New Base Classes
Add reusable component classes:
.card { /* bg-card, 1px border-default, 8px radius, no shadow */ }
.card-interactive { /* extends .card + hover border-hover transition */ }
.stat-card { /* extends .card + 3px left border */ }
.badge { /* 11px, pill shape, dim bg + matching text */ }
.btn-primary { /* solid accent, white text, 5px radius — NOTE: text changes from dark (#101114) to white */ }
.btn-ghost { /* transparent, 1px border, hover bg-elevated */ }
Implement each class per DESIGN-SYSTEM.md Component Patterns section for exact values.
Phase 2: Icon Rail Sidebar
New Component: IconRailSidebar
Replaces current Sidebar.tsx. Two states:
Icon Rail (72px, default):
bg-sidebarbackground, full viewport height- Logo mark at top: 30px cyan gradient square with lightning bolt
- Nav items: vertical column, 20px icon + 10px label underneath
- Horizontal dividers between sections (RESOLVE / KNOWLEDGE / INSIGHTS)
- User avatar at bottom
- Pin/expand toggle below avatar
- Active item:
accent-dimbackground,accent-texton icon + label
Hover Flyout (220px panel):
- Opens to the right of the hovered rail item with 150ms ease-out transition
- Also opens on keyboard focus/Enter for accessibility; closes on Escape or focus-out
- Shows sub-navigation for that section
- If section has many sub-items, flyout scrolls with
max-height: 70vh; overflow-y: auto bg-cardwithborder-defaultandbox-shadow: 0 4px 12px rgba(0,0,0,0.3)- Stays open while cursor is on rail item OR flyout panel
- Closes on mouse leave from both
Pinned State (260px full sidebar):
- Click pin → expands to traditional sidebar with text labels, section headers, badges
- 3px left accent bar on active item
- Unpin button in sidebar header
- Preference persisted in localStorage / userPreferences store
Mobile:
- Icon rail hidden below
smbreakpoint - Hamburger menu opens full overlay sidebar (same as pinned content)
Layout Changes
AppLayout.tsx CSS Grid:
- Default:
grid-template-columns: 72px 1fr - Pinned:
grid-template-columns: 260px 1fr - Mobile:
grid-template-columns: 1fr - CSS variable
--sidebar-wupdated accordingly (used by FlowPilotMessageBar, FlowPilotActionBar) - Ensure
--sidebar-wtransition is coordinated with sidebar width transition to prevent layout jump on pin/unpin
Sidebar commits: Phase 2 produces 2-3 commits (icon rail core, flyout behavior, pinned state + persistence).
BrandLogo Update
Replace current decision-tree icon SVG in BrandLogo.tsx with 30px gradient square (cyan, border-radius: 8px) + white lightning bolt mark. Wordmark: "ResolutionFlow" in Bricolage Grotesque 700, text-heading color (no gradient).
Files
| Action | File |
|---|---|
| Rewrite | frontend/src/components/layout/Sidebar.tsx → icon rail with flyout + pinned state |
| Modify | frontend/src/components/layout/AppLayout.tsx → grid columns, mobile handling |
| Modify | frontend/src/components/layout/TopBar.tsx → flat styling, remove blur |
| Keep | FlowPilotMessageBar.tsx, FlowPilotActionBar.tsx — left: var(--sidebar-w) still works |
Phase 3: Component Sweep
Pattern Replacement Map
| Old Pattern | New Pattern |
|---|---|
glass-card / glass-card-static |
bg-[var(--bg-card)] border border-[var(--border-default)] rounded-lg (or .card class) |
bg-gradient-brand |
bg-[var(--accent)] (solid cyan) |
text-gradient-brand |
text-[var(--accent-text)] |
bg-gradient-brand-hover |
hover:brightness-110 |
text-foreground |
text-[var(--text-primary)] |
text-muted-foreground |
text-[var(--text-secondary)] |
bg-background |
bg-[var(--bg-page)] |
bg-card (old token) |
bg-[var(--bg-card)] |
border-border |
border-[var(--border-default)] |
font-label (on code/monospace content) |
font-mono |
font-label (on labels/badges/timestamps) |
font-sans text-xs — inspect each usage |
backdrop-filter: blur(...) |
Remove |
shadow-lg shadow-primary/20 on buttons |
Remove |
rounded-[10px] / rounded-[16px] on cards |
rounded-lg (8px) |
scale(1.02) hover on cards |
Border color transition |
.atmosphere-orb elements |
Remove from JSX |
style={{ background: 'rgba(...)' }} glass surfaces |
Use CSS variable classes |
Sweep Order (one commit per directory group, ~10 commits total)
Phase 3 covers app components only; landing page is handled in Phase 4.
components/layout/(3 files) — AppLayout, TopBar, BrandLogocomponents/dashboard/(16 files) — highest visibilitycomponents/flowpilot/(12 files) — core productpages/(25 files) — all page componentscomponents/session/(8 files)components/script-builder/(4 files)components/kb-accelerator/(5 files)components/account/(4 files)components/tree-editor/(4 files)- All remaining directories (~51 files: admin, analytics, assistant, common, copilot, library, procedural, public, script-editor, ui)
What Stays the Same
- Component logic, state management, hooks, API calls — untouched
- Lucide icons — same
cn()utility — same- All non-design Tailwind utilities (flex, grid, padding, margin, etc.)
- React Router, Zustand stores, type definitions
Phase 4: Landing Page
- Remove ambient glow effects and gradient overlays from
landing.css - Hero: subtle radial gradient at 15% accent opacity (replaces heavy glow)
- Section labels: JetBrains Mono, 12px, uppercase, accent-text
- Section titles: Bricolage Grotesque,
clamp(28px, 4vw, 42px), weight 800 - Pricing cards: flat
bg-card+border-default, featured card gets accent border - Top nav: flat, no blur backdrop
- CTAs: solid accent buttons
- Product mockup: update screenshot to show new flat UI
Files: landing.css, LandingPage.tsx, landing-specific components
Phase 5: Cleanup & Documentation
- Remove compatibility shims from
index.css(deprecatedglass-cardaliases from Phase 1) - Update CLAUDE.md: verify branding section and design system section reflect the new flat theme (already partially done in the doc-swap commit — verify no stale references remain)
- Update
BrandWordmark.tsxif it referencestext-gradient-brand - Verify
npm run buildpasses with zero references to removed utilities
Light mode note: All colors use CSS custom properties. Light mode values from DESIGN-SYSTEM.md are stored as comments in index.css. Adding light mode later = add .light class values + toggle in user settings. Not implemented in this migration.
Out of Scope
- Light mode toggle (future follow-up — just variable swap + settings toggle)
- React Flow canvas theme updates (separate concern, works with any color scheme)
- Backend changes (none needed)
- New features or functionality (purely visual migration)
- Test changes (no visual tests exist)
Risk Mitigation
- Each phase produces deployable commits
- The app is functional throughout (just visually inconsistent during Phase 3)
- Old CSS utilities removed in Phase 1 — if a component breaks visually, it's obvious
npm run buildverified after each phase- No logic changes = no new bugs in functionality
Verification
After each phase:
npm run buildpasses- Visual spot-check of key pages (Dashboard, FlowPilot session, Script Builder, Landing)
After all phases:
- Full app walkthrough — every sidebar nav item
- Mobile responsive check (icon rail hidden, hamburger menu works)
- Landing page check
- FlowPilot session check (message bar, action bar positioning)