Skip to content
RealBrain Design System v2.0
tokens.css realbrain.cc

REALBRAIN · DESIGN SYSTEM · V2.0

Premium comes from restraint.

One accent per screen. Flat surfaces separated by hairlines. Type that carries hierarchy through size, not weight. Every value a named token, shipped as one plain CSS file that any RealBrain project can link in a minute.

16Colour tokens
13Components
2Themes
2Densities
1Accent per screen
600Max font weight

Getting started

The system is one CSS file with no build step and no framework coupling. There is no npm package on purpose: a URL is easier to keep in sync than a version matrix.

1. Link it

For prototypes, link the canonical URL. Tokens, base reset, fonts, every component, and the composed patterns all come with it.

<link rel="stylesheet" href="https://realbrain.cc/design-system/tokens.css">

2. Vendor it for anything that ships

A deploy should never depend on another origin. Copy the file into the repository and import it once, globally. The version line at the top is what to compare when you update.

curl -o src/tokens.css https://realbrain.cc/design-system/tokens.css

3. Use the classes

The classes go straight into markup, the way utility classes would. Thin wrapper components are fine when you want prop-driven variants, but keep the styles in the one shared stylesheet, never in a scoped block that will drift.

<!-- RbButton.vue -->
<template>
  <button class="btn" :class="`btn-${variant}`" :aria-disabled="loading || undefined">
    <span v-if="loading" class="spinner" aria-hidden="true"></span>
    <slot />
  </button>
</template>
<script setup>
defineProps({ variant: { type: String, default: 'primary' }, loading: Boolean })
</script>

4. Themes and density

Dark is the default. Light is one attribute on <html>. Density is one class on a container, chosen once per product. Try both with the switches in the top bar: every component on this page responds.

document.documentElement.setAttribute('data-theme', 'light')  // light
document.documentElement.removeAttribute('data-theme')        // back to dark

document.body.classList.add('density-compact')                // 32px controls for dense tooling

Tailwind v4

Tailwind can consume the tokens without duplicating a value. @theme inline makes each utility use the variable, so the theme switch keeps working. With --spacing: 4px, Tailwind's numeric scale lines up with the space tokens: p-4 is 16px, p-6 is 24px, p-12 is 48px.

@import "tailwindcss";
@import "./tokens.css";

@theme inline {
  --color-*: initial;                 /* drop Tailwind's palette: tokens only */
  --color-bg: var(--bg);
  --color-surface: var(--surface);
  --color-elevated: var(--elevated);
  --color-text-1: var(--text-1);
  --color-text-2: var(--text-2);
  --color-text-3: var(--text-3);
  --color-accent: var(--accent);
  --color-accent-fg: var(--accent-fg);
  --color-success: var(--success);
  --color-warning: var(--warning);
  --color-error: var(--error);
  --color-info: var(--info);
  --color-border: var(--border);
  --color-border-strong: var(--border-strong);

  --font-sans: var(--font-ui);
  --font-mono: var(--font-mono);
  --spacing: 4px;
  --radius-sm: var(--radius-sm);
  --radius-md: var(--radius-md);
  --radius-lg: var(--radius-lg);
  --radius-full: var(--radius-full);
  --ease-rb: var(--ease);
}
Fonts tokens.css imports IBM Plex Sans and IBM Plex Mono from Google Fonts at weights 400, 500, and 600. If a CSP blocks that origin, self-host the same three weights and delete the @import line from the vendored copy. The stacks fall back to system-ui and ui-monospace, so a blocked font is a degraded page, not a broken one.

Colour

Sixteen tokens, two themes, one accent. Chips are painted with the live CSS variables; the hex shown is the value for the active theme. Switch the theme in the top bar to compare.

Technique worth reusing --accent-hover and --accent-pressed are not hardcoded. They are color-mix() formulas relative to --accent, which is why the light theme does not redefine them. Prefer this over hand-picking a shade whenever a colour is derived from another.

Both themes

TokenDarkLightRole

Verified contrast

WCAG relative luminance. AA thresholds: 4.5:1 for body text, 3:1 for large text. Every pair the system relies on passes in both themes. Hold any new colour to the same bar before it becomes a token.

PairDarkLightResult

Typography

Two families: IBM Plex Sans for UI and IBM Plex Mono for code, data, and IDs. Weights 400, 500, and 600 only. The font import does not load 700, so nothing can accidentally use it.

