# Theming

Override CSS custom properties to rebrand every kai-* component — colors, radii, typography, and dark mode — without touching component code.

Set the **`--kai-color-*`** tokens on `:root` to rebrand every `kai-*` web component at once. Inherited custom properties pierce the Shadow DOM boundary, so a single CSS rule propagates into all of them with no stylesheet import.

> **caution:** 
Each element adopts the kit's compiled CSS into its own shadow root, and that sheet declares every `--color-*` on `:host` as `var(--kai-color-<name>, <default>)`. A declaration on the host beats a value inherited from the page, so overriding **`--color-primary` on `:root` does not retheme a `kai-*` element** — importing `theme.css` doesn't change that. `--kai-color-*` is the layer the elements read.

The unprefixed `--color-*` names still matter: they are what `theme.css` / `theme.tokens.css` define for **your own host-page chrome and the light-DOM SolidJS components**, which have no shadow root. Both walkthroughs are below.

## How tokens work

The kit's appearance is driven entirely by **CSS custom properties** defined in `theme.css`. Each token follows a semantic naming convention borrowed from shadcn/ui — names describe purpose (`--color-primary`), not hue (`--color-blue`) — and surface/text pairs come together:

| Token pair | Controls |
|---|---|
| `--color-background` / `--color-foreground` | Page/chat surface and text |
| `--color-primary` / `--color-primary-foreground` | Buttons, active states, accents |
| `--color-secondary` / `--color-secondary-foreground` | Secondary buttons, chips |
| `--color-muted` / `--color-muted-foreground` | Subdued surfaces and placeholder text |
| `--color-card` / `--color-card-foreground` | Message bubbles, panels |
| `--color-border` | Dividers and input outlines |
| `--color-input` | Input field background |
| `--color-destructive` / `--color-destructive-foreground` | Error and danger states |
| `--color-ring` | Focus ring (blue by default for WCAG AA contrast) |
| `--color-sidebar` | Conversation sidebar background |
| `--color-code-foreground` | Inline code text and chip accent |

Border radii are controlled by `--radius` (default `0.6rem`); `--radius-sm`, `--radius-md`, `--radius-lg`, and `--radius-xl` derive from it automatically.

## Import the stylesheet

The kit injects its own scoped CSS into each component's Shadow DOM automatically — the `kai-*` elements need no import at all. Import `theme.css` when you want the same `--color-*` tokens for your own markup or for the light-DOM SolidJS components:

```js

```

Or via CDN:

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kitn.ai/ui/theme.css">
```

> **caution:** 
The components need no CSS import - they are shadow-isolated. Import `theme.css` only for the shadcn-style unprefixed `--color-*` path. In a Tailwind v4 app those generic names merge into your `@theme` and can override your own `bg-primary`, `bg-card`, and friends (last import wins). Prefer the namespaced `--kai-color-*` tokens below (no import), or - if you do import `theme.css` - import it **before** your own token overrides.

## Override tokens

Set your overrides on `:root` **after** importing `theme.css`. This is the host-page layer — your own markup and the light-DOM Solid components. To retheme the `kai-*` elements, use the [`--kai-color-*` form](#namespaced-overrides---kai-color-) instead; every token below has one.

```css
:root {
  --color-background: hsl(0 0% 6%);
  --color-foreground: hsl(0 0% 96%);
  --color-primary: hsl(271 91% 65%);
  --color-primary-foreground: hsl(0 0% 100%);
  --color-muted: hsl(0 0% 12%);
  --color-muted-foreground: hsl(0 0% 55%);
  --color-border: hsl(0 0% 16%);
  --color-card: hsl(0 0% 10%);
  --color-card-foreground: hsl(0 0% 96%);
  --radius: 0.5rem;
}
```

> **tip:** 
Assign tokens to a container element instead of `:root` to theme only that section of the page — useful when the kit sits alongside other UI that shouldn't change.

```css
.my-chat-panel {
  --color-primary: hsl(271 91% 65%);
  --color-background: hsl(0 0% 6%);
}
```

## Dark mode

Every `kai-*` element carries a `theme` attribute — `'light' | 'dark' | 'auto'`, defaulting to **`auto`**. On `auto` the element watches `prefers-color-scheme` itself and applies the kit's dark tokens inside its own shadow root, so OS dark mode works with no wiring:

```html
<kai-chat></kai-chat>                <!-- follows the OS -->
<kai-chat theme="dark"></kai-chat>   <!-- pinned dark -->
```

For your own markup and the light-DOM Solid components, toggle the `dark` class on `<html>` (or any ancestor):

```js
document.documentElement.classList.toggle('dark');
```

The `.dark` selector in `theme.css` redefines every `--color-*` token for dark surfaces. Override inside `.dark` to customize the dark-mode palette:

```css
:root {
  --color-primary: hsl(271 91% 65%);     /* light mode */
}

