@ai-created/ui
Design-system overview

Foundations

The decisions every surface inherits.

This is the implementation reference: token values, live specimens, and the exact CSS variables that resolve the same way in every component and every consuming product. The principles, decisions, and acceptance rules that govern them live in the Foundations guideline.

Design tokens

Every visual decision on this page resolves through one of 154 CSS custom properties declared in styles/tokens.css. Product UI consumes semantic names, never raw values.

Token decision hierarchy
LevelExampleWho consumes itRule
Reference--ref-red-500System maintainersStores a raw value. Never consumed directly in product UI.
Semantic--color-action-primaryDesigners and engineersNames intent and owns light, dark, and accent behavior.
ComponentButton / Primary / BackgroundComponent authorsMaps one component decision onto a semantic token.

Color

--color-*

Backgrounds, surfaces, text, borders, actions, and semantic feedback.

Layout

--layout-*

Container maximum, gutters, and section rhythm.

Radius

--radius-*

The complete corner scale: 4px, 6px, and 10px.

Motion

--motion-*

Duration steps consumed by components and the motion helpers.

Elevation

--shadow-elevation-*

The low, medium, and high shadow steps.

Colors

Nine accessible accent schemes share one semantic contract across dark and light mode. Status and destructive colors remain independent.

Semantic first

Components consume accent, action, focus, and selection roles. They never select a named hue directly.

Red by default

Existing consumers remain red until data-accent or ThemeProvider selects another supported scheme.

Meaning stays fixed

Destructive, success, warning, info, and error never change when the accent changes.

Dual-theme contract

Every role is independently tuned for dark and light foundations instead of mechanically inverted.

Accent schemes

Choose a scheme to preview the full portal. Dark display accents share the current red’s luminance target; light values and yellow-family actions deliberately deepen to preserve contrast.

Active red roles

Public utilities keep semantic names. The legacy red aliases resolve to these same active values for compatibility.

Meaning does not follow the accent

A green brand accent does not turn errors green, and a red accent does not make routine information destructive.

Success
Warning
Info
Error
Destructive

red in dark and light

Dark mode

Accent text remains readable on black foundations.

Primary actionHover state
#FF4B2B#D41010
Light mode

Accent text deepens to remain readable on white foundations.

Primary actionHover state
#C81E1E#D41010

Accessibility contract

  • -Accent, muted-accent, and hover text meet 4.5:1 on bg, surface, and surface2 in both themes.
  • -Primary action and hover fills meet 4.5:1 with on-action text and 3:1 against every foundation.
  • -Focus and accent borders meet 3:1 against all three foundations.
  • -Selection keeps primary text at 4.5:1 or better on every foundation.
  • -The browser suite exercises all nine accents across both themes: 18 appearance combinations per browser project.
  • -Color reinforces state but never carries meaning without text, iconography, or native semantics.

Typography

One serif for tone, one sans for almost everything else, and monospace for structure. The system works because serif usage is restrained.

Displayfont-display

Instrument Serif

The art of building software

The art of building software

The art of building software

Aa400 Regular

Hero titles, section headers, editorial moments. The only serif in the system — used sparingly for maximum impact.

Primary Sansfont-heading

Space Grotesk

Products that ship. Clear, readable text that scales from captions to paragraphs.

Products that ship. Clear, readable text that scales from captions to paragraphs.

Products that ship. Clear, readable text that scales from captions to paragraphs.

Aa300 Light
Aa400 Regular
Aa500 Medium
Aa600 Semi
Aa700 Bold

Headings, body text, navigation, UI labels. The workhorse typeface — geometric, distinctive, readable at every size.

Monospacefont-mono

System Monospace

const system = { status: "live" }

const system = { status: "live" }

const system = { status: "live" }

Aa400 Regular

Code, technical labels, badges, metadata. Uses the platform’s native monospace (SF Mono, Menlo, Consolas).

Role Recipes

Hero Title

font-display text-4xl md:text-7xl tracking-wide

Reserved for route-level hero moments and major page framing.

Section Title

font-display text-3xl md:text-5xl tracking-wide

Used for major sections on the homepage and key interior pages.

Card Title