The weight column is typical usage per step. Components pin their own weight explicitly: buttons and field labels use --fs-2 at 500 even though body copy at the same step is 400. Check the component's CSS rather than assuming from the ramp.

Spacing

A 4px base unit with nine non-linear steps: tight at the low end for component internals, wide at the high end for section rhythm.

Radius & shadow

Four radii. Three shadows that exist only to say "this surface is above the page". Never a glow.

Radius

Shadow

Structural depth cues for elevated surfaces: menus, popovers, modals, toasts. A card at rest has no shadow. The light theme uses a tinted rgba(20,20,30) at lower alpha instead of pure black.

Motion

One easing curve, three durations. Under prefers-reduced-motion: reduce all three collapse to 0ms and every animation and transition on the page is forced to 0ms. No springs, no bounce, no tilt-on-hover.

--dur-1
--dur-2
--dur-3

--dur-1: 120ms;   /* hover and press colour shifts */
--dur-2: 200ms;   /* toggles, small state changes */
--dur-3: 360ms;   /* toast enter, larger transitions */
--ease: cubic-bezier(.22,.61,.36,1);   /* the only curve */

.btn { transition: background var(--dur-1) var(--ease); }

Layout & density

Two content widths and two densities. A marketing page is comfortable, a dense admin console is compact, and a single screen is never both.

TokenValueUse
<body class="density-comfortable">  <!-- 44px controls: marketing, consumer apps (default) -->
<body class="density-compact">      <!-- 32px controls: admin consoles, dev tools -->

Brand chrome

The system's own mark is CSS only: an accent square with a mono, weight-600 "R" in --accent-fg. The company's neural-network logo is a separate asset; on v2 surfaces use a single-colour version filled with currentColor so it reads in both themes.

.r-mark · .r-mark-lg · .theme-toggle · neural mark

Button

Four variants. One .btn-primary per screen; everything else is secondary, ghost, or neutral text. Height and padding come from the density tokens, so set density on an ancestor, not per button.

.btn + .btn-primary / .btn-secondary / .btn-ghost / .btn-destructive
  • States: default, hover, :focus-visible (2px accent ring, 2px offset), active, disabled, loading.
  • Loading uses aria-disabled="true" plus .spinner, not the native disabled attribute, so the button stays focusable and announced.
  • Copy: sentence case, verbs not nouns. "Sign in", never "Sign In" or "Login". Destructive actions name the object: "Delete workspace", not "Delete".
<button class="btn btn-primary" aria-disabled="true">
  <span class="spinner" aria-hidden="true"></span>Signing in…
</button>

Field

A label, a control, and help or error text wired together with aria-describedby. Error copy says what is wrong and shows the fix. No "Invalid input" dead ends.

We only use this to sign you in.

That email is missing a domain. Add one after the @, like [email protected].

.field > label + .input / .select + .help / .error-msg
  • .select is a native <select> with appearance: none and a CSS-drawn chevron. No JS dropdown for the basic case.
  • Always aria-describedby to the help or error text, and aria-invalid="true" on error.

Checkbox & radio

Real native inputs with appearance: none, redrawn in CSS. Keyboard and screen-reader behaviour come free.

.check-row > .checkbox / .radio

Toggle

A visually hidden real checkbox under a track and knob. opacity: 0, not display: none, so focus and keyboard work. Always give the input an aria-label or a visible label.

.toggle > input + .track > .knob

Card

Standard cards are flat: surface on bg, hairline border, --radius-md, --space-5 padding, no shadow at rest. .elevated is for content that is actually above the page, not for making a card stand out.

Standard card

Surface on bg, 1px border, radius-md, space-5 padding. No shadow at rest.

Elevated card

Elevated surface with shadow-md. Reserve for overlays and popped content.

.card · .card.elevated

Toast

A permanent role="status" live region; toasts are appended and removed. Self-dismisses after five seconds or on the dismiss button. The left border colour signals type, always with the icon.

.toast-region > .toast

Tabs

The ARIA tabs pattern with roving tabindex: the selected tab is 0, the rest are -1. Arrow keys, Home, and End move selection and focus together. Click a tab, then try the arrow keys.

