# Styles

Components in this section are **headless** — they ship with no CSS. The `elements-kit/ui/styles` layer is an *optional* theme package on top. Skip it entirely and style with your own system, or import only the pieces you want.

> Core components don't depend on these styles. Importing `theme.css` is a choice, not a requirement.

## Install

The token layer is color-agnostic: `styles.css` bundles every structural token (radius, space, scaling, typography, shadow, material, cursor) plus the `unset` reset in one import, and you add a **neutral** and an **accent** on top. Nothing is grayscale-by-default — you pick the palette.

```ts
// Structural tokens + reset (one import):
import "elements-kit/ui/styles.css";

// A neutral scale (pick one):
import "elements-kit/ui/styles/palette/slate.css";
import "elements-kit/ui/styles/neutral/slate.css";

// An accent scale (any color):
import "elements-kit/ui/styles/accent/neutral.css";
```

Then **activate them once on your root** — accent/neutral only apply inside `data-accent` / `data-neutral`, so set them high up and every component below is styled with no per-element attributes:

```html
<html data-accent="neutral" data-neutral="slate">
```

```ts
// Or hand-pick individual token files instead of the barrel:
import "elements-kit/ui/styles/typography.css";
import "elements-kit/ui/styles/radius.css";
import "elements-kit/ui/styles/unset.css";
import "elements-kit/ui/styles/palette/blue.css";
import "elements-kit/ui/styles/accent/blue.css";
```

> `styles.css` carries no color. Colors need **both** the imported scales **and** a matching `data-accent` / `data-neutral` on an ancestor (the accent/neutral files only map their tokens inside `[data-accent="…"]` / `[data-neutral="…"]`) — set them once on `<html>`. Without an active accent, `--accent-*` / `--neutral-*` are undefined and components render uncolored. Radius, size, and each component's default variant/size need no color and work from `styles.css` alone.

## Theming via data attributes

Switches are `data-*` attributes on a root container — not classes you toggle, not a JS provider.

```html
<body
  class="dark"
  data-radius="medium"
  data-scaling="md"
  data-material-background="translucent"
  data-accent="iris"
  data-neutral="slate"
>
  ...
</body>
```