font-heading text-lg or text-xl font-medium

Most UI titles should stay in Space Grotesk rather than borrowing display styling.

Metadata

font-mono text-xs uppercase tracking-wider

Use for dates, labels, statuses, platform markers, and structural utility copy.

Type Scale

Base font-size is set to 125% (20px). These are the computed sizes at that base.

text-xs15px
Published May 2026Meta labels, timestamps, badges
text-sm17.5px
Structured product and editorial copy.Card copy, controls, supporting UI
text-base20px
Clear, confident body text for authored content.Primary paragraphs and intro copy
text-lg22.5px
A system that stays readable while feeling premium.Hero subheads and summary lines
text-xl25px
What the interface should make obviousCard titles and callout headings
text-3xl37.5px
Section HeadingSection titles
text-5xl60px
Design SystemLarge display moments
Pairing in context

Building in the open

Editorial voice plus quiet UI typography

Serif creates the atmosphere. Space Grotesk carries the actual reading load. That split keeps the site expressive without making it fragile.

rule: use display typography sparingly

Accessibility Notes

  • -The effective base size is 20px, so the UI starts from a readable floor instead of relying on micro-type.
  • -Use real heading levels in page templates; display styling never replaces document structure.
  • -Serif is reserved for expressive moments. Dense UI, forms, and filters stay in Space Grotesk to preserve legibility.

Spacing & Layout

The site relies on a small set of repeatable spacing and layout recipes. Consistency here is what keeps the visual system tight.

Layout Recipes

Hero Frame

pt-32 pb-20 with centered max-w-4xl copy block

Used on browse and context pages. Homepage hero is larger, but follows the same centered copy logic.

Standard Section

py-20 with one clear heading and one primary grid or block

The default rhythm across homepage sections and most interior modules.

Feature Card

bg-surface border rounded-md p-8 md:p-12

Primary module shell for proof blocks, summaries, and larger content groups.

Grid Rhythm

gap-6 for cards and related modules

The system mostly relies on 24px gaps; larger jumps should be intentional and rare.

Overview + Workspace

compact summary row or cards above one active workspace panel

Use this on product-heavy surfaces when several tools or outputs share a page. Let users scan first, then work in one focused area.

Dense Toolbar

fixed-height controls with one trailing flex item that fills remaining width

Useful for source rows, filters, and compact control strips. Mixed controls should align by height and visual weight.

Spacing Scale

p-1
0.25rem4px
p-2
0.5rem8px
p-3
0.75rem12px
p-4
1rem16px
p-6
1.5rem24px
p-8
2rem32px
p-10
2.5rem40px
p-12
3rem48px
p-16
4rem64px
p-18
4.5rem72pxCustom
p-20
5rem80px
p-24
6rem96px
p-32
8rem128px

Border Radius

rounded-sm4px
rounded6px
rounded-md6px
rounded-lg10px
rounded-full9999px

Container

Viewport
.container-custom
max-width: 1400pxpadding: 2vw / 6vw on mobile

Responsive Strategy

Mobile-first with standard Tailwind breakpoints. Content wrappers control reading width, not the container.

sm: 640pxSmall tablets, 2-col grids
md: 768pxTablets, hero text scaling
lg: 1024pxDesktop sidebar, nav
xl: 1280pxWide grids, split layouts
Articlesmax-w-3xl
Hero Copymax-w-4xl
Gridsmax-w-6xl

Image Patterns

Consistent image handling across heroes, cards, and media embeds.

Video Embedsaspect-video or padding-bottom: 56.25% for 16:9
Fill Imagesnext/image with fill + sizes prop
Object Fitobject-cover default, object-contain for full visibility
LoadingLazy by default, priority for above-fold heroes

Accessibility Notes

  • -Every route must expose the shared skip-link target: `#main-content`.
  • -Source order should stay logical on mobile and desktop; visual rearrangement cannot break reading or tab order.
  • -Headings, sections, and landmarks are part of layout, not content garnish. The system expects both visual rhythm and structural rhythm.
  • -Toolbars should preserve shared hit areas and consistent control height so mixed buttons, dropdowns, and icon actions still read as one system.
  • -Overview regions and active workspaces should remain clearly grouped so screen-reader and keyboard users can distinguish scanning from editing.

