The rules of the road
Kaotypr Design System is a single canonical theme. Most decisions about names, structure and pairings have already been made — and locked. The job of a consumer project is to override the tunable bits, not to redesign the system.
The three tiers
Every token in the system carries one of three tier labels. The label tells you whether you may override the value in your project, and how loud the consequences are if you do.
Never override per-project.
- z-index scale (cross-product layering)
- --ring-width = 3px
- Status hue conventions (red=destructive, green=success, …)
- State-layer opacities (4/6/8/12/16%)
- --size-* ratios
- Opacity scale
Override expected per-project. The reskin lever.
- Surfaces (--background, --card, --popover)
- Foreground hierarchies
- --primary, --secondary, --accent
- Status lightness/chroma
- Fonts
- Semantic radii (--radius-button, --radius-card, …)
- Chart palette
Any project may override.
- Shadows
- Motion durations & easings
- --overlay opacity
- Per-control surfaces (switch, slider, scrollbar, skeleton)
- --placeholder-color
- Link / code / kbd treatments
- Blur scale
Structural locks
These structural shapes are part of the system identity. Even “tunable” values are tunable within these shapes — never tunable to a different shape.
- 3-tier foreground.
--foreground→--foreground-subtle→--foreground-disabled. Never collapse to two tiers. - 4-tier border.
--border/--border-subtle/--border-strong/--border-input. - Status triple. Every status name comes with a
-foregroundand a-borderpeer. Never split. - Status hue conventions. red = destructive, green = success, yellow/orange = warning, blue = info. Hue is locked; lightness and chroma are tunable.
- Five-stop state-layer opacities. 4 / 6 / 8 / 12 / 16 percent. These map to
--state-expanded,--state-hover,--state-focus,--state-active,--state-selected. - --size-* scale ratios. Icon, avatar, control sizes. Locked.
Spacing & grid
Spacing and grid are deliberately nottokenized. Kaotypr Design System inherits Tailwind v4's default ratio scale (--spacing: 0.25rem) and Tailwind's default breakpoints. Tokenizing spacing per-product would duplicate that scale without adding intent — so it's left as a system-wide constant.
Three places hold structural spacing tokens — reach for these before raw Tailwind utilities:
- Density for component padding and field gap:
p-(--density-card-padding),h-(--density-control-h),gap-(--density-field-gap). These auto-tighten underdata-density="compact". - Layout for page widths:
max-w-(--container-content),max-w-(--container-prose),max-w-(--container-dashboard),max-w-(--container-wide). Never ad-hocmax-w-3xl. - Sizing for control / icon / avatar dimensions:
--size-control-md,--size-icon-sm, etc. Locked ratios.
Rules of thumb for everything else:
- Prefer Tailwind's spacing scale in even steps:
2,3,4,6,8,10,12. Avoid1.5,2.5,5unless the layout truly requires them. - Reach for
gap-*on a flex / grid parent beforem-*on children. Margins collapse and fight stacking; gap composes. - Page gutters use
px-4 md:px-6 lg:px-10conventionally — match the site shell padding for consistency. - Grid columns use Tailwind's defaults (
grid-cols-1 md:grid-cols-2 lg:grid-cols-3). No tokenized grid system; pick column counts that match your content's natural breakpoints. - Touch targets stay ≥
--size-touch-target(44px). On mobile, never let an interactive element fall below that.
Forbidden patterns
The system is unforgiving about these. They're bugs, not opinions.
<div className="bg-black/30 rounded-3xl z-50">…</div><div className="bg-overlay rounded-card z-overlay">…</div>Inline color/radius/z-index values. Use the token vocabulary.
<div className="bg-destructive/10 text-destructive">Error</div><div className="bg-destructive text-destructive-foreground border border-destructive-border">Error</div>Status uses the solid pattern. /10 on a pastel base loses contrast.
<div className="bg-card text-foreground/70">…</div><div className="bg-card text-card-foreground">…</div>Semantic foreground pairs. Never split bg-{role} from text-{role}-foreground.
<input className="text-sm" /><input className="text-base md:text-sm" />iOS Safari focus-zoom rule. Text inputs must be at least 16px on mobile.
<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.
<div className="gap-3 p-5">…</div><div className="gap-2 p-4">…</div>Prefer even Tailwind spacing steps (2, 4, 6, 8, 10, 12). Odd steps usually mean fighting the layout — pick the nearest even step or a density token.
The semantic-pairs rule
For every surface there is exactly one foreground. Always render them together: bg-card text-card-foreground, bg-popover text-popover-foreground, bg-primary text-primary-foreground. If you find yourself reaching for text-foreground/60, you're fighting the system.
The focus ring
Pinned at --ring-width: 3px across the entire system. The focus indicator should look identical in every Kaotypr product. never override.