Design SystemGuidelines

Guidelines

Practical rules that keep the ONCE interface consistent. These apply to both human developers and AI agents writing code in the codebase.

Animation

Motion is kept minimal and purposeful — only on hover and focus.

Allowed Transitions

PatternTailwindUsage
Color changetransition-colorsLinks, buttons, icon tints
Generaltransition-all duration-300Cards (hover lift + border change)

What to avoid

  • No entrance animations (fade-in, slide-up) on page load
  • No looping animations except approved status motion (Early Access badge pulse and AI thinking loader)
  • No parallax scrolling or scroll-triggered effects
  • No motion that could trigger vestibular discomfort

Hover Lift

Cards use a subtle upward shift on hover:

.card:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(58, 69, 92, 0.08);
}

The lift is 1px — not 2px or 4px. Keep it barely perceptible.

Dark Mode

ONCE is a dark-first design system. All components are designed for dark backgrounds first, then adapted for light mode.

Implementation

  • The docs site uses html.dark class toggling (Nextra’s built-in dark mode)
  • The dev-app uses Tailwind’s dark: variant
  • CSS custom properties swap between light and dark palettes via html.dark { ... }

Rules

  • Always test new components in dark mode first
  • Use var(—text-strong) and var(—text-subtle) instead of hardcoded colors
  • Backgrounds should use surface tokens, not raw hex values
  • Avoid pure white (#fff) on dark backgrounds — use —once-white with opacity

Naming Conventions

CSS Variables

  • Brand colors: --once-{name} (e.g., --once-blue, --once-bg)
  • Utility colors: --mr-{name} (e.g., --mr-approval)
  • Surface tokens: --surface, --surface-muted, --surface-strong
  • Text tokens: --text-strong, --text-subtle
  • Font tokens: --font-sans, --font-display, --font-mono

Tailwind Classes (dev-app)

  • Color utilities match the variable name: once-blue, mr-warning
  • Use with standard prefixes: bg-once-blue, text-once-white, border-once-blue/20

CSS Classes (docs)

  • Component classes are lowercase, hyphen-separated: card-grid, info-box, api-endpoint
  • State classes use semantic names: early-access-badge, patron-badge
  • Design system preview classes use ds- prefix: ds-swatch, ds-btn

Accessibility

Contrast

  • Primary text on --once-bg must meet WCAG AA (4.5:1 ratio minimum)
  • --once-blue-light (#6B7A99) is used instead of --once-blue for text on dark backgrounds, because the base blue does not pass contrast checks alone
  • Utility colors were chosen to pass AA on both light and dark backgrounds

Focus States

  • Interactive elements must have visible focus indicators
  • Use outline or box-shadow for focus rings — not border, which shifts layout
  • Default browser focus styles are acceptable if they remain visible on --once-bg

Reduced Motion

Respect prefers-reduced-motion for the badge pulse animation:

@media (prefers-reduced-motion: reduce) {
  .early-access-badge {
    animation: none;
  }
  .early-access-badge::before {
    animation: none;
  }
}

For AI Agents

If you are an AI agent working in this codebase:

  • Always use CSS variables (var(—once-blue)) — never hardcode hex values
  • Use the opacity scale for text hierarchy — do not invent new colors
  • Keep font-family to Manrope and JuliaMono — no other typefaces
  • Cards get border-radius: 12px, code blocks get 8px, inline code gets 4px
  • Test your output in dark mode. If it looks wrong in dark, it’s wrong
  • When in doubt, follow existing patterns in globals.css