Search Kaotypr Design System

Search tokens, pages and quick actions

LLM reference

Kaotypr Design System cheat sheet

One page. No marketing copy. Token names by family, tier rules, forbidden patterns, common-task snippets. Optimised for context-efficient ingestion.

Top rules

  1. Shadcn props surface is immutable. Variants are additive only.
  2. Components reference tokens only — never inline bg-black/30, rounded-3xl, z-50, text-foreground/60.
  3. Semantic pairs are atomic: bg-{role} text-{role}-foreground. Never split.
  4. Status uses the SOLID pattern: bg-destructive text-destructive-foreground border-destructive-border. Never bg-{status}/10.
  5. Text-entry surfaces apply text-base md:text-sm (iOS Safari focus-zoom).
  6. Focus ring is pinned at --ring-width: 3px.

Tier semantics

Locked

System identity. Never override per-project. Includes z-index, ring-width, status hues, state-layer opacities, --size-* ratios, --opacity-* scale.

Brand

Override expected per-project. Surfaces, foregrounds, borders (values only — not the 3-/4-tier structure), status lightness/chroma, fonts, semantic radii, chart palette, sidebar palette.

Tunable

Override allowed where it helps the product. Shadows, motion, overlay, per-control surfaces (switch/slider/scrollbar/skeleton), placeholder, link/code/kbd, blur scale.

Token names by family

Blur Backdrop blur scale

Tunable
  • --blur-lg
  • --blur-md
  • --blur-sm

Color Surfaces, brand, status, state layers, charts

Locked
  • --color-destructive
  • --color-destructive-border
  • --color-destructive-foreground
  • --color-info
  • --color-info-border
  • --color-info-foreground
  • --color-ring-invalid
  • --color-state-active
  • --color-state-expanded
  • --color-state-focus
  • --color-state-hover
  • --color-state-selected
  • --color-success
  • --color-success-border
  • --color-success-foreground
  • --color-warning
  • --color-warning-border
  • --color-warning-foreground
Brand
  • --color-accent
  • --color-accent-foreground
  • --color-background
  • --color-border
  • --color-border-focus
  • --color-border-input
  • --color-border-strong
  • --color-border-subtle
  • --color-card
  • --color-card-foreground
  • --color-chart-1
  • --color-chart-10
  • --color-chart-11
  • --color-chart-12
  • --color-chart-2
  • --color-chart-3
  • --color-chart-4
  • --color-chart-5
  • --color-chart-6
  • --color-chart-7
  • --color-chart-8
  • --color-chart-9
  • --color-chart-axis
  • --color-chart-grid
  • --color-chart-tooltip-bg
  • --color-chart-tooltip-fg
  • --color-foreground
  • --color-foreground-disabled
  • --color-foreground-subtle
  • --color-input
  • --color-muted
  • --color-popover
  • --color-popover-foreground
  • --color-primary
  • --color-primary-foreground
  • --color-ring
  • --color-secondary
  • --color-secondary-foreground
  • --color-sidebar
  • --color-sidebar-accent
  • --color-sidebar-accent-foreground
  • --color-sidebar-border
  • --color-sidebar-foreground
  • --color-sidebar-primary
  • --color-sidebar-primary-foreground
  • --color-sidebar-ring
  • --gradient-brand
  • --slider-range
  • --switch-track-on
Tunable
  • --code-bg
  • --code-fg
  • --color-muted-foreground
  • --color-overlay
  • --kbd-bg
  • --kbd-border
  • --kbd-fg
  • --label-color
  • --link
  • --link-hover
  • --link-visited
  • --placeholder-color
  • --required-indicator-color
  • --scrollbar-thumb
  • --scrollbar-track
  • --selection-bg
  • --selection-fg
  • --skeleton-bg
  • --skeleton-shimmer
  • --slider-thumb
  • --slider-track
  • --switch-thumb
  • --switch-track-off

Density Comfortable vs compact mode mapping

Locked
  • --density-card-padding
  • --density-control-h
  • --density-field-gap

Focus ring Pinned to 3px

Locked
  • --ring-offset
  • --ring-width

Font Sans, mono, heading, display

Tunable
  • --font-display
  • --font-heading
  • --font-mono
  • --font-sans

Form Field padding, label rhythm

Tunable
  • --field-gap
  • --field-padding-x

Layout Container widths, sidebar widths

Tunable
  • --container-content
  • --container-dashboard
  • --container-prose
  • --container-wide
  • --sidebar-width
  • --sidebar-width-icon

Motion Durations + easing curves