Motion

Motion should support structure, emphasis, and state changes. If it cannot explain its purpose, it should not ship.

Entrance

Default to simple fade/slide reveals in the 0.45s to 0.6s range. They should clarify hierarchy, not become a visual event.

Hover

Use subtle lift, border emphasis, and color shifts. The public site should feel alive, not animated for its own sake.

State Change

The strongest motion belongs to real UI state changes such as menu open/close, theme toggles, and media interactions.

Allowed Patterns

These are the motion patterns that fit the public site.

Entrance

Fade plus a small upward movement.

Hover

Small lift plus stronger border, nothing theatrical.

State Cue

Reserved for actual state communication, not ambient decoration.

CSS Motion Tokens

These are the utility-level animations available to the system. Keep usage narrow and intentional.

Framer Motion Patterns

These are the standard Framer Motion patterns used across the site. Keep them consistent rather than inventing variations.

Entryinitial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
Viewportviewport={{ once: true }}
Animate once on scroll, do not repeat
Staggertransition={{ delay: index * 0.1 }}
Sequential items in grids and lists
Exit<AnimatePresence>
Mobile menu, theme toggle icon swap
Card HoverwhileHover={{ y: -2 }}
Subtle lift, duration 0.2s
Button TapwhileTap={{ scale: 0.85 }}
Toggle buttons, theme toggle

Avoid By Default

  • -Glitch, wave, shimmer, or neon treatments on core public pages.
  • -Perpetual decorative motion unless the route is explicitly an experimental surface.
  • -Large hover transforms that make cards feel unstable or playful when the rest of the system is controlled.

Accessibility Notes

  • -Motion must degrade cleanly under `prefers-reduced-motion`; the interface still needs clear hierarchy and state without animation.
  • -Do not rely on motion alone to explain selection, success, error, or hierarchy.
  • -Continuous motion should be rare and tied to state, never treated as ambient decoration on core routes.

Theme Rules

The system supports dark and light foundations plus nine accessible accent schemes. Theme, accent, motion, and semantic feedback are one appearance contract.

Implementation rules

  • -Prefer semantic tokens such as bg-bg, bg-surface, text-text2, and border-border before reaching for raw white or black utilities.
  • -text3 is metadata only. Do not use it for critical navigation or long-form body copy, especially in light mode.
  • -Use bg-action-primary or bg-action-destructive with text-on-action for filled actions. Primary follows the accent; destructive never does.
  • -Prefer shared primitives such as Button, Surface, TextInput, and TextArea before rebuilding interaction styling route by route.
  • -Accent hover values are state roles, not standalone palette choices. Do not select numbered reference steps in product code.
  • -Focus styling is tokenized. Do not invent ad hoc focus colors that drift from the system.
  • -Status feedback uses semantic success, info, warning, and error tokens instead of borrowing brand red for every message.
  • -Choose a persisted preference with useTheme, a fallback with defaultAccent, or a fixed product accent with accent.
  • -Hero media uses shared theme variables and the ThemedHeroImage component. Do not hand-roll overlay colors or theme swaps in route components.
  • -A component is not done until it works credibly in both dark and light themes.

How it works

ThemeProviderappearance owner / storagehtml.light + data-accentCSS vars update

Preference mode reads theme and accent before first paint; fixed mode reads only theme and keeps its server-rendered accent. The .theme-transitioning class enables smooth 0.3s transitions only after user-initiated changes.

Accent color

Change the portal appearance

Every semantic component adapts to theme and accent without hue-specific component branches.

Three accent selection modes

defaultAccent

Uncontrolled fallback. Resolution is saved preference, existing data-accent, this default, then red.

useTheme().setAccent

Use with accentNames for a picker. Changes update the document and persist for the user.

accent + onAccentChange

Controlled mode. The prop wins and stays fixed; requests call the callback without persistence. The callback also observes uncontrolled changes.

For a fixed product accent, pair data-accent="blue" on the initial html element with <ThemeProvider accent="blue"> and use a theme-only pre-hydration script.