.dark {
  --color-primary: hsl(271 91% 75%);     /* dark mode — brighter for contrast */
}
```

> **note:** 
The kit never adds `.dark` to your `<html>` — your page's chrome is yours. It only syncs the elements, each of which follows `prefers-color-scheme` on its own while `theme` is `auto`. Pin an element with `theme="light"` / `theme="dark"` when your app owns the choice, and mirror the media query onto your own markup:

```js
const mq = window.matchMedia('(prefers-color-scheme: dark)');
mq.addEventListener('change', (e) => {
  document.documentElement.classList.toggle('dark', e.matches);
});
document.documentElement.classList.toggle('dark', mq.matches);
```

## Namespaced overrides (`--kai-color-*`)

Every `--color-*` token resolves through a **`--kai-color-*` alias** before falling back to its default. Override the `--kai-color-*` form to rebrand without importing or redefining the entire `theme.css` token set:

```css
:root {
  --kai-color-primary: hsl(271 91% 65%);
  --kai-color-primary-foreground: hsl(0 0% 100%);
  --kai-radius: 0.375rem;
}
```

This is the lightest-weight override path — no stylesheet import needed.

## Typography

The kit exposes four namespaced typography tokens. Override them to adjust the size of UI chrome (labels, badges, controls) globally:

| Token | Default | Applies to |
|---|---|---|
| `--kai-text-caption` | `0.6875rem` | Micro labels, badges, sub-counts |
| `--kai-text-meta` | `0.75rem` | Controls, toggles, captions |
| `--kai-text-body` | `0.875rem` | Primary reading text |
| `--kai-text-title` | `1rem` | Emphasis, headers |

```css
:root {
  --kai-text-body: 0.9375rem;   /* bump reading text to 15px */
}
```

Message and markdown reading size scales separately via the `proseSize` prop — see [Appearance settings](#appearance-settings) below.

## Appearance settings

Non-color appearance is controlled by `kai-chat` attributes (and the matching `ChatConfig` props in the SolidJS layer):

| Setting | Values | Purpose |
|---|---|---|
| `proseSize` | `xs` · `sm` · `base` · `lg` | Message / markdown text size |
| `codeTheme` | any [Shiki theme name](https://shiki.style/themes) | Syntax-highlight theme for code blocks |
| `codeHighlight` | `true` / `false` | Disable code highlighting entirely (no Shiki loaded) |

<Tabs>
<TabItem label="Web component">
```html
<kai-chat prose-size="base" code-theme="github-dark-dimmed"></kai-chat>
```
</TabItem>
<TabItem label="SolidJS">
```tsx

<ChatConfig proseSize="base" codeTheme="github-dark-dimmed">
  {/* your components */}
</ChatConfig>
```
</TabItem>
</Tabs>

## Token reference

The full list of overridable tokens lives in `theme.css` (shipped at `@kitn.ai/ui/theme.css`). For a browser-ready version with `:root` and `.dark` blocks pre-separated, use `@kitn.ai/ui/theme.tokens.css` — it is auto-generated from `theme.css` and never drifts.