Tunable
  • --duration-fast
  • --duration-instant
  • --duration-normal
  • --duration-slow
  • --duration-slower
  • --ease-in-out
  • --ease-out
  • --ease-overshoot
  • --ease-spring

Opacity Disabled, hover, pressed, overlay, loading

Locked
  • --opacity-disabled
  • --opacity-hover
  • --opacity-loading
  • --opacity-overlay
  • --opacity-pressed

Radius Generic scale + semantic radii per registry component

Locked
  • --radius-lg
  • --radius-md
  • --radius-sm
  • --radius-xl
Brand
  • --radius-button
  • --radius-card
  • --radius-chip
  • --radius-dialog
  • --radius-input
  • --radius-popover
  • --radius-sheet

Shadow Elevation tokens; --shadow-focus is locked

Locked
  • --shadow-focus
Tunable
  • --shadow-card
  • --shadow-inset
  • --shadow-overlay
  • --shadow-popover

Sizing Icon, avatar, control, touch-target sizes

Locked
  • --size-avatar-lg
  • --size-avatar-md
  • --size-avatar-sm
  • --size-avatar-xl
  • --size-control-lg
  • --size-control-md
  • --size-control-sm
  • --size-icon-lg
  • --size-icon-md
  • --size-icon-sm
  • --size-touch-target

Z-index Cross-product layering — never override

Locked
  • --z-index-base
  • --z-index-dropdown
  • --z-index-modal
  • --z-index-overlay
  • --z-index-popover
  • --z-index-sticky
  • --z-index-toast
  • --z-index-tooltip

Disambiguation — which token for this job?

Several tokens are semantically close. This section is the decision tree.

Which surface for a content area?
bg-background
the page itself, the lowest layer
bg-card
elevated content blocks (article cards, dashboard tiles, list rows that read as separate)
bg-popover
transient floating layers (dropdowns, tooltips, command palettes, comboboxes, datepickers)
bg-muted
low-emphasis fills inside a card or surface (input wells, deemphasized sections, code blocks, sidebar groups)
bg-secondary
secondary buttons, badges, low-emphasis interactive controls (NOT a backdrop)
bg-accent
highlight surface for active nav items, selected list rows, current-step indicators
Which foreground for body text?
text-foreground
primary body text, headings, labels — the default
text-foreground-subtle
captions, helper text, deemphasized headings (still legible)
text-muted-foreground
muted body copy on bg-muted, placeholders that aren't using --placeholder-color, ancillary metadata
text-foreground-disabled
disabled control labels — never use for design choice, only for disabled state
Which border for a divider/outline?
border-border
default outlines, dividers between sibling cards
border-border-subtle
low-contrast separators inside a card, table row dividers, list item separators
border-border-strong
emphasized outlines, hover/active outlines on cards, table column separators in dense layouts
border-input
form inputs only (slightly stronger than -subtle for affordance)
Which radius for this surface?
rounded-input
form inputs, search boxes, single-line text controls
rounded-button
buttons, icon buttons, segmented controls
rounded-chip
tags, filter pills, badges, status chips (pill-shaped)
rounded-card
content cards, dashboard tiles, list-row cards
rounded-popover
dropdowns, tooltips, comboboxes, hover cards
rounded-dialog
modal dialogs, alert dialogs (always centered, scrim behind)
rounded-sheet
side sheets, drawers, mobile bottom sheets
Which shadow for elevation?
shadow-card
content cards at rest
shadow-popover
floating layers (dropdowns, tooltips, comboboxes)
shadow-overlay
modal dialogs and side sheets — the highest elevation
shadow-focus
focus-ring glow on inputs (paired with the ring token)
shadow-inset
pressed states, sunken wells, scrollable region indicators
Which interactive state-layer?
bg-state-hover
hover affordance on buttons, list rows, nav items (4–6% layer)
bg-state-focus
keyboard-focus background — usually paired with the focus ring
bg-state-active
pressed state (8–12% layer)
bg-state-expanded
open/expanded affordance: aria-expanded='true' on triggers, current open menu item
bg-state-selected
persistent selection: selected row in a table, picked option in a list, current step in a wizard
Which duration for this motion?
duration-instant
0ms — feedback that should feel immediate (toggle flips, focus rings); also the motion-reduce: fallback
duration-fast
micro-interactions: hover, ripple, tooltip show, pressed feedback
duration-normal
layout reveals, panel slides, accordion expand, tab content swap
duration-slow
page transitions, large surface entrances, modal open
duration-slower
confidence-builder moments only (success animations, celebratory reveals)
Which container width?
max-w-(--container-prose)
article-style reading content, ~65ch — comfortable for body copy
max-w-(--container-content)
marketing pages, single-column docs, narrow forms
max-w-(--container-dashboard)
app shells with sidebars, multi-column dashboards (default for product UI)
max-w-(--container-wide)
data-heavy tables, design canvases, full-bleed dashboards

