diff --git a/README.md b/README.md
index 94445b5..20ea723 100644
--- a/README.md
+++ b/README.md
@@ -253,20 +253,24 @@ pnpm build-storybook # Static build
The React components assume a React runtime. For HTMX, Django templates, Rails ERB, Go `html/template`, Astro SSR, or any other server-rendered stack, consume the design system via the auto-generated CSS layer.
+**The HTMX theme is derived from React.** React's `components/ui/*.tsx` is the single source of truth: the generator AST-walks each component, extracts its `cva()` bindings and static `className` strings, and emits CSS rules keyed on the same `data-slot` / `data-variant` / `data-size` attributes React already sets. If a `.tsx` file doesn't use it, the HTMX layer doesn't have it. Never edit `dist/greyhaven.htmx.css` by hand.
+
### What you get
-`dist/greyhaven.htmx.css` is generated from `components/ui/*.tsx` (AST walk over `cva()` configs + static `className` strings on `data-slot` elements). It contains ~300 `@layer components` rules, one per data-slot, with attribute selectors for variants and sizes.
+`dist/greyhaven.htmx.css` is ~100KB with ~300 rules emitted into `@layer utilities`, one per data-slot, with attribute selectors for variants and sizes. Selectors are wrapped in `:where()` for zero specificity so consumer `className` overrides still win (matching React + tailwind-merge behavior).
```css
-[data-slot="card"] { @apply bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm; }
-[data-slot="card-header"] { @apply grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6; }
-[data-slot="card-title"] { @apply leading-none font-semibold; }
+@layer utilities {
+ :where([data-slot="card"]) { @apply bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm; }
+ :where([data-slot="card-header"]) { @apply grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6; }
+ :where([data-slot="card-title"]) { @apply leading-none font-semibold; }
-[data-slot="button"] { @apply inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium …; }
-[data-slot="button"]:not([data-variant]),
-[data-slot="button"][data-variant="default"] { @apply bg-primary text-primary-foreground hover:bg-primary/90; }
-[data-slot="button"][data-variant="outline"] { @apply border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground; }
-[data-slot="button"][data-size="sm"] { @apply h-8 rounded-md gap-1.5 px-3; }
+ :where([data-slot="button"]) { @apply inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium …; }
+ :where([data-slot="button"]):where(:not([data-variant])) { @apply bg-primary text-primary-foreground hover:bg-primary/90; }
+ :where([data-slot="button"]):where([data-variant="default"]) { @apply bg-primary text-primary-foreground hover:bg-primary/90; }
+ :where([data-slot="button"]):where([data-variant="outline"]) { @apply border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground; }
+ :where([data-slot="button"]):where([data-size="sm"]) { @apply h-8 rounded-md gap-1.5 px-3; }
+}
```
### Install
@@ -304,19 +308,58 @@ Add to your Tailwind v4 input CSS:
Active
```
+See `public/htmx.html` for a full reference implementation — every component in the React showcase has a matching static-HTML section.
+
### Scope
- **Static visual components** (Card, Button, Badge, Input, Label, Textarea, Table, Separator, Code, Kbd, Progress, Avatar, Skeleton, Alert, Pagination, Breadcrumb, Navbar, etc.) → fully driven by CSS, no JS needed.
-- **Interactive components** (Dialog, Dropdown, Popover, Select, Combobox, Accordion, Tabs, Tooltip, etc.) → CSS emits their static styles, but open/close / positioning / focus management is the consumer's responsibility. Alpine.js pairs naturally with HTMX for these.
+- **Interactive components with simple state toggles** (Checkbox, Switch, Tabs, ToggleGroup) → `public/htmx.html` ships a ~60-line vanilla-JS delegation bridge that flips `data-state` on click. Copy or adapt it into your consumer.
+- **Interactive components with positioning** (Dialog, Dropdown, Popover, Select, Combobox, Tooltip) → CSS emits their per-state visual rules, but open/close, portaling, and focus management are the consumer's responsibility. Alpine.js pairs naturally with HTMX for these.
- **Native HTML alternatives**: `` covers Accordion/Collapsible, `