# Styling

The styled components are authored in Tailwind v4 and read `--mirio-*` CSS variables and two `data-mirio-*` attributes, so the Tailwind source and the compiled CSS look and behave the same. There are five layers, from "do nothing" to "own every class". Most sites stop at the first or second. The interactive [Theming](/docs/theming.md) page shows each knob live.

## Import the CSS (once)

`mirio init` does this for you. By hand:

**Tailwind v4.** Your Tailwind build generates the utilities the components use, so your own classes override theirs normally:

```css
/* app/globals.css */
@import "tailwindcss";
@import "@trymirio/mirio/theme.css";
@import "@trymirio/mirio/themes/shadcn.css";   /* only on shadcn/ui sites */
@source "../node_modules/@trymirio/mirio/dist";
```

**Anything else** (Tailwind v3, plain CSS, CSS modules). Import the compiled stylesheet. It is scoped under `[data-mirio-root]` (the `Form` root), so it does not touch the rest of the page and has no global reset. On a shadcn/ui site with Tailwind v3, add `@trymirio/mirio/themes/shadcn-v3.css` after it.

```ts
import '@trymirio/mirio/styles.css';
```

## 1. Inherit the site

The form uses your page's font (`--mirio-font: inherit`). On shadcn/ui sites, `themes/shadcn.css` maps every `--mirio-*` token to shadcn's variables (`--primary`, `--primary-foreground`, `--background`, `--foreground`, `--muted`, `--muted-foreground`, `--input`, `--ring`, `--destructive`, `--radius`), so the form matches your buttons and inputs and changes with your theme. `themes/shadcn-v3.css` does the same for the HSL-triplet style (`hsl(var(--primary))`).

## 2. Dark mode follows the site

The built-in dark values apply when the form sits under a `.dark` or `[data-theme="dark"]` ancestor, which is what next-themes and most Tailwind setups toggle. To force it on one form, pass `theme={{ colorScheme: 'dark' }}` (`'light'` forces light, `'auto'` follows the visitor's OS). A form is never dark because of the OS alone unless you ask for `'auto'`. Override the dark values with your own rule:

```css
.dark { --mirio-primary: #a5b4fc; --mirio-primary-fg: #1e1b4b; }
```

## 3. Tokens and the `theme` prop

Every color, the radius, font, sizes and spacing are CSS variables. Set them on `:root`, on `.dark`, or on any wrapper:

```css
:root {
  --mirio-primary: #111827;     --mirio-primary-fg: #ffffff;
  --mirio-bg: #ffffff;          --mirio-fg: #111827;
  --mirio-muted: #f3f4f6;       --mirio-muted-fg: #6b7280;
  --mirio-border: #e5e7eb;      --mirio-ring: #2563eb;
  --mirio-error: #dc2626;       --mirio-input-bg: #ffffff;
  --mirio-radius: 0.5rem;       --mirio-font: inherit;
  --mirio-control-h: 2.5rem;    --mirio-text: 15px;
  --mirio-border-width: 1px;    --mirio-label-weight: 500;
  --mirio-space: 1.25rem;       /* between fields */
  --mirio-gap: 0.5rem;          /* inside a field */
}
```

Or pass `theme` to one form (or to `MirioProvider` for all of them; the form's keys win). It becomes inline variables on the form root:

```tsx
<Form schema={waitlist} theme={{ primary: '#2563eb', radius: 'full', font: 'var(--font-sans)' }} />
```

## 4. `size` and `layout`

`size="sm" | "md" | "lg"` swaps one bundle of tokens (control height, text size, spacing) through `data-mirio-size`. `layout={{ columns: 2 }}` lays the auto-rendered fields (and `Page`) out in a grid; long text, choices, consent and keys listed in `layout.full` span every column, and everything is one column below 640px.

```tsx
<Form schema={demo} size="lg" layout={{ columns: 2, full: ['company_url'] }} />
```

## 5. `classNames` slots, `className`, and owning the source

`classNames` adds classes to every instance of a part: `root`, `form`, `page`, `pageHeader`, `field`, `label`, `help`, `input` (Input, Textarea, Select, DatePicker), `option` (choice rows), `segment` (YesNo), `rating`, `consent`, `error`, `submit`, `button` (Back, Next), `progress`, `success`. On `MirioProvider` they apply to every form (both are kept, the form's after the provider's). They are merged with tailwind-merge before each component's own `className`, so a conflicting utility on the component wins:

```tsx
<Form schema={waitlist} classNames={{ label: 'uppercase tracking-wide', input: 'bg-zinc-50', submit: 'rounded-full' }} />
<Submit className="w-auto" />   {/* composed: beats classNames.submit and the default */}
```

Plain CSS can target the `data-mirio` hooks (`[data-mirio="input"]`, `[data-mirio="submit"]`, …) and `[data-mirio-size]`, `[data-mirio-color-scheme]`.

To change the markup itself, start from `@trymirio/mirio/headless` with your own elements ([Headless](/docs/components/headless.md)); the styled components are built on the same hooks.