Migration map — Tailwind drift → tokens

When retrofitting an existing codebase, replace left with right.

From (drift)To (token)
bg-whitebg-background
bg-gray-50 / bg-zinc-50 / bg-slate-50bg-muted
bg-gray-100bg-muted
bg-gray-900 / bg-zinc-900 / bg-blackbg-card
bg-white shadow-md (a card)bg-card shadow-card
text-black / text-gray-900text-foreground
text-gray-700text-foreground-subtle
text-gray-500 / text-zinc-500text-muted-foreground
text-gray-400text-foreground-disabled
text-white (paired with a colored bg)text-{role}-foreground
border-gray-200 / border-zinc-200border-border
border-gray-100border-border-subtle
border-gray-300border-border-strong
border (on input)border-input
bg-red-500 / text-red-600bg-destructive / text-destructive (with paired foreground + border)
bg-green-500 / text-green-600bg-success / text-success
bg-yellow-500 / bg-amber-500bg-warning
bg-blue-500 / text-blue-600bg-info / text-info
rounded-md (control)rounded-input or rounded-button
rounded-lg / rounded-xl (card)rounded-card
rounded-2xl / rounded-3xl (modal)rounded-dialog or rounded-sheet
rounded-full (pill chip)rounded-chip
shadow / shadow-md (card)shadow-card
shadow-lg / shadow-xl (popover)shadow-popover
shadow-2xl (modal)shadow-overlay
z-10 (sticky header)z-sticky
z-40 (dropdown)z-dropdown
z-50 (overlay/modal)z-overlay or z-modal
duration-150 / duration-200duration-fast
duration-300duration-normal
duration-500duration-slow
ease-in-out (UI)ease-out (most cases)
size-4 (icon)size-(--size-icon-sm)
size-5 (icon)size-(--size-icon-md)
size-6 (icon)size-(--size-icon-lg)
h-10 (control)h-(--density-control-h)
min-h-[44px]min-h-(--size-touch-target)
max-w-2xl / max-w-3xl (article)max-w-(--container-prose) or max-w-(--container-content)
max-w-7xl (dashboard)max-w-(--container-dashboard)

Forbidden patterns

className="bg-black/30"
className="bg-overlay"

Inline color literal. Use --overlay or token-mapped utilities.

className="text-gray-500" /* or text-zinc-500 / text-slate-500 */
className="text-muted-foreground"

Tailwind palette literals never enter components. Muted body copy is text-muted-foreground; deemphasized headings are text-foreground-subtle.

className="bg-gray-100" /* or bg-zinc-100 / bg-slate-50 */
className="bg-muted"

Low-emphasis surface background is bg-muted. Inputs / wells / deemphasized sections all use it.

className="bg-zinc-900 text-white"
className="bg-card text-card-foreground" /* or bg-popover for floating */

Theme-fixed dark surfaces break light/dark mode. Pick the semantic surface (bg-card / bg-popover / bg-secondary) and pair it with its foreground.

className="border-gray-200"
className="border-border" /* or border-border-subtle for low contrast */

Use the 4-tier border vocabulary (border, border-subtle, border-strong, border-input). Never reach for Tailwind palette borders.

className="text-red-500"
className="text-destructive"

Status uses semantic names (destructive / success / warning / info), not red/green/yellow/blue.

className="bg-red-500 text-white"
className="bg-destructive text-destructive-foreground border border-destructive-border"

Solid status pattern requires the full triple: bg + foreground + border.

className="text-white" /* or text-black */
className="text-{role}-foreground" /* paired with its bg-{role} */

Theme-fixed text colors break dark mode. Pair every surface with its semantic foreground.

className="bg-destructive/10 text-destructive"
className="bg-destructive text-destructive-foreground border border-destructive-border"

Status uses the SOLID pattern. /10 on a pastel base loses contrast.

className="bg-card text-foreground/70"
className="bg-card text-card-foreground"

Always pair bg-{role} with text-{role}-foreground. Never split.

className="text-foreground/60"
className="text-muted-foreground"

Use the foreground hierarchy (foreground / -subtle / -disabled / muted-foreground), not opacity fractions.

className="rounded-3xl" /* or rounded-2xl */
className="rounded-card" /* or rounded-dialog / rounded-sheet */

Use the semantic radius vocabulary (rounded-button, rounded-input, rounded-chip, rounded-card, rounded-popover, rounded-dialog, rounded-sheet).

className="rounded-md" /* on a control */
className="rounded-input" /* or rounded-button */

