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

# Style with host tokens

> Inherit the host's palette, type and spacing so your surface renders correctly in light and dark.

Your component mounts in a shadow root. The host's CSS variables inherit into it and your
CSS cannot leak out. Write every colour, radius and font as a variable with a fallback and
your surface follows the owner's theme with no theme code.

```css theme={null}
.funnel-note {
  color: var(--fg-muted, rgba(18, 18, 18, 0.6));
  border-top: 1px solid var(--divider, rgba(18, 18, 18, 0.12));
  border-radius: var(--tap-radius, 6px);
  font-family: var(--font-sans, system-ui, sans-serif);
}
```

Import that file from your entry. The build collects the stylesheets each entry reaches and
the host injects them into your shadow root, ahead of your component.

## The variables

| Variable                                     | Is                                                   |
| -------------------------------------------- | ---------------------------------------------------- |
| `--bg-base`, `--bg-subtle`, `--bg-raised`    | Page, quiet surface, raised surface                  |
| `--fg-default`, `--fg-muted`, `--fg-inverse` | Body text, secondary text, text on an inverse ground |
| `--tap-accent`, `--tap-accent-fg`            | The accent and the text that sits on it              |
| `--tap-danger`                               | Destructive text and borders                         |
| `--tap-scrim`                                | The wash behind a dialog or the expand panel         |
| `--tap-radius`, `--tap-space`                | The corner radius and the base spacing step          |
| `--font-sans`, `--font-mono`                 | The two type families                                |
| `--divider`                                  | Hairlines                                            |

Those fifteen are the whole list, and they are the same fifteen
`installHostTheme()` sets in a test, so a component renders in a test the way it renders in
the host. Always write a fallback: a variable the host has not set yet falls through to it
rather than to nothing. Today the host sets a handful of these; the rest fall through to your
fallback until the host theme lands.

They change with the owner's theme. `useTapTheme()` gives you `{ mode: "light" | "dark" }`
when a component has to branch rather than restyle — a chart's series colours, say.

## The UI kit already uses them

`TapCard`, `TapStat`, `TapButton`, `TapTable` and the rest of the kit are built on exactly
this list, so a surface assembled from them needs no CSS of your own:

```tsx theme={null}
import { TapCard, TapStat } from "@tappify/extension-sdk";
import "@tappify/extension-sdk/styles.css";
```

## Two rules the checks read

* **No bundled fonts and no third-party stylesheets.** A publish rejects a bundle that loads
  a font or a script from another origin. Use `--font-sans` and `--font-mono`. Writing a
  stylesheet into the document is a warning rather than a rejection, and the warning is
  worth acting on: styles put on `document.head` leave your shadow root and land on the host
  and on every other extension on the page. An emitted `.css` asset is a rejection, because
  a separate file never reaches a shadow root — the build inlines the stylesheets your entry
  imports, so that one does not fire on its own.
* **Container queries, not viewport queries.** A slot's width has nothing to do with the
  viewport. Your mount is the container, so size against it:

```css theme={null}
@container (min-width: 480px) {
  .funnel-grid {
    grid-template-columns: 1fr 1fr;
  }
}
```

A widget has to be readable at 320 pixels. That is the width to design against.