Three services healthy. Last deploy 12 minutes ago.
.tabs > [role=tablist] > [role=tab] · [role=tabpanel]
const list = document.querySelector('[role="tablist"]')
const tabs = [...list.querySelectorAll('[role="tab"]')]
function select(tab) {
  tabs.forEach(t => {
    const on = t === tab
    t.setAttribute('aria-selected', on)
    t.tabIndex = on ? 0 : -1
    document.getElementById(t.getAttribute('aria-controls')).hidden = !on
  })
  tab.focus()
}
list.addEventListener('click', e => e.target.matches('[role="tab"]') && select(e.target))
list.addEventListener('keydown', e => {
  const i = tabs.indexOf(document.activeElement)
  if (i < 0) return
  const next = { ArrowRight: i + 1, ArrowLeft: i - 1, Home: 0, End: tabs.length - 1 }[e.key]
  if (next === undefined) return
  e.preventDefault()
  select(tabs[(next + tabs.length) % tabs.length])
})

Table

No zebra striping. Rows separate with hairlines. IDs and numbers use .mono and .num. Compact density tightens the cell padding; try it in the top bar.

ScanTargetStatusFindings
#4812api.realbrain.ccPassed0
#4811forum.realbrain.ccDegraded2
#4810accounts.realbrain.ccFailed3
#4809realbrain.ccQueued
.table-wrap > .table · td.mono · td.num

Status

A currentColor dot plus text. This is the "colour is never the only signal" rule made concrete. Never ship a bare swatch or coloured text alone to mean pass, fail, or warn.

Passed Degraded Failed Queued
.status.ok / .warn / .err / .info

App scaffold

Top bar, side nav, and main area: the shell for a product console. The active link is signalled by background plus an inset left accent bar, not colour alone. Not for marketing pages.

Console

No projects yet

Create your first project to start building. It takes about a minute.

.scaffold > .topbar + .body > .sidenav + .main

Empty state

Dashed border, centred, and always paired with an action. Never a dead end.

No scans yet

Run your first scan to see findings here. Most take under two minutes.

.empty > .glyph + h4 + p + .btn

Skeleton

Loading placeholders on the elevated surface with a shimmer that respects reduced motion through the global rule.

.skeleton

Composed screens

Four starting layouts, each built only from the tokens and components above. Use a product shell for a product surface. Do not use one for a marketing page.

Marketing hero

Comfortable density. Eyebrow, one display heading, one lead paragraph, a primary and a secondary action.

REALBRAIN · SOFTWARE LAB

We build intelligent software for the world.

From AI tools to enterprise software: products that think, adapt, and deliver.

.hero > .eyebrow + h1 + p + .cta-row

Editor shell

Comfortable density. A dark canvas with a checkerboard transparency preview, a narrow side panel, and one primary action. The shape of a single-canvas tool such as BG Remover.

BG Remover Processed
.bgr > .bgr-top + .bgr-body > .bgr-canvas > .checkerboard · .bgr-side

Compiler

Compact density, mono type. Source and output panes over a status bar. The shape of any dev tool with a split view.

main.rbReady
Source12 lines
// Compute the accent hover colour
const hover = mix('oklab', accent, white, '14%')
export { hover }
Output0 warnings
#9EB5FF
// contrast on --accent-fg: 10.2:1
Built42 ms
.compiler > .compiler-top + .compiler-panes > .compiler-pane + .compiler-status

Dashboard

Compact density. Stat cards over an alert table, with semantic colour always paired with a dot and text. The shape of a security or operations console.

Open findings
7
Assets scanned
312
Last scan
4m
SeverityFindingAsset
CriticalExpired TLS certificateapi.example.com
MediumMissing security headerswww.example.com
LowOutdated dependencyworker-01
.secdash > .secdash-nav + .secdash-main > .stat-row > .stat-card · .table-wrap

Content & interaction rules

The condensed version. Skim this even if nothing else.

Do

  • Use --accent for the single primary action on a screen. Everything else stays neutral.
  • Snap every value to the nearest token. If none fits, stop and flag it ⚑ NEW TOKEN with a proposal.
  • Pair semantic colours with a dot or icon and text.
  • Write errors as what happened plus what to do next, in sentence case.
  • Say "Sign in", not "Log in". Pick one density per product and keep it.

Don't

  • No font weight above 600, anywhere.
  • No gradients, glassmorphism, blur, or decorative shadows.
  • No white text on accent. Always --accent-fg.
  • No raw hex or px in component code. Tokens only.
  • No mixing densities within one product. No "Log in". No Title Case Buttons.

Error copy

"That email is missing a domain. Add one after the @, like [email protected]." Not "Invalid email". The pattern is what is wrong + a concrete example of the fix, and it is baked into the field example above.