Per-component radii are tokenized. rounded-md is a fallback, not the convention.

<button className="rounded-full px-3">Filter</button>
<button className="rounded-chip px-3">Filter</button>

Pill-shaped chips/badges/filters use rounded-chip — never raw rounded-full on text-bearing controls.

className="shadow-lg" /* or shadow-xl / shadow-2xl */
className="shadow-card" /* content */ /* or shadow-popover for floating, shadow-overlay for modal */

Shadows are tokenized by surface role: shadow-card, shadow-popover, shadow-overlay, shadow-focus, shadow-inset.

className="drop-shadow-md"
className="shadow-card"

drop-shadow is for SVG/icon glyphs. Surfaces use the shadow-* tokens.

className="z-50"
className="z-overlay" /* or z-modal / z-popover / z-tooltip / z-toast / z-dropdown / z-sticky */

The z-index ladder is locked across products. Pick the semantic level: sticky 30 < dropdown 40 < overlay 50 < modal/popover 60 < tooltip 70 < toast 80.

className="duration-200" /* or duration-150 / duration-300 */
className="duration-fast" /* or duration-normal / duration-slow / duration-slower */

Motion durations are tokenized: instant / fast / normal / slow / slower. Numbered Tailwind durations bypass the system.

className="ease-in-out" /* on UI motion */
className="ease-out" /* or ease-spring / ease-overshoot */

UI motion defaults to ease-out (decelerating). Reach for ease-spring for layout reveals and ease-overshoot for confidence-builder moments.

className="transition-all duration-200"
className="transition-colors duration-fast" /* or transition-transform */

transition-all triggers layout/paint on every property change. Be specific (colors / transform / opacity) and use a duration token.

<motion.div animate={{ x: 100 }} transition={{ duration: 0.3 }} />
<motion.div animate={{ x: 100 }} transition={{ duration: 0.2, ease: [0.16, 1, 0.3, 1] }} /> /* read tokens via CSS or constants */

Hardcoded Motion durations/easings drift from the design system. Pull values from the tokens (CSS getPropertyValue or a shared constants module).

<Icon className="size-5" />
<Icon className="size-(--size-icon-sm)" /> /* or --size-icon-md / --size-icon-lg */

Icon sizes use the locked --size-icon-* ratios. Hardcoded size-* doesn't survive density changes.

className="h-10"
className="h-(--density-control-h)"

Control heights use --density-control-h so they auto-tighten under data-density="compact". Hardcoded h-* breaks compact mode.

className="p-5"
className="p-(--density-card-padding)"

Card padding uses --density-card-padding (compact-aware). Reach for it before raw p-*.

className="min-h-[44px]"
className="min-h-(--size-touch-target)"

Touch target floor is tokenized at 44px via --size-touch-target. Don't hardcode the magic number.

className="ring-2 ring-blue-500"
className="ring-(length:--ring-width) ring-ring"

Focus ring is pinned at --ring-width: 3px. Use the canonical ring color.

className="focus:ring-2 focus:ring-blue-500"
className="focus-visible:ring-(length:--ring-width) focus-visible:ring-ring/40 focus-visible:border-ring focus-visible:outline-none"

Use focus-visible (not focus) and the canonical ring tokens. Pair with focus-visible:outline-none and a colored border.

className="hover:bg-gray-100 active:bg-gray-200"
className="hover:bg-state-hover active:bg-state-active"

Interactive states use the 5-stop state-layer scale (4/6/8/12/16% opacity), not Tailwind palette colors.

className="aria-expanded:bg-secondary"
className="aria-expanded:bg-state-expanded" /* or bg-state-selected */

Open/expanded/selected affordances are state-layer tokens, not surface roles.

className="gap-3 p-5"
className="gap-2 p-4" /* or gap-4 / p-6 */

Prefer even Tailwind spacing steps (2, 4, 6, 8, 10, 12). Odd steps usually mean fighting the layout — pick the nearest even step or reach for a density token.

<div><Card className="mb-4" /><Card className="mb-4" /></div>
<div className="flex flex-col gap-4"><Card /><Card /></div>

Margins collapse and fight stacking. Use gap-* on a flex/grid parent for sibling spacing.

className="max-w-3xl"
className="max-w-(--container-content)"

Page widths use container tokens (--container-content, --container-prose, --container-dashboard, --container-wide). Never ad-hoc Tailwind max-w sizes.

<input className="text-sm" />
<input className="text-base md:text-sm" />

iOS Safari focus-zoom rule. Text-entry surfaces must be ≥16px on mobile.

<input className="border" />
<input className="border-input" />

