> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vendo.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Theme your Vendo surfaces

> The VendoTheme token shape extracted into .vendo/theme.json and consumed by every shipped chrome surface, including colors, radii, density, and motion.

Set colors, typography, radii, density, and motion once in
`.vendo/theme.json` (or a runtime `VendoProvider.theme` override), and every
shipped chrome surface, including the
[prewired primitives](/customize/host-components), picks them up automatically.
This page covers how to set the theme and see it flow through; the exact
token shape and CSS variable tables live in the reference section at the
end.

## Set the theme

`vendo init` extracts `.vendo/theme.json` and names it in the
`<VendoProvider theme={...}>` paste it prints. `vendo sync` regenerates the file on
each build, so a fresh install renders on brand without passing `theme` by
hand.

Pass partial runtime overrides through `VendoProvider.theme` when you want to
adjust tokens without touching the file. Shipped chrome derives its colors,
typography, radius, density, and motion from these tokens and does not
hardcode a Vendo brand.

Generation receives the same theme. Optional design rules add
generation-time guidance without changing runtime tokens: set
`createVendo({ apps: { designRules } })` in config, or keep a
`.vendo/design-rules.md` file, re-read per generation (a non-blank config
value wins over the file).

## See it flow through

`VendoProvider` emits stable CSS custom properties derived from `density` and
`motion`. Chrome and the prewired primitives read them directly, and you can
consume the same variables from your own styles. It also derives
`--vendo-color-scheme` from your background color and stamps a
`--fl-kb-inset` variable while the mobile takeover is open. All three are
covered in the reference below.

## Theme reference

### The VendoTheme shape

```ts theme={null}
export interface VendoTheme {
  colors: {
    background: string;
    surface: string;
    text: string;
    muted: string;
    accent: string;
    accentText: string;
    danger: string;
    border: string;
  };
  typography: {
    fontFamily: string;
    headingFamily?: string;
    baseSize: string;
  };
  radius: {
    small: string;
    medium: string;
    large: string;
  };
  density: "compact" | "comfortable";
  motion: "full" | "reduced";
}
```

### Density variables

`--vendo-density-*` names are stable: new variables may be added under this
prefix, but the ones below will not be renamed.

`density: "compact"` tightens control sizes, padding, and gaps; `density:
"comfortable"` relaxes them. Every compact value is less than or equal to
its comfortable counterpart.

| Variable                          | `compact`  | `comfortable` |
| --------------------------------- | ---------- | ------------- |
| `--vendo-density-control-height`  | `32px`     | `38px`        |
| `--vendo-density-control-padding` | `6px 10px` | `9px 12px`    |
| `--vendo-density-card-padding`    | `12px`     | `16px`        |
| `--vendo-density-content-gap`     | `7px`      | `10px`        |
| `--vendo-density-inline-gap`      | `5px`      | `7px`         |
| `--vendo-density-field-gap`       | `4px`      | `6px`         |
| `--vendo-density-table-padding`   | `7px 10px` | `10px 12px`   |
| `--vendo-density-badge-height`    | `20px`     | `24px`        |
| `--vendo-density-badge-padding`   | `3px 7px`  | `5px 9px`     |
| `--vendo-density-stat-padding`    | `9px 11px` | `12px 14px`   |
| `--vendo-density-tabs-padding`    | `3px`      | `4px`         |
| `--vendo-density-tab-height`      | `26px`     | `30px`        |
| `--vendo-density-tab-padding`     | `4px 8px`  | `6px 10px`    |

### Color scheme

`VendoProvider` derives `color-scheme` from the WCAG relative luminance of
`colors.background` and exposes it as `--vendo-color-scheme`. Backgrounds
below the flip point (L \< 0.179) resolve to `dark`; everything else,
including unparseable values, resolves to `light`.

| Variable               | Light background | Dark background |
| ---------------------- | ---------------- | --------------- |
| `--vendo-color-scheme` | `light`          | `dark`          |

Chrome uses this variable to activate `light-dark()` branches, so a
dark-brand host automatically gets the dark chrome treatment without any
extra configuration. Set `colors.background` in `.vendo/theme.json` (or
through a `VendoProvider.theme` override) and the scheme follows.

```json .vendo/theme.json theme={null}
{
  "colors": {
    "background": "#14151a",
    "surface": "#1b1c22",
    "text": "#f5f5f7"
  }
}
```

Reference `--vendo-color-scheme` from your own styles if you want custom
surfaces to track the same flip:

```css theme={null}
.my-card {
  color-scheme: var(--vendo-color-scheme);
}
```

### Motion

`motion: "reduced"` collapses `--vendo-motion-duration` to `0ms` so chrome
respects user reduced-motion preferences. The easing curve stays constant.

| Variable                  | `full`                           | `reduced`                        |
| ------------------------- | -------------------------------- | -------------------------------- |
| `--vendo-motion-duration` | `160ms`                          | `0ms`                            |
| `--vendo-motion-easing`   | `cubic-bezier(0.2, 0.8, 0.2, 1)` | `cubic-bezier(0.2, 0.8, 0.2, 1)` |

Reference the variables from your own CSS to keep custom surfaces in sync
with the current theme:

```css theme={null}
.my-card {
  padding: var(--vendo-density-card-padding);
  transition:
    background-color var(--vendo-motion-duration)
    var(--vendo-motion-easing);
}
```

### Mobile takeover

Shipped overlay and palette chrome switch to a full-viewport takeover
at viewports 767px wide and narrower. The takeover covers the host layout
instead of docking inside a squeezed column and portals to `document.body`
so transformed host ancestors cannot confine it. It honors iOS safe-area
insets on all four edges. On touch devices (`pointer: coarse`), the composer
and palette search render at 16px to prevent iOS auto-zoom, and icon buttons
and the overlay close control expand to a 44px touch target. Desktop chrome
is unchanged.

The takeover surface stamps a stable `--fl-kb-inset` CSS variable derived
from `visualViewport` so the composer lifts above the on-screen keyboard.
Read it from your own styles if you render a custom surface inside a
takeover:

```css theme={null}
.my-mobile-footer {
  padding-bottom: calc(
    env(safe-area-inset-bottom, 0px) + var(--fl-kb-inset, 0px)
  );
}
```

`--fl-kb-inset` is `0px` when no keyboard is open and outside of takeover mode.