Accessibility

The system is built so most of this is free. Verify it stays that way on each screen.

  • Text meets 4.5:1 on the surface it sits on (3:1 at --fs-6 and above). The token pairs in Colour already do; new combinations must be checked.
  • Every interactive element shows the 2px accent focus ring on :focus-visible. Do not remove outlines.
  • Controls are at least 44px tall in comfortable density; 32px in compact is for pointer-precision tooling only.
  • Fields have a visible label, aria-describedby to help or error text, and aria-invalid on error.
  • Loading buttons use aria-disabled, not disabled, so they stay in the tab order and are announced.
  • Modals are native <dialog>. Toasts live in a role="status" region. Tabs use the ARIA tabs pattern with roving tabindex.
  • Status is dot plus text. Charts and badges follow the same rule.
  • Motion goes through the duration tokens, which collapse to zero under reduced motion.
  • color-scheme is declared per theme, so native form controls and scrollbars match.

Governance

If you need a value that does not exist in tokens.css:

  1. Do not invent a raw hex or px inline "just this once".
  2. Check whether an existing token is close enough semantically, not just numerically. A new destructive-adjacent colour probably wants --error, not a new red.
  3. If it is genuinely new, flag it in your output as ⚑ NEW TOKEN with the proposed name (--{category}-{step} or --{semantic-name}), the value, and why nothing existing fits.
  4. Do not silently fix drift you notice elsewhere either. Flag it the same way so the pattern stays visible.

Tokens change in one place: tokens.css in the realbrain.cc repository. A deploy republishes every file in Files. Projects that vendored the file update by re-running the curl and diffing. Breaking changes (a renamed or removed token) bump the major version; new tokens or components bump the minor.

For AI agents

Everything on this page exists in a form an agent can fetch. The short index fits in a few hundred tokens; the full guide is the same content as this page in Markdown.

  1. Fetch llms.txt first. It has the rules and a quick reference for both themes.
  2. Fetch tokens.css and use its classes and variables directly. Do not restyle a component that already exists there.
  3. Read the relevant section of design-system.md for the component or pattern you are building.
  4. If the repository has no agent instructions yet, copy AGENTS.md in as AGENTS.md or CLAUDE.md and adjust the vendored-file path.
  5. Before finishing, run the self-check in that file.

Point an agent at it

This project uses the RealBrain Design System. Before writing any UI or CSS:
1. Fetch https://realbrain.cc/design-system/llms.txt and follow its rules.
2. Use the classes and variables from https://realbrain.cc/design-system/tokens.css directly.
3. For component markup and states, read the matching section of https://realbrain.cc/design-system/design-system.md.
Tokens only, one accent per screen, no weight above 600, no gradients. Flag anything missing as ⚑ NEW TOKEN instead of inventing a value.

Self-check

From the repository root, adjusting src. Every command should print nothing.

# raw colours or px outside the token file
grep -rnE --include=*.css --include=*.vue --include=*.jsx --include=*.tsx --include=*.svelte \
  --exclude=tokens.css '#[0-9a-fA-F]{3,8}\b|rgba?\(|\b[0-9]+px\b' src

# forbidden weight and effects
grep -rnE --include=*.css --include=*.vue --include=*.jsx --include=*.tsx --include=*.svelte \
  --exclude=tokens.css 'font-weight:\s*(700|800|900|bold)|linear-gradient|radial-gradient|backdrop-filter|text-shadow' src

# copy rules
grep -rniE --exclude-dir=node_modules 'log ?in|Sign In\b|Log In\b' src

Files

Every file is published from the realbrain.cc repository on deploy, generated from the one canonical tokens.css.

tokens.css
Canonical CSS: tokens, base reset, brand chrome, every component, composed patterns. Framework-agnostic.
Open
tokens.json
The same tokens in the W3C Design Tokens format (DTCG 2025.10), both themes, with computed contrast ratios. For Style Dictionary, Tokens Studio, or scripts.
Open
design-system.md
This guide as Markdown, tables generated from tokens.css.
Open
llms.txt
Short index for AI agents: rules, quick reference for both themes, links.
Open
AGENTS.md
Drop-in instructions for a new RealBrain repository, with a self-check.
Open
starter.html
A minimal page wired to tokens.css: hero, cards, a form, and a status row. Copy it to start a new surface.
Open

Delete this workspace?

All 14 projects and their build history will be removed. This can't be undone. Export anything you need first.