Inputs use --border-input (slightly stronger than --border-subtle for affordance). Generic border-* loses the input shape.

className="font-mono" /* on the brand wordmark */
className="font-display" /* paired with --font-display */

Display, heading, sans, and mono are distinct font roles. Don't reuse font-mono outside of code.

className="opacity-50" /* on a disabled control */
className="opacity-(--opacity-disabled)" /* or aria-disabled with --opacity-disabled */

Disabled / loading / pressed / hover / overlay opacities are tokenized so they're consistent across components.

<motion.div animate={{ opacity: 1 }} transition={{ duration: 0.4 }} />
<motion.div animate={{ opacity: 1 }} transition={{ duration: 0.4 }} className="motion-reduce:!duration-(--duration-instant)" />

Respect prefers-reduced-motion. Either gate the animation behind motion-safe: or collapse the duration to --duration-instant under motion-reduce:.

Common tasks

Status alert (any of destructive/success/warning/info)
<div className="flex gap-3 rounded-card border bg-{status} text-{status}-foreground border-{status}-border p-4">
  <Icon weight="fill" className="size-5 shrink-0" />
  <div>
    <p className="font-medium">Title</p>
    <p className="text-sm opacity-90">Body</p>
  </div>
</div>
Solid status badge
<Badge className="bg-success text-success-foreground border border-success-border">
  Active
</Badge>
Card with elevation
<div className="rounded-card bg-card text-card-foreground shadow-card ring-1 ring-border-subtle p-(--density-card-padding)">
  …
</div>
Focus-visible ring
className="focus-visible:outline-none focus-visible:ring-(length:--ring-width) focus-visible:ring-ring/40 focus-visible:border-ring"
Hover/active state via state-layer tokens
className="hover:bg-state-hover active:bg-state-active aria-expanded:bg-state-expanded"
Modal layering
<DialogOverlay className="fixed inset-0 bg-overlay z-overlay" />
<DialogContent className="z-modal rounded-dialog bg-popover text-popover-foreground shadow-overlay" />
Side sheet / drawer
<SheetContent className="z-modal rounded-sheet bg-popover text-popover-foreground shadow-overlay">
  …
</SheetContent>
Dropdown / popover
<PopoverContent className="z-popover rounded-popover bg-popover text-popover-foreground shadow-popover border-border-subtle">
  …
</PopoverContent>
Tooltip
<TooltipContent className="z-tooltip rounded-popover bg-popover text-popover-foreground shadow-popover px-2 py-1 text-xs">
  …
</TooltipContent>
Toast
<Toast className="z-toast rounded-card bg-card text-card-foreground shadow-overlay border-border-subtle p-4">
  …
</Toast>
Empty state
<div className="flex flex-col items-center gap-3 rounded-card bg-muted/40 border border-border-subtle p-(--density-card-padding) text-center">
  <Icon className="size-(--size-icon-lg) text-muted-foreground" />
  <p className="font-medium">No items yet</p>
  <p className="text-sm text-muted-foreground">Get started by creating one.</p>
</div>
Skeleton loading
<div className="rounded-card bg-card border border-border-subtle p-(--density-card-padding) space-y-3">
  <div className="h-4 w-1/3 rounded bg-muted animate-pulse" />
  <div className="h-3 w-2/3 rounded bg-muted animate-pulse" />
</div>
Form field (with iOS focus-zoom guard)
<label className="flex flex-col gap-1.5">
  <span className="text-sm font-medium">Email</span>
  <input
    type="email"
    className="h-(--density-control-h) rounded-input border-input bg-background px-3 text-base md:text-sm focus-visible:outline-none focus-visible:ring-(length:--ring-width) focus-visible:ring-ring/40 focus-visible:border-ring"
  />
</label>
Sidebar nav item
<a
  href="#"
  data-active={isActive}
  className="flex items-center gap-2 rounded-input px-3 h-(--density-control-h) text-sm hover:bg-state-hover data-[active=true]:bg-state-selected data-[active=true]:text-foreground"
>
  …
</a>
Compact density
<html data-density="compact"> {/* or scope to a section */}
  …controls auto-tighten via --density-* tokens
</html>
Chart series colors
const palette = Array.from({ length: 12 }, (_, i) => `var(--color-chart-${i + 1})`);
<Bar fill={palette[0]} /> // anchored to brand
Reduced-motion-safe animation
<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  transition={{ duration: 0.4 }}
  className="motion-reduce:!duration-(--duration-instant)"
/>

Either gate behind motion-safe: or collapse to --duration-instant under motion-reduce:.

Source-of-truth for tokens: app/globals.css. This page is generated from that file at build time so it never drifts.