tsx
// Persisted user preference: render the fallback before hydration.
<html data-accent="blue">
  <head>{/* Run the validated theme + accent storage script from the README. */}</head>
  <body>
    <ThemeProvider defaultAccent="blue">{children}</ThemeProvider>
  </body>
</html>

// Fixed product accent: ignore saved accent storage.
<html data-accent="blue">
  <head>{/* Run the theme-only initialization script from the README. */}</head>
  <body>
    <ThemeProvider accent="blue">{children}</ThemeProvider>
  </body>
</html>

// Externally controlled accent: the owner applies callback requests.
<ThemeProvider accent={accent} onAccentChange={setAccent}>
  {children}
</ThemeProvider>
css
:root {
  --radius-md: 6px;
  --layout-container-max: 1400px;
  --motion-base: 0.3s;
  --color-bg: #0A0A0B;
  --color-surface: #101113;
  --color-text: #F5F7FA;
  --color-focus: #FF4B2B;
  --color-accent: var(--ref-accent-current-400);
  --color-accent-hover: var(--ref-accent-current-500);
  --color-action-primary: var(--ref-accent-current-700);
  --color-action-primary-hover: var(--ref-accent-current-800);
  --color-action-destructive: #B91C1C;
  --color-on-action: #FFFFFF;
  --color-success: #55D39A;
  --color-info: #6BB9FF;
}

html.light {
  --color-bg: #F2EDE6;
  --color-surface: #F7F3EC;
  --color-text: #1D1D1F;
  --color-focus: var(--ref-accent-current-750);
  --color-accent: var(--ref-accent-current-750);
  --color-accent-hover: var(--ref-accent-current-900);
  --color-action-destructive: #9F1239;
  --color-success: #065F46;
  --color-info: #1E40AF;
}

html[data-accent='blue'] {
  /* Switches the current accent reference family; semantic utilities stay unchanged. */
}

Token Reference

Variable
Dark
Light
--radius-md
6px
6px
--layout-container-max
1400px
1400px
--motion-base
0.3s
0.3s
--color-bg
#0A0A0B
#F2EDE6
--color-surface
#101113
#F7F3EC
--color-surface2
#14161A
#EAE4DB
--color-text
#F5F7FA
#1D1D1F
--color-text2
rgba(245,247,250,0.72)
rgba(29,29,31,0.72)
--color-text3
rgba(245,247,250,0.62)
rgba(29,29,31,0.68)
--color-accent
#FF4B2B
#C81E1E
--color-accent-hover
#F13A1D
#B80E0E
--color-action-primary
#D41010
#D41010
--color-action-primary-hover
#C81010
#C81010
--color-action-destructive
#B91C1C
#9F1239
--color-on-action
#FFFFFF
#FFFFFF
--color-border
rgba(255,255,255,0.10)
rgba(0,0,0,0.10)
--color-border-strong
rgba(255,255,255,0.16)
rgba(0,0,0,0.18)
--color-control-border
rgba(255,255,255,0.36)
rgba(0,0,0,0.42)
--color-control-border-strong
rgba(255,255,255,0.50)
rgba(0,0,0,0.54)
--color-focus
#FF4B2B
#C81E1E
--color-overlay
rgba(0,0,0,0.60)
rgba(0,0,0,0.45)
--color-highlight
rgba(255,255,255,0.05)
rgba(0,0,0,0.04)
--color-success
#55D39A
#065F46
--color-success-surface
rgba(85,211,154,0.12)
rgba(6,95,70,0.08)
--color-info
#6BB9FF
#1E40AF
--color-warning
#F2B84B
#713F12
--color-error
#FF6B6B
#9F1239

Accessibility Checks

  • -Verify contrast and focus visibility in both themes before shipping.
  • -Filled actions must keep at least 4.5:1 foreground contrast through the primary/destructive and on-action token pairs.
  • -Every accent must pass text, focus, boundary, hover, and selection checks across bg, surface, and surface2 in dark and light mode.
  • -Success, info, warning, and error surfaces should remain readable in both themes and should not become accidental brand accents.
  • -The theme toggle itself must remain clearly named and keyboard-usable.
  • -If a theme-specific exception is required, document why it exists and how it avoids becoming permanent design debt.