# 02. Theme System — Auto-Shifting CSS with ShieldAI Brand Palette meta: id: shieldai-unified-restructure-02 feature: shieldai-unified-restructure priority: P0 depends_on: [shieldai-unified-restructure-01] tags: [frontend, design-system, css, theme] objective: - Create a comprehensive, auto-shifting CSS theme system for the web app using Tailwind v4 `@theme` and CSS custom properties with `@property` animations, adapted from the Lendair reference but using a ShieldAI-appropriate brand palette. deliverables: - `web/src/app.css` — Complete theme file with: - `@property` declarations for all animatable color tokens - `:root` light-mode color tokens (backgrounds, text, brand, borders, semantic, glass) - `@media (prefers-color-scheme: dark)` dark-mode overrides - `:root.light` and `:root.dark` manual override classes - `@theme` block registering all tokens for Tailwind v4 - Base styles (`html`, `body`, `*:focus-visible`) - Utility classes (gradients, glassmorphism, gradient text, glow shadows, dot-grid background, noise texture) - Global background dot-grid pattern and smooth 500ms color transitions - Typography scale using Inter font family - Spacing and radius scale aligned with Lendair's design steps: 1. Copy the Lendair `app.css` structure from `~/code/Lendair/web/src/app.css` as the scaffold. 2. Replace the brand color tokens with ShieldAI palette: - Primary: deep indigo `#4f46e5` (brand-primary), light `#818cf8` (brand-primary-light), dark `#4338ca` (brand-primary-dark) - Accent: electric cyan `#06b6d4` (brand-accent), light `#67e8f9` (brand-accent-light), dark `#0891b2` (brand-accent-dark) - Alert/Danger: amber `#f59e0b` (warning), red `#ef4444` (error) - Keep neutral grays from Lendair for backgrounds and text 3. Add `@property` declarations for every custom property that should animate smoothly. 4. Define `@theme` block with all tokens so Tailwind v4 utility classes resolve correctly. 5. Implement `prefers-color-scheme: dark` media query with full dark palette. 6. Add `.light` and `.dark` classes on `:root` for manual JS toggling. 7. Define utility classes: - `.gradient-primary`, `.gradient-accent`, `.gradient-subtle`, `.gradient-card` - `.glass`, `.glass-dark` - `.text-gradient-primary`, `.text-gradient-accent` - `.shadow-glow-primary`, `.shadow-glow-accent` - `.bg-dot-grid`, `.bg-noise` 8. Set global `background-color`, `background-image` (dot-grid), and `transition` on `:root` and `body`. 9. Import the CSS in `web/src/entry-client.tsx` or `web/src/app.tsx` (whichever is the root). 10. Create a small `useTheme()` hook in `web/src/lib/theme.ts` that detects `prefers-color-scheme`, exposes `theme` signal, and toggles `.light`/`.dark` on `document.documentElement`. tests: - Unit: `useTheme()` hook returns correct initial theme based on media query; toggling updates class and signal - Visual: Open app in light and dark OS modes; verify all colors shift smoothly over 500ms - Visual: Toggle theme manually via `useTheme()`; verify override persists across reloads (localStorage) acceptance_criteria: - [ ] All color tokens animate smoothly between light/dark modes - [ ] Tailwind utilities like `text-brand-primary`, `bg-bg-secondary`, `border-border` work correctly - [ ] Manual theme toggle (light/dark/system) functions and persists - [ ] Dot-grid background pattern renders correctly in both modes - [ ] No FOUC (flash of unstyled content) on initial load validation: - Open `http://localhost:3000` in browser DevTools - Toggle OS dark mode; verify background, text, and card colors shift - Run `document.documentElement.classList.add('dark')` in console; verify immediate dark mode - Check computed styles for `--color-bg` and confirm it matches token values notes: - Reference: `~/code/Lendair/web/src/app.css` — this is the exact structure we want, just with ShieldAI colors. - Tailwind v4 `@theme` is compile-time; changing tokens requires rebuild. Runtime theme switching uses CSS custom properties. - The `transition` on `:root` and `body` must include `background-color` and `color` for smooth shifts. - Consider adding a `theme-color` meta tag that updates with the theme for mobile browsers.