# CTM / Wall-E Light Mode Theme Design

## Goal

Add a first-class light theme to CTM and Wall-E without changing the default
experience. A user who never touches appearance settings should continue to see
the existing dark UI. A user who selects a theme should see that choice restored
after reload, restart, and across CTM browser tabs.

## Product Contract

- Default mode is `dark`.
- Supported user modes are `dark`, `light`, and `system`.
- `system` resolves from `prefers-color-scheme`, but it is never the default.
- Theme choice is a CTM UI preference stored in the existing `settings` table as
  `ui_theme_mode`.
- Browser startup uses `localStorage` as a pre-CSS bootstrap cache only. The DB
  remains the source of truth after CTM loads.
- Cross-tab updates use the existing `ui-prefs-changed` WebSocket broadcast.
- Terminal canvases and xterm layers follow the resolved app theme. Provider
  ANSI output is preserved through a theme-specific ANSI palette, so explicit
  red/green/diff colors still read correctly in either mode.

## UX Placement

Theme is an application preference, not a Wall-E provider setting. It belongs in
`Setup -> Advanced -> Appearance`, near other global CTM settings.

The control is a three-option segmented control:

- `Dark` - stable default, best for terminal-heavy sessions.
- `Light` - high-contrast daytime UI for CTM/Wall-E chrome.
- `System` - follows the OS setting.

Changing the selection applies immediately and saves in the background. The
status line should say `Saved` or `Unable to save` without blocking the UI. The
control should remain keyboard accessible and should not require a restart.

## Theme Architecture

The root element owns resolved theme state:

```html
<html data-theme-mode="light" data-theme="light">
```

`data-theme-mode` is the user's stored mode. `data-theme` is the effective
rendering mode after resolving `system`.

The CSS contract is semantic token first:

- Base tokens: `--bg`, `--bg-light`, `--bg-lighter`, `--fg`, `--fg-dim`,
  `--accent`, `--border`, status colors.
- Surface aliases: `--bg-card`, `--bg-panel`, `--bg-elevated`,
  `--hover-bg`, `--shadow-color`.
- Interaction aliases: `--accent-soft`, `--danger-soft`, `--warning-soft`,
  `--success-soft`, `--focus-ring`.

Terminal surfaces use the same resolved mode with dedicated tokens:
`--terminal-bg`, `--terminal-fg`, `--terminal-cursor`,
`--terminal-selection-bg`, and `--terminal-selection-fg`. JavaScript mirrors
those values into xterm's runtime theme object so existing terminals update
without a reload.

New UI should consume tokens, not hard-coded dark colors. Hard-coded provider
ANSI colors are only acceptable inside the xterm palette.

## Persistence Flow

1. Before CSS loads, a tiny inline boot script reads `localStorage.ctm.theme.mode`.
2. If the value is valid, the script applies the resolved theme to `<html>`.
   Missing or invalid values resolve to `dark`.
3. After WebSocket/bootstrap completes, `loadPrefs()` reads `ui_theme_mode` from
   `/api/settings?prefix=ui_`.
4. If the DB setting exists, CTM applies it and refreshes the local bootstrap
   cache.
5. When the user changes theme, CTM calls the existing `savePref('theme_mode',
   mode)`.
6. Other browser tabs receive `ui-prefs-changed` for `ui_theme_mode`, refetch
   settings, and apply the same mode without reloading.

## Accessibility Requirements

- Text contrast should meet WCAG AA on both dark and light surfaces.
- Active nav, selected tabs, and status chips must not rely on hue alone.
- Focus states use `--focus-ring` and remain visible on both themes.
- The segmented control must have `aria-pressed` or equivalent selected state.
- The setting must be usable by keyboard only.

## Test Matrix

Automated render coverage should capture these surfaces in both themes:

- Main sessions view: top bar, sidebar, active tabs, session toolbar.
- Terminal session: verify xterm/provider output follows the selected theme and
  remains stable.
- Conversation tab and review tab.
- Wall-E dashboard/chat/session cards.
- Setup page with the Appearance control.
- Menus/popovers: nav more, model picker or prompt dropdown where practical.
- Mobile viewport for app chrome and Wall-E/session surfaces.

Functional assertions:

- No setting -> `dark`.
- `light` persists through reload using DB-backed `ui_theme_mode`.
- `system` responds to `prefers-color-scheme`.
- Cross-tab `ui_theme_mode` broadcast updates other tabs.
- Terminal surfaces use the resolved theme palette and update in-place when the
  setting changes.

## Rollout Phases

1. Document the contract and risks.
2. Add theme bootstrap, state management, DB-backed preference wiring, and UI
   controls with dark as the default.
3. Migrate CTM/Wall-E/setup/review/conversation chrome to semantic tokens and
   add targeted light-mode overrides for legacy dark surfaces.
4. Add render tests with screenshot artifacts and focused persistence checks.
5. Run the screenshot-heavy suite, fix contrast/layout issues, and land on
   local `main`.

## Known Boundaries

- This is not a per-provider terminal profile editor. CTM controls the base
  xterm palette for `dark`, `light`, and `system`; provider TUIs can still emit
  their own ANSI colors inside that palette.
- This is not a per-session setting. Theme is global per CTM database.
- The localStorage value is a startup cache, not an independent preference store.