| Attribute                  | Values                                                 |
| -------------------------- | ------------------------------------------------------ |
| `data-radius`              | `none` · `small` · `medium` · `large` · `pill`         |
| `data-scaling`             | `xs` · `sm` · `md` · `lg` · `xl`                       |
| `data-material-background` | `solid` · `translucent`                                |
| `data-accent`              | accent name — see [accent list](#customization)        |
| `data-neutral`             | `gray` · `mauve` · `olive` · `sage` · `sand` · `slate` |

## Light & dark

Color tokens flip when the container has `.dark` or `.dark-theme`. `.light` / `.light-theme` opt back in.

```html
<html class="dark">...</html>
```

Pair with [`createMediaQuery`](/primitives/browser-state#createmediaquery) to follow the OS preference:

```ts
import { createMediaQuery } from "elements-kit/utilities/media-query";
import { effect } from "elements-kit/signals";

const prefersDark = createMediaQuery("(prefers-color-scheme: dark)");
effect(() => {
  document.documentElement.classList.toggle("dark", prefersDark());
});
```

## Token reference

Override any token by re-declaring on `:root` or any container.

### Color

Semantic — read these in your component CSS:

* `--color-background`
* `--color-overlay`
* `--color-material-solid`, `--color-material-translucent`, `--color-material`, `--backdrop-filter-material`
* `--color-surface`
* `--color-transparent`
* `--focus-1`..`--focus-12`, `--focus-a1`..`--focus-a12` (alias of the active color)

Scales:

* `--neutral-1`..`--neutral-12` plus `--neutral-a1`..`--neutral-a12` — the active neutral (set by [`neutral/<scale>.css`](https://github.com/elements-kit/elements-kit/tree/main/src/ui/styles/neutral) or `data-neutral`).
* `--accent-1`..`--accent-12` plus `--accent-a1`..`--accent-a12` — the active accent (set by [`accent/<color>.css`](https://github.com/elements-kit/elements-kit/tree/main/src/ui/styles/accent) or `data-accent`).
* `--<color>-1`..`--<color>-12` plus alpha — raw palette scales from [`palette/<color>.css`](https://github.com/elements-kit/elements-kit/tree/main/src/ui/styles/palette), e.g. `--blue-9`.
* `--black-a1`..`--black-a12` and `--white-a1`..`--white-a12` — alpha-on-color scales from `palette/black-alpha.css` / `palette/white-alpha.css` (auto-imported by `theme.css`).

### Typography

`--font-size-0`..`--font-size-9` (`0` is 10px, for captions under an icon in stacked buttons, toggles and segmented controls only), `--line-height-1`..`9`, `--letter-spacing-1`..`9`, plus weights `--font-weight-{light,regular,medium,bold}`. Per-element families and overrides (`--heading-*`, `--code-*`, `--strong-*`, `--em-*`, `--quote-*`, `--tab-*`) live in [`typography.css`](https://github.com/elements-kit/elements-kit/blob/main/src/ui/styles/typography.css).

### Radius

`--radius-1`..`--radius-6`, `--radius-pill`, `--radius-thumb`. All scale with `--radius-factor` (driven by `data-radius`) and `--scaling`. `radius.css` sets the `medium` values at `:root`, so radius resolves even without a `data-radius` ancestor; set `data-radius` to override.

### Spacing

`--space-1` (4px) · `--space-2` (8px) · `--space-3` (12px) · `--space-4` (16px) · `--space-5` (24px) · `--space-6` (32px) · `--space-7` (40px) · `--space-8` (48px) · `--space-9` (64px). Each multiplied by `--scaling`.

### Shadow

`--shadow-1`..`--shadow-6`. Light/dark variants ship out of the box, with a `color-mix(in oklab, ...)` upgrade for browsers that support it.

### Cursor

`--cursor-button`, `--cursor-checkbox`, `--cursor-link`, `--cursor-disabled`, `--cursor-menu-item`, `--cursor-radio`, `--cursor-slider-thumb`, `--cursor-slider-thumb-active`, `--cursor-switch`. Defaults are platform-native; override per-element if you want a `pointer` button.

## Unset native styles

Native form and text elements — `<button>`, `<input>`, `<a>`, `<h1>`–`<h6>`, lists, tables, `<svg>`, `<img>` — ship with browser defaults that bleed through component styles (gray button background, default font, list bullets, etc.). Apply `class="unset"` from [`unset.css`](https://github.com/elements-kit/elements-kit/blob/main/src/ui/styles/unset.css) to neutralise them in one line:

```html
<button class="unset x-button" data-variant="solid" data-size="2">
  Click me
</button>
```

`unset` uses `:where(...)` everywhere so it has zero specificity — your component classes (`.x-button`, `.x-checkbox`, …) and your own overrides always win.

Composite components in this kit (Button, future Checkbox, Switch, Listbox…) all rely on it. If you skip the import, native button rendering will leak through `.x-button` styling.

## Customization

Override any token at any level. Container-scoped overrides win over `:root`:

```css
.brand-card {
  --color-material-solid: var(--accent-2);
  --radius-3: var(--radius-5);
  background: var(--color-material);
  border-radius: var(--radius-3);
  padding: var(--space-4);
}
```

To swap the active accent, import a different `accent/<color>.css`:

```ts
// Replace this …
import "elements-kit/ui/styles/accent/neutral.css";
// … with this.
import "elements-kit/ui/styles/accent/iris.css";
```

Available accents: `amber`, `blue`, `bronze`, `brown`, `crimson`, `cyan`, `gold`, `grass`, `green`, `indigo`, `iris`, `jade`, `lime`, `mint`, `orange`, `pink`, `plum`, `purple`, `red`, `ruby`, `sky`, `teal`, `tomato`, `violet`, `yellow`. Plus semantic aliases that point at the active neutral or a fixed hue: `neutral`, `info`, `success`, `warning`, `danger`.

Available neutral scales (pick one): `gray`, `mauve`, `olive`, `sage`, `sand`, `slate`.
