# Wingo UI > Wingo UI is a library of animated, configurable, mobile-first React components and blocks you copy into your project, with a CLI and an MCP server for coding agents. 326 items (218 components, 72 blocks, 17 hooks, 19 helper libraries) for React 19 and Tailwind CSS v4, release 1.7.0. 75 items are free; the rest need a Pro plan. Components are installed as source you own with the CLI (`npx wingo-ui@latest add `). Coding agents connect to the MCP server to search components, read props and design rules, and check for updates. Every item has an HTML docs page (live preview, props, usage) and the same docs as Markdown at the page URL plus `.md`. - MCP server (Streamable HTTP): https://wingo-ui.com/mcp (send "Authorization: Bearer wui_..." to get any source: a free account key returns free sources, a Pro key Pro sources; search, docs and props work without one) - JSON registry (shadcn format): https://wingo-ui.com/r/registry.json, https://wingo-ui.com/r/.json (item with source; Pro items need an API key), https://wingo-ui.com/r/meta/.json (docs), https://wingo-ui.com/r/versions.json ## About - What: a commercial React component library. Components, full-screen blocks, page templates, hooks and helpers are copied into your project as TypeScript source (shadcn style), so you own and edit the code. - Stack: React 19, Tailwind CSS v4, Next.js (App Router) or Vite. Animations use motion; overlays use Radix primitives. - Built for phones first (bottom sheets instead of popovers, 44px touch targets), light and dark mode, and props for every visual aspect. - Coding agents: an MCP server, a CLI that writes rule files for Claude Code, Codex, Gemini CLI, Grok and Cursor, and this file. Details: [AI agents](https://wingo-ui.com/ai). ## Pricing - Free: 75 of 326 items with full source, free forever. Every Pro item can still be previewed and configured on its docs page; only copying its source needs Pro. - Pro: the source of all 326 items (251 Pro-only), updates and the Pro MCP tools. $8 a month, $80 a year (17% less than paying monthly) or $150 once for lifetime access. Prices in USD. - License: one license per developer; use the components in unlimited end products, your own or your clients'; no reselling them as a UI kit or library. Copied components stay yours after a subscription ends. - Refunds: within 14 days of the first purchase. [Pricing and FAQ](https://wingo-ui.com/pricing), [license](https://wingo-ui.com/legal/license), [refund policy](https://wingo-ui.com/legal/refund). ## Docs - [Installation](https://wingo-ui.com/docs/installation): Set up a project and add components - [MCP server](https://wingo-ui.com/docs/mcp): Connect your coding agent - [CLI](https://wingo-ui.com/docs/cli): Every command and flag - [Coding agents](https://wingo-ui.com/docs/agents): Claude Code, Codex, Gemini CLI, Grok, Cursor - [Updates](https://wingo-ui.com/docs/updates): Versions, merges and the changelog - [Theming](https://wingo-ui.com/docs/theming): Tokens, dark mode and themes - [Components](https://wingo-ui.com/components): browse every item with live, configurable previews - [Templates](https://wingo-ui.com/templates): whole website pages built from the marketing sections - [Theme generator](https://wingo-ui.com/theme): brand, neutrals, status colors, radius, font and component defaults, with a live preview and export - [Changelog](https://wingo-ui.com/changelog): every release ([RSS](https://wingo-ui.com/changelog/rss.xml), [JSON](https://wingo-ui.com/changelog/feed.json)) - [Full docs for language models](https://wingo-ui.com/llms-full.txt): install guide, design rules (tokens, sizes, motion, forms, overlays, mobile) and every item's props and usage in one large file; the same item docs per category are linked under Categories ## Categories Each category page lists its items with live previews; the full docs of a category (props, parts, usage) are also plain text, in parts of up to 100 KB for the big categories. - [Buttons & Actions](https://wingo-ui.com/components/category/buttons): 7 items, 3 free ([full docs](https://wingo-ui.com/llms/buttons.txt)) - [Inputs](https://wingo-ui.com/components/category/inputs): 36 items, 11 free (full docs in 4 parts: [1](https://wingo-ui.com/llms/inputs.txt), [2](https://wingo-ui.com/llms/inputs-2.txt), [3](https://wingo-ui.com/llms/inputs-3.txt), [4](https://wingo-ui.com/llms/inputs-4.txt)) - [Forms](https://wingo-ui.com/components/category/forms): 8 items, 1 free ([full docs](https://wingo-ui.com/llms/forms.txt)) - [Navigation](https://wingo-ui.com/components/category/navigation): 19 items, 7 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/navigation.txt), [2](https://wingo-ui.com/llms/navigation-2.txt)) - [Overlays](https://wingo-ui.com/components/category/overlays): 12 items, 7 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/overlays.txt), [2](https://wingo-ui.com/llms/overlays-2.txt)) - [Feedback](https://wingo-ui.com/components/category/feedback): 12 items, 8 free ([full docs](https://wingo-ui.com/llms/feedback.txt)) - [Data Display](https://wingo-ui.com/components/category/data-display): 23 items, 5 free (full docs in 3 parts: [1](https://wingo-ui.com/llms/data-display.txt), [2](https://wingo-ui.com/llms/data-display-2.txt), [3](https://wingo-ui.com/llms/data-display-3.txt)) - [Tables & Lists](https://wingo-ui.com/components/category/tables): 11 items, 1 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/tables.txt), [2](https://wingo-ui.com/llms/tables-2.txt)) - [Charts & Stats](https://wingo-ui.com/components/category/charts): 15 items, 2 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/charts.txt), [2](https://wingo-ui.com/llms/charts-2.txt)) - [Layout](https://wingo-ui.com/components/category/layout): 12 items, 3 free ([full docs](https://wingo-ui.com/llms/layout.txt)) - [Media](https://wingo-ui.com/components/category/media): 15 items, 1 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/media.txt), [2](https://wingo-ui.com/llms/media-2.txt)) - [AI Kit](https://wingo-ui.com/components/category/ai): 16 items, 3 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/ai.txt), [2](https://wingo-ui.com/llms/ai-2.txt)) - [Text & Effects](https://wingo-ui.com/components/category/effects): 1 item, 1 free ([full docs](https://wingo-ui.com/llms/effects.txt)) - [Mobile](https://wingo-ui.com/components/category/mobile): 15 items, 0 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/mobile.txt), [2](https://wingo-ui.com/llms/mobile-2.txt)) - [Commerce](https://wingo-ui.com/components/category/commerce): 16 items, 0 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/commerce.txt), [2](https://wingo-ui.com/llms/commerce-2.txt)) - [Marketing Sections](https://wingo-ui.com/components/category/marketing): 20 items, 6 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/marketing.txt), [2](https://wingo-ui.com/llms/marketing-2.txt)) - [Blocks](https://wingo-ui.com/components/category/blocks): 23 items, 0 free (full docs in 3 parts: [1](https://wingo-ui.com/llms/blocks.txt), [2](https://wingo-ui.com/llms/blocks-2.txt), [3](https://wingo-ui.com/llms/blocks-3.txt)) - [Templates](https://wingo-ui.com/templates): 29 items, 2 free (full docs in 3 parts: [1](https://wingo-ui.com/llms/templates.txt), [2](https://wingo-ui.com/llms/templates-2.txt), [3](https://wingo-ui.com/llms/templates-3.txt)) - [Hooks & Utilities](https://wingo-ui.com/components/category/utilities): 36 items, 14 free (full docs in 2 parts: [1](https://wingo-ui.com/llms/utilities.txt), [2](https://wingo-ui.com/llms/utilities-2.txt)) ## Install Wingo UI (Next.js, npm) Wingo UI components are React 19 + Tailwind CSS v4 source files you own. The CLI copies them into your project with their dependencies and records versions so you can update later. ### 1. A React 19 + Tailwind v4 project New project: ```bash npx create-next-app@latest my-app --ts --tailwind --eslint --app --import-alias "@/*" ``` ### 2. Initialize ```bash npx wingo-ui@latest init ``` `init` detects the framework, the `@/*` alias and your global stylesheet (app/globals.css), installs `clsx` and `tailwind-merge`, creates `lib/utils.ts` (the `cn` helper), merges the Wingo UI design tokens into app/globals.css without overwriting your values, and writes `wingo-ui.json` (commit it). ### 3. Add components ```bash npx wingo-ui@latest add button input card ``` Registry dependencies (shared hooks like `use-controllable-state`, helpers like `lib/motion`) and npm packages come along automatically. Files land in `components/ui`, `components/blocks`, `hooks` and `lib`. Pro components need a Pro account: ```bash npx wingo-ui@latest login ``` (opens the browser; on a server use `npx wingo-ui@latest login --key wui_...` with a key from https://wingo-ui.com/account/ai, or set `WINGO_UI_API_KEY`). ### 4. Dark mode and app-wide defaults Components read the `.dark` class. With Next.js use next-themes: ```bash npm install next-themes ``` ```tsx // app/layout.tsx import { ThemeProvider } from "next-themes" import { UIProvider } from "@/lib/ui-config" export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ) } ``` `UIProvider` (item `ui-config`, installed with any component) sets defaults for every component (`defaults={{ input: { variant: "filled" } }}`) and the `locale` for dates and numbers. Explicit props always win. ### 5. Use it ```tsx import { Button } from "@/components/ui/button" export function Save() { return } ``` ### Stay up to date ```bash npx wingo-ui@latest outdated # what changed upstream npx wingo-ui@latest update # 3-way merge that keeps your local edits ``` ### Coding agents Connect the MCP server (https://wingo-ui.com/mcp) so Claude Code, Codex, Gemini CLI, Grok or Cursor search components, read props and design rules, and install with the CLI: ```bash npx wingo-ui@latest agents install ``` ### Without the CLI - shadcn: `npx shadcn@latest add https://wingo-ui.com/r/button.json` (free items). For Pro items add the `@wingo-ui` registry with an `Authorization: Bearer ${WINGO_UI_API_KEY}` header to components.json. - Manual: copy the files from the component page, install its npm dependencies, add `lib/utils.ts` and the tokens (https://wingo-ui.com/docs/theming). ## Wingo UI design rules Every Wingo UI component follows these rules; screens you build around them should too, so the app feels like one system. When a component exists for the job, use it and configure it through props (size, variant, tone, radius, labels) instead of restyling it. Use semantic tokens only (bg-background, bg-card, text-muted-foreground, border-border, bg-success-soft...) so light and dark mode both work. ### Principles **Tactile.** Everything you can press answers within one frame: the state layer tints on hover (`hover:before:opacity-[0.08]`), the surface dips to `scale: 0.97` on a snappy spring while pressed, and the focus ring sits 2px off the edge. Nothing pressable is inert-looking. **Fast.** Animate `transform` and `opacity` only. Entrances take 150 to 300ms, exits are quicker than entrances. No layout thrash, no `setState` per animation frame (use motion values), no JS on scroll unless passive. A component renders its final state on the server; motion is an enhancement. **Calm.** Neutral by default: every `tone` prop defaults to `neutral` (black in light mode, white in dark mode), including switches, checkboxes, sliders, progress, tabs and selected states. Color only where it carries meaning: status tones for status, brand orange opt-in for the one hero action. One solid action per view. Springs settle without wobble except `bouncy`, which is for rare moments of delight. Copy is short and plain. **Mobile first.** Design at 360 to 390px, then widen. Touch targets are 44px on coarse pointers. Overlays become bottom sheets below 768px. Tables become cards. Nothing depends on hover. Safe areas are respected on anything pinned to an edge. ### Tokens Always use semantic tokens so light and dark both work. Hardcoded colors are allowed only as overridable prop defaults. #### Surfaces (back to front) | Token | Class | Light | Dark | Use for | |---|---|---|---|---| | `--background` | `bg-background` | white | black | the page | | `--card` | `bg-card` | #EBEBEB | #121212 | flat gray tiles with no shadow, grouped rows | | `--muted` | `bg-muted` | #F9FAFB | #171717 | large wells on the page background only: code blocks, table header bands. It is nearly invisible on white, so never use it for fields, tracks or skeletons (use the tints below) | | `--surface` | `bg-surface` + `shadow-raised` | white | #1A1A1A | raised panels on a page: list groups, stat cards, form cards, toolbars | | `--canvas` | `bg-canvas` | #F6F7F9 | #0E0E10 | the page of an app (dashboards, admin, settings in an `app-shell` inset panel): a cool gray canvas so white / #1A1A1A `bg-surface` cards read as cards. Marketing and docs pages stay on `bg-background` | | `--popover` | `bg-popover` + `shadow-floating` / `shadow-modal` | white | #262626 | everything that floats: popovers, menus, selects, dialogs, sheets, toasts | | `--primary` | `bg-primary text-primary-foreground` | black | near-white | the neutral solid fill (neutral tone), tooltips | Each surface has its `-foreground` text token (`text-surface-foreground`, `text-popover-foreground`, `text-card-foreground`); on `bg-background` use `text-foreground`. #### Tints Translucent foreground over whatever is behind, so they work on every surface in both themes. Use only these steps: | Class | Use | |---|---| | `bg-foreground/5` | hover on rows, items and ghost controls; the soft field fill; chips; segmented and tab tracks; skeletons; the empty-state icon tile | | `bg-foreground/7` | hover on a soft field (one step above its fill) | | `bg-foreground/10` | pressed and selected rows; progress and slider tracks; avatar fallbacks | | `bg-foreground/15` | the switch track when off; sheet handles; scrollbar thumbs | | `border-foreground/10` | hairlines on tinted surfaces and between rows | **Legacy tokens.** `--secondary`, `--accent` (an orange tint here, not shadcn's gray), `--sidebar-*`, `--chart-*` and the `shadow-sm` ... `shadow-2xl` scale exist for the first 21 components and the showcase shell. New components never use `bg-accent`, `bg-secondary` or `bg-muted` on controls: shadcn's `focus:bg-accent` becomes `data-highlighted:bg-foreground/5`, `bg-secondary` becomes `variant="soft"`. #### Text levels | Level | Class | Use | |---|---|---| | Primary | `text-foreground` (or the surface's `-foreground`) | titles, values, labels | | Secondary | `text-muted-foreground` | descriptions, helper text, timestamps, placeholders | | Tertiary / disabled | `text-foreground/45` | disabled labels only; never for text people must read | | Tone text | `text-{tone}-soft-foreground` | colored text on any surface: an error message, a +12% delta, a link | `text-muted-foreground` passes AA on every surface in both themes. Never go lighter than it for readable text. #### Borders and rings - `border-border` for dividers and input outlines (the base layer sets it as the default border color, so `border` / `border-b` alone is enough). - `border-foreground/10` for hairlines on tinted surfaces. - `outline-ring` for the focus outline of pressables (section 7), `ring-ring/50` for fields (section 9). `--ring` is the brand orange, a touch deeper in light mode so a 2px outline keeps 3:1 on white and on `bg-card`. #### Brand and status tones | Tone | Tokens | Meaning | |---|---|---| | brand | `--brand` #D63F00 (the #FC4C01 family, deep enough for white text) | opt-in with `tone="brand"`: the one hero CTA of a marketing, pricing or checkout screen, brand moments. Never a default | | success | `--success` | done, paid, online, positive delta | | warning | `--warning` (amber fill, dark text) | needs attention soon, low stock, expiring | | destructive (tone `danger`) | `--destructive` | errors, delete, failed, negative delta | | info | `--info` | neutral news, tips, in progress | For each tone `X`: | Token | Class | Use | |---|---|---| | `--X` | `bg-X` | solid fill (buttons, solid badges, progress bars, switch on) | | `--X-foreground` | `text-X-foreground` | text and icons on the solid fill | | `--X-soft` | `bg-X-soft` | tinted surface (soft badges, alerts, soft buttons, selected rows) | | `--X-soft-foreground` | `text-X-soft-foreground` | tone text on the soft surface **and on any neutral surface** | Rules: - Colored text is always `text-X-soft-foreground`, never `text-X`: fills are tuned for fills (`text-destructive` on a dark card is below AA). - Borders in a tone: `border-X/40` or the `--tone-border` var (see below). - The warning fill is light (amber), so it takes dark text. A bare warning dot on white is low contrast: pair it with text or an icon. #### Tones in components: `lib/tones.ts` A component with a `tone` prop never maps tokens itself. It sets five CSS vars with `toneClasses[tone]` (or `colorVars(color)` for a custom color) and paints with them: ``` --tone bg-(--tone) solid fill --tone-foreground text-(--tone-foreground) text on the fill --tone-soft bg-(--tone-soft) tinted surface --tone-soft-foreground text-(--tone-soft-foreground) tone text --tone-border border-(--tone-border) outline / divider ``` ```tsx import { colorVars, toneClasses, type Tone } from "@/lib/tones" ``` `tone="neutral"` maps to `--primary` (black / white). `colorVars` picks black or white text for the fill by lightness and mixes tone text toward the foreground for contrast. A caller can force any var: `className="[--tone-foreground:white]"`. #### Elevation | Class | Token | Use | |---|---|---| | `shadow-raised` | `--elevation-raised` | solid buttons, `bg-surface` panels, switch thumbs, slider thumbs, segmented thumbs, cards that lift | | `shadow-floating` | `--elevation-floating` | popovers, menus, selects, hover cards, tooltips, toasts, dragged items | | `shadow-modal` | `--elevation-modal` | dialogs, sheets, drawers, command palette | Every level carries its own hairline (light: a 1px 5% black ring; dark: a 1px white ring plus a lit top edge), so elevated surfaces need no `border`. The old `shadow-sm` ... `shadow-2xl` still exist for existing components; new code uses the three levels above. #### Stacking layers | Class | Value | Use | |---|---|---| | `z-dropdown` | 1000 | in-flow floating panels that are not portaled (an inline autocomplete list) | | `z-sticky` | 1100 | sticky headers, bottom tab bars, sticky CTA bars | | `z-overlay` | 1200 | the dimmed backdrop behind dialogs and sheets (vaul `Drawer.Overlay` too) | | `z-modal` | 1300 | dialog, alert dialog, sheet and drawer content (vaul `Drawer.Content` too) | | `z-popover` | 1400 | every portaled popover, dropdown menu, context menu, select, combobox, hover card (above modals, so a select inside a dialog works) | | `z-toast` | 1500 | toasts and snackbars | | `z-tooltip` | 1600 | tooltips, always on top | Never use raw `z-50` style numbers in library code. #### Radius **Trap:** the legacy `--radius` (6px) remaps Tailwind's `rounded-sm`, `rounded-md`, `rounded-lg` and `rounded-xl` to 2 / 4 / 6 / 10px for the ported components. New components never use those four classes. Controls take the per-size map from section 4 (copy the `RADII` map from `button.tsx` verbatim), surfaces use the table below, anything else uses an explicit `rounded-[Npx]`. `rounded-2xl` (16px), `rounded-3xl` (24px) and `rounded-full` keep Tailwind's values and are fine. | Surface | Radius | |---|---| | cards, list groups, popovers, menus, selects, hover cards, toasts | `rounded-2xl` (16px) | | dialogs, large panels, demo cards | `rounded-3xl` (24px) | | bottom sheets | `rounded-t-[28px]` | | tooltips, kbd, small tags inside text | `rounded-[8px]` / `rounded-[5px]` | | anything inside a padded surface | the outer radius minus the padding: a `rounded-2xl p-1.5` menu has `rounded-[10px]` items, a `rounded-[10px] p-0.5` segmented track has a `rounded-[8px]` thumb | A surface with a `radius` prop (card, dialog, sheet, popover) maps `none` `rounded-none`, `sm` `rounded-[12px]`, `md` `rounded-2xl`, `lg` `rounded-3xl`; `full` falls back to `lg`. Cards and popovers default to `md`, dialogs to `lg`. #### CSS motion tokens For CSS transitions (colors, opacity, simple transforms) that do not go through `motion/react`: | Class | Value | Use | |---|---|---| | `duration-fast` | 150ms | hover, color, state layers, press release | | `duration-normal` | 240ms | small enter / exit | | `duration-slow` | 400ms | large surfaces | | `ease-smooth` | cubic-bezier(0.22, 1, 0.36, 1) | the default curve for everything above | | `ease-smooth-in-out` | cubic-bezier(0.65, 0, 0.35, 1) | moving between two on-screen states | | `ease-sheet` | cubic-bezier(0.32, 0.72, 0, 1) | sheets and drawers | | `ease-spring` + `duration-spring` | springs.smooth as `linear()`, 500ms | CSS-only transforms that should feel like the smooth spring | | `ease-snappy` + `duration-snappy` | springs.snappy as `linear()`, 450ms | CSS-only press / toggle transforms | ### Typography and spacing Font: `font-sans` (Inter), inherited. Do not hardcode a font family in a component; `font-runde` is only for display numerals and titles in demos. Numbers that change or align get `tabular-nums`. | Role | Classes | |---|---| | Display (hero numbers, page titles in demos) | `text-[32px] leading-[1.05] font-bold tracking-[-0.03em]` (`md:text-5xl`) | | Title (dialog, sheet, page header) | `text-lg font-semibold tracking-tight` (18px) | | Heading (card, section, list group) | `text-[15px] font-semibold tracking-tight` | | Body | `text-sm leading-relaxed` (14px); reading content `text-[15px]` | | Label (form labels, button md, menu items) | `text-sm font-medium` (menu items `text-sm` regular) | | Small label (button sm, chips, tabs sm) | `text-[13px] font-medium` | | Caption (helper, meta, timestamps, field errors) | `text-xs text-muted-foreground` (12px) | | Eyebrow | `text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground` | | Mono (ids, code, keys) | `font-mono text-[12.5px]` | | Text inputs | `text-base md:text-sm` (16px on phones so iOS never zooms) | `cn()` is tailwind-merge: a `text-*` size removes a `leading-*` that comes before it. Put line height after the size or in the same class (`text-sm/6`). Spacing is a 4px grid (`--spacing: 0.25rem`): - icon to label: `gap-1.5` (sm) / `gap-2` (md, lg) - controls in a row: `gap-2`; groups of controls: `gap-3` - inside a panel: `p-4` on phones, `sm:p-5` or `p-6` on larger screens - label to field: `gap-1.5`; field to field: `gap-4` - between sections: `gap-6` to `gap-8`; page sections `py-12 md:py-16` - phone gutters: `px-4` (16px); adjacent touch targets at least 8px apart ### Sizes `size="sm" | "md" | "lg"`, default `md`. Every control with a height uses this table so a button, an input and a select line up: button, toggle, toggle group, segmented control, tabs (pill and segmented variants), input and every field trigger (select, combobox, date / time pickers, color picker), number stepper buttons, pagination buttons. | | sm | md | lg | |---|---|---|---| | Height | 32px `h-8` | 40px `h-10` | 48px `h-12` | | Height on coarse pointers | 32px + 44px hit area | **44px** `pointer-coarse:h-11` | 48px | | Horizontal padding (buttons) | `px-3` | `px-4` | `px-5` | | Horizontal padding (fields) | `px-2.5` | `px-3` | `px-3.5` | | Font | `text-[13px]` | `text-sm` (14px) | `text-[15px]` | | Font in text fields | `text-base md:text-[13px]` | `text-base md:text-sm` | `text-base md:text-[15px]` | | Icon | 14px `size-3.5` | 16px `size-4` | 18px `size-[18px]` | | Gap | `gap-1.5` | `gap-2` | `gap-2` | | Square (icon-only) | `size-8` | `size-10` (`pointer-coarse:size-11`) | `size-12` | Hit area without changing the look (sm on touch): `pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-1.5` on a `relative` element (square: `pointer-coarse:after:-inset-1.5`). Unsized icons follow the size with `[&_svg:not([class*='size-'])]:size-4`. Radius per size (`radius` prop, default `md`): | radius | sm | md | lg | |---|---|---|---| | none | 0 | 0 | 0 | | sm | 6px | 8px | 10px | | md | 8px | 10px | 12px | | lg | 10px | 14px | 16px | | full | pill | pill | pill | #### Selection controls | | sm | md | lg | |---|---|---|---| | Checkbox / radio box | 16px `size-4` | 18px `size-[18px]` | 20px `size-5` | | Checkbox radius | `rounded-[4px]` | `rounded-[5px]` | `rounded-[6px]` | | Check / dot icon | 12px | 14px | 16px | | Switch track | 32 x 18 `h-[18px] w-8` | 40 x 24 `h-6 w-10` | 48 x 28 `h-7 w-12` | | Switch thumb (2px inset) | 14px | 20px | 24px | | Slider track / thumb | 4px / 16px | 6px / 20px | 8px / 24px | - Off: checkbox and radio `border-[1.5px] border-foreground/30 bg-transparent`; switch track `bg-foreground/15`; slider track `bg-foreground/10`. - On: `bg-(--tone) text-(--tone-foreground)` (checkbox, radio, switch track, slider range), so `tone` and `color` work like the button's. The switch thumb is `bg-white shadow-raised`, and `bg-(--tone-foreground)` while checked (in dark mode the neutral track is white, so the thumb turns dark). - The thumb and the check mark move on `springs.snappy`; the check draws with `pathLength`. - The label sits to the right and the whole row is the target: wrap control and text in a `