---
title: Themes and design
description: The token-driven design system behind every surface, the four themes, and the places you can explore both.
sidebar:
  order: 14
---

The product's look is one coherent system: semantic design tokens, a small set of
typefaces, and themes that flip the whole palette at once.

## Four themes

The theme picker at the bottom of the sidebar switches between four palettes:

<CardGroup cols={2}>
  <Card title="Light" icon="sun">
    The light palette: white surfaces over `#f7f7f7` / `#ebebeb` neutrals, with
    the `#3392ff` accent.
  </Card>
  <Card title="Midnight" icon="moon">
    The default. A dark gray ramp: `#121212` canvas, `#171717` chrome, `#262626`
    raised surfaces, `#fafafa` primary text, the same `#3392ff` accent.
  </Card>
  <Card title="Aura" icon="sparkles">
    A violet dark ramp: a vivid-violet accent over a violet-tinted canvas.
  </Card>
  <Card title="Harbor" icon="anchor">
    A deep blue-slate dark ramp with a soft periwinkle accent.
  </Card>
</CardGroup>

A theme is applied wholesale through semantic tokens rather than per-component
overrides, so switching palettes recolors the entire app consistently. Components
reference tokens like a strong-text or a canvas-surface role, and the active theme
supplies the values. The user menu additionally carries a Dark-mode switch that
flips between Light and Midnight with a View Transition reveal.

## The token foundation

The app runs on a light-first token architecture:

- **`:root` holds the light token set.** The `dark`, `aura`, and `harbor`
  classes override the same semantic slots, so a component never keys on a
  theme name (`frontend/app/globals.css`).
- **Primitives live in `frontend/styles/theme.css`.** An accent ramp
  (`--color-accent-50` through `-950`) defaults to the blue primitive at
  `#3392ff`, and the neutral overrides are `#f7f7f7`, `#ebebeb`, and `#121212`.
  Interactive surfaces reference `accent-*` rather than a raw hue, so the whole
  system re-tints by overriding eleven variables.
- **The type ramp lives in `frontend/styles/typography.css`.** Each style
  registers a composite text utility (`text-body-medium`,
  `text-title-1-semibold`, `text-caption-2-bold`, ...) that applies size, line
  height, tracking, and weight in one class. The entire ramp is Inter.
- **Native base primitives.** 26 component families under
  `frontend/components/base/**` (buttons, dropdown, switch, tabs, table, date
  picker, the thinking orb, ...), plus larger application blocks under
  `components/application/**`. The legacy vendored kit in `components/ui`
  keeps working through a compat token bridge in `globals.css`.

## Typography

Three typefaces cover three roles:

| Role | Typeface |
| --- | --- |
| Page-hero display (the top-level page heading only) | Inter Tight (`--font-display`) |
| All other headings, body, and UI | Inter, via the type ramp |
| Code and technical labels | JetBrains Mono |

The display face is used sparingly: section headings, card titles, navigation,
and body text all stay in Inter.

## Explore it

Two surfaces let you see the system directly:

- **`/foundation`** is the foundation smoke page: button variants, input, badge,
  switch, tab menus, and the brand motion primitives, with a theme toggle so the
  foundation can be proven to render in both themes.
- **`/lab`** is the component lab: the vendored component library, the AI kit, and
  timeline samples. `/lab/session` renders one synthetic session through the real
  timeline components, so every canonical event type can be reviewed on a single
  page, and `/lab/workspace` shows the workpiece editor surfaces in context.

:::note
The UI has two component layers. The native base kit under `components/base`
uses named single-component exports (`import { Switch } from
'@/components/base/switch/switch'`); the legacy vendored kit under
`components/ui` survives behind namespace imports (`import * as Input from
'@/components/ui/input'`), with neutral names rather than any vendor's product
name. New surfaces compose `components/base`. Styling is token-driven in both
layers, so there are no per-component dark-mode branches to keep in sync.
:::

## Why a component lab

The lab is not decoration. Because the timeline must render every event type
correctly for every engine, `/lab/session` gives a single page where a synthetic
run exercises the whole grammar. It is where a rendering regression is caught
before it reaches a real session.
