# Manti UI Design System
The first design-system release. One word drives every decision: **smooth**.
## Theming
Color tokens resolve with the CSS `light-dark()` function and follow the used
`color-scheme`. By default that means the OS preference; set `data-theme` on any
container to override it for that subtree:
```html
…
```
Apply `.manti-app` (or `body`) to pick up the themed background, text color, and
font. Import the stylesheet once at your app root —
`import '@manti-ui/styles/index.css'` — or use the Tailwind entry point;
`@manti-ui/react` deliberately ships no CSS side effects so headless usage
stays possible. See [styling.md](./styling.md) for the full customization
contract (plain CSS overrides, token theming, custom tones, Tailwind v4).
> Build note: bundlers must keep modern CSS (`light-dark()`, nesting) intact.
> The workspace Vite configs target `chrome123` for exactly this reason; a
> `prefers-color-scheme`-only polyfill would ignore manual `data-theme`.
## Motion tiers
Motion is a choice. Set `data-motion` on any container — like `data-theme` — to
pick how animated Manti is for that subtree:
```html
…
```
- `default` (or unset) — the shipped transitions and keyframes.
- `none` — drop Manti's decorative motion (the spinner keeps spinning); hand the
motion story to the host app. Your own animations inside a component survive.
- `full` — expressive, spring-driven motion built purely in CSS with the
`--manti-ease-spring` / `--manti-ease-bounce` curves.
`prefers-reduced-motion: reduce` always wins, even over `full`. The full
contract — tokens, nesting rules, the SSR-safe story — is in
[styling.md](./styling.md#motion-tiers).
## Color
Six perceptually-uniform OKLCH ramps (`50`–`950`) from the mantı kitchen:
| Ramp | Role | Reference |
| -------- | ------- | ------------ |
| `gray` | neutral | warm neutral |
| `orange` | primary | warm orange |
| `green` | success | fresh green |
| `amber` | warning | golden amber |
| `red` | danger | hot red |
| `blue` | info | calm blue |
### Semantic & tonal roles
`:root` exposes surfaces and text — `--manti-bg`, `--manti-surface`,
`--manti-surface-raised`, `--manti-border`, `--manti-text`, `--manti-text-muted`,
and more.
Every tonal component reads a uniform vocabulary selected by `[data-tone]`:
```
--tone-solid --tone-soft-bg --tone-border
--tone-solid-hover --tone-soft-bg-hover --tone-text
--tone-solid-active --tone-soft-text --tone-ring
--tone-on-solid
```
A component never hard-codes a hue; it sets `data-tone` and consumes `--tone-*`.
## Material — sleek monochrome panel
The Manti UI signature. Surfaces are **cool, near-neutral, and monochrome** —
dark is the hero (a deep near-black with a faint cool cast), light a soft
daylight that never goes stark white. **No gradients** and no colored brand
accent: emphasis is carried by neutral light/dark (a top-lit rim, a neutral
focus ring, near-white/near-black solids), and color appears only through the
semantic tones. Floating surfaces — cards, tooltips, the field control — are a
**translucent panel**: a light `backdrop-filter: blur() saturate()`, a hairline
border, a top-lit rim catching the light, and a soft, deep shadow. This translucent
panel is the **pervasive** material: it also carries soft buttons, soft badges,
soft alerts, toggles, accordions, and collapsibles. Only **solid** fills (which
gain nothing from a blur) and the tiny form marks (checkbox, radio, switch) stay
crisp. Solid buttons invert the theme by default (near-white on dark, near-black
on light), exactly like the reference.
A subtle **ambient mesh** — three faint glows (violet, magenta, warm ember) at
very low opacity — sits behind every `.manti-app`/`body` as pure scene lighting
(not a gradient element), so the deep background reads with depth rather than
flat. The color ramps (orange, green, amber, red, blue) remain as semantic
tones for badges, alerts, and the like.
Retune the whole material from one place:
```
--manti-panel-tint --manti-panel-border --manti-panel-shadow
--manti-panel-tint-strong --manti-panel-highlight --manti-panel-shadow-color
--manti-panel-blur --manti-ambient-1 … 3
```
Use the `.manti-panel` helper to give your own floating surfaces (menus, sheets,
command palettes) the same material. Where `backdrop-filter` is unsupported,
every panel surface falls back to an opaque token surface automatically.
## Scales
- **Radius** — `--manti-radius-xs … 2xl`, `full`. Pillowy by default.
- **Spacing** — `--manti-space-0 … 16` on a 4px grid.
- **Type** — `--manti-text-xs … 5xl`, weights `regular`–`bold`, Inter.
- **Elevation** — `--manti-shadow-sm | md | lg`, soft and warm-tinted, plus the
layered `--manti-panel-shadow` for floating panels.
- **Motion** — `--manti-ease-smooth` (default), `--manti-ease-soft`, plus the
expressive `--manti-ease-spring` / `--manti-ease-bounce` curves, with
`--manti-duration-fast | base | slow | slower`. Honors
`prefers-reduced-motion`, and is tunable per subtree via
[motion tiers](#motion-tiers).
## Components
| Component | Tones | Notes |
| ----------- | :---: | ------------------------------------------------------ |
| `Button` | all | `solid` / `soft` / `outline` / `ghost`, sizes, loading |
| `Toggle` | all | Zag.js toggle machine; controlled or uncontrolled |
| `Switch` | all | real checkbox + `role="switch"`, smooth thumb |
| `Checkbox` | all | checked + indeterminate, drawn check |
| `TextField` | all | label, hint, error, adornments, wired ARIA |
| `Badge` | all | `solid` / `soft` / `outline`, optional dot |
| `Card` | — | pillowy surface; `Header`/`Title`/`Body`/`Footer` |
| `Alert` | all | soft/solid, dismiss, role escalates for danger/warning |
| `Spinner` | — | inherits `currentColor` |
## Anatomy contract
Every component renders stable attributes so the CSS is framework-agnostic:
```html
```
A future `@manti-ui/vue` or `@manti-ui/svelte` adapter renders the same anatomy
and reuses these tokens, styles, and folds unchanged.