# Ticket 10.1 — Theme System

**Phase**: 10 — Feature Parity Enhancements
**Priority**: High
**Depends on**: None

## Description

Implement a comprehensive theme system with multiple bundled themes and support for user custom themes. claude-relay ships 22 Base16 themes (Catppuccin, Dracula, Gruvbox, Nord, One Dark, Rose Pine, Solarized, Tokyo Night, etc.) with instant loading from localStorage (no FOUC), terminal color sync, and mermaid diagram theme sync. conduit currently has only hardcoded light-mode HSL colors with no theme switching.

The system should:

- Include 8–12 curated Base16 themes (light + dark variants)
- Support user custom themes loaded from `~/.conduit/themes/`
- Generate CSS custom properties from Base16 color palette
- Sync theme to xterm.js terminal colors
- Sync theme to mermaid diagram rendering
- Cache selected theme in localStorage and apply before first paint (prevent FOUC)
- Provide a theme picker UI in the sidebar footer or settings
- Detect light/dark variant from the palette luminance

## Acceptance Criteria

### AC1: Theme picker shows available themes
```gherkin
Given the user opens the theme picker in the sidebar footer
When the picker is displayed
Then it lists all bundled themes (8–12) and any user custom themes from ~/.conduit/themes/
  And each theme shows a colour swatch preview
  And clicking a theme applies it immediately without page reload
```

### AC2: Selected theme persists across reloads
```gherkin
Given the user has selected the "Dracula" theme
When the user reloads the page
Then the "Dracula" theme is loaded from localStorage
  And the UI renders with Dracula colours
```

### AC3: No flash of unstyled content (FOUC prevention)
```gherkin
Given a theme is saved in localStorage
When the page loads
Then a blocking inline script applies CSS custom properties before first paint
  And no default/fallback theme is visible before the saved theme renders
```

### AC4: Terminal colors sync with theme
```gherkin
Given the user switches from "Nord" to "Solarized Light"
When the theme change is applied
Then the xterm.js terminal updates its foreground, background, cursor, and ANSI palette
  And existing terminal content re-renders with the new colours
```

### AC5: Mermaid diagrams re-render with matching theme
```gherkin
Given a chat message contains a mermaid diagram
When the user switches themes
Then the mermaid diagram re-renders using colours derived from the active Base16 palette
  And the diagram background matches the theme's background colour
```

### AC6: User custom themes from filesystem
```gherkin
Given a valid Base16 JSON file exists at ~/.conduit/themes/my-custom.json
When the user opens the theme picker
Then "my-custom" appears in the theme list alongside bundled themes
  And selecting it applies the custom colour palette
```

### AC7: Light/dark variant detection
```gherkin
Given a Base16 theme with a dark background (base00 luminance < 0.5)
When the theme is applied
Then the system sets a "dark" variant class on the document root
  And scrollbar colours, selection highlights, and other variant-sensitive styles adapt accordingly

Given a Base16 theme with a light background (base00 luminance >= 0.5)
When the theme is applied
Then the system sets a "light" variant class on the document root
  And variant-sensitive styles adapt for light backgrounds
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| Base16-to-CSS variable computation | Unit | Given a Base16 palette object, produces correct `--base00` through `--base0F` CSS custom property values and derived semantic variables (e.g., `--bg`, `--fg`, `--accent`) |
| Light/dark variant detection | Unit | Correctly classifies palettes by computing relative luminance of `base00`; dark when < 0.5, light when >= 0.5 |
| Theme loading and validation | Unit | Parses valid Base16 JSON, rejects malformed files (missing keys, invalid hex), returns typed theme object |
| Bundled theme registry | Unit | All bundled themes load without error and pass validation; count matches expected 8–12 |
| Theme picker UI interaction | E2E | Opening picker shows all themes; clicking a theme updates CSS variables on `:root`; picker dismisses on selection |
| localStorage persistence and FOUC prevention | E2E | After selecting a theme and reloading, no default-theme flash occurs; `localStorage.getItem("theme")` matches selection |
| Terminal colour sync | E2E | After theme switch, `Terminal.options.theme` matches the new palette's ANSI colour mapping |
| Custom theme directory scanning | Unit | Scans `~/.conduit/themes/`, filters to `.json` files, parses and returns valid themes, skips invalid files with warning |

## Reference

- claude-relay theme engine: `../claude-relay/lib/public/modules/theme.js` (~622 lines)
- claude-relay bundled themes: `../claude-relay/lib/themes/` (22 JSON files)
- Current hardcoded colours: `conduit/src/lib/public/style.css` (HSL values)
- xterm.js theme API: `ITheme` interface on Terminal options
- Base16 spec: https://github.com/chriskempson/base16
