Swivel Design System

One stylesheet for every Swivel surface.

Tokens, type, components, page patterns, and voice for the command center of modern ad operations. Link one file and you get the brand fonts, every token in both themes, and every component class. Agents read the same rules from llms.txt.

Get started.

Link the stylesheet from any origin. Fonts are served with CORS, so it works from a prototype on your laptop as well as from a product domain.

<link rel="stylesheet" href="https://design-system.swivel-dev.net/stylesheet.css">

Then build from the system's classes and tokens. Nothing else is required.

<h1 class="t-h1">A million decisionS a minute.</h1>
<p class="t-body">You set the rules. Swivel executes against them.</p>
<button class="btn btn-accent">Run playbook</button>

Working with an agent.

Point Claude, Cursor, or any coding agent at https://design-system.swivel-dev.net/llms.txt. It carries the theme contract, the component selection rules, page patterns, copy rules, and every token with both theme values, all generated from the same source as this page.

Use the Swivel design system. Read https://design-system.swivel-dev.net/llms.txt first and follow it.

Dark by default.

With no attribute set, every token resolves to its dark value. data-theme="light" opts a page or any subtree into light, and data-theme="dark" nests a dark island inside a light page. The token names stay the same, so markup is written once.

data-theme="dark" (default)
Actions / 24h 1,284
12%vs last week
Healthy
data-theme="light"
Actions / 24h 1,284
12%vs last week
Healthy

Every artifact ships a working switch.

Use the canonical .theme-switch: sun, track, moon, and no text label. It is a switch, never a button group, and aria-checked="true" means dark. Persist the choice to localStorage under swivel-theme and apply it in <head> before first paint. The one in this page's header is the real thing.

<button type="button" class="theme-switch" role="switch" aria-checked="true" aria-label="Dark mode" data-theme-switch>
  <span class="ts-ico ts-sun material-symbols-outlined">light_mode</span>
  <span class="ts-track"></span>
  <span class="ts-ico ts-moon material-symbols-outlined">dark_mode</span>
</button>

The full script, including the before-first-paint step, is in llms.txt under Theming.

Four colors, used with discipline.

Switch, Graphite, Slate, and white. No other hues, and no gradients unless they come from the palette. Status colors mark data states only, never decoration.

Graphite + Switch→Product default
White + Graphite→Light marketing
Switch + Graphite→Call-out blocks

Tokens.

Each swatch paints with its variable, so it follows the theme switch. D is the dark value, L the light one. Names describe a role, and the ramps invert between themes to keep it: --graphite-90 is primary text in both.

Switch.

  • --switch-100#A8F8FF#A8F8FF
  • --switch-bg#1F4A4E#D6FEFF
  • --switch-contrast#00E5FF#0097A7

Graphite.

  • --graphite-10#2C3030#F0F1F0
  • --graphite-20#3A3E3D#D4D6D5
  • --graphite-30#4A4F4E#B8BAB9
  • --graphite-40#646866#9C9F9E
  • --graphite-50#808382#808382
  • --graphite-60#9C9F9E#646866
  • --graphite-70#B8BAB9#484C4B
  • --graphite-80#D4D6D5#2C3030
  • --graphite-90#F2F3F2#131514
  • --graphite-base#F2F3F2#131514
  • --graphite-bg#B8BAB9#6B7170
  • --graphite-contrast#131514#000000

Slate.

  • --slate-10#F0F3F7#F0F3F7
  • --slate-20#DCE4ED#DCE4ED
  • --slate-30#C8D5E3#C8D5E3
  • --slate-40#B4C6D9#B4C6D9
  • --slate-50#A0B7CF#A0B7CF
  • --slate-60#8CA8C5#8CA8C5
  • --slate-70#7899BB#7899BB
  • --slate-80#6F8BA7#6F8BA7
  • --slate-90#677F9F#677F9F
  • --slate-100#637D9C#637D9C
  • --slate-110#567088#567088
  • --slate-120#496374#496374
  • --slate-130#3C5660#3C5660
  • --slate-140#2F494C#2F494C
  • --slate-150#223C38#223C38
  • --slate-base#7B9BBF#637D9C
  • --slate-bg#1E3048#DCE8F5
  • --slate-contrast#A8C5E8#1A2D42
  • --slate-bg-50rgba(30, 48, 72, 0.5)rgba(220, 232, 245, 0.5)

Surface.

  • --white#E0E0E0#FFFFFF
  • --white-contrast#BDBDBD#9E9E9E
  • --surface-base#1E2120#FFFFFF
  • --surface-canvas#131514#FCFCFC
  • --surface-muted#1A1C1B#F0F1F0
  • --surface-stroke#2C3030#D4D6D5
  • --surface-input#1E2020#FFFFFF

Status.

  • --success#43A047#2E7D32
  • --success-bg#1B3A1C#C8E6C9
  • --success-fg#B9F6CA#0A3D0C
  • --warning#FF8F00#D96600
  • --warning-bg#3E2000#FFE0B2
  • --warning-fg#FFD54F#7A3300
  • --info#1E88E5#1976D2
  • --info-bg#12294D#BBDEFB
  • --info-fg#90CAF9#0A2A6E
  • --error#E53935#D32F2F
  • --error-bg#3B0000#FFCDD2
  • --error-fg#FF8A80#5C0000

Data viz.

  • --viz-slatealiasalias
  • --viz-switchaliasalias
  • --viz-deepoklch(0.48 0.070 250)oklch(0.30 0.060 252)
  • --viz-steeloklch(0.66 0.100 232)oklch(0.55 0.090 235)
  • --viz-mistoklch(0.86 0.045 218)oklch(0.78 0.045 220)
  • --viz-graphitealiasalias

Avantt speaks, Antarctica explains.

Avantt carries headlines and display moments. Antarctica Condensed carries body and UI. JetBrains Mono is for IDs, code, and data. Every headline ends with a period.

.t-display · 72
A million decisionS a minute.
.t-h1 · 48
We built the sell-side stack.
.t-h2 · 36
Now we automate it.
.t-h3 · 28
Scale your decisions, not your headcount.
.t-h4 · 22
Rules you set, executed everywhere.
.t-body-l · 18
You set the rules. Swivel executes against them across every platform you touch.
.t-body · 14
Swivel tells you what it did and why. When something needs your judgment, it stops and asks.
.t-ui-page-header · 21
Automations
.t-ui-title · 18
auto-pause-low-fill
.t-ui-metric · 28
+12% ROI →
.t-ui-caps · 13
Last 24 hours
--font-mono
BYR-4471 · PLN-92 · 314273

Sharp edges, structural space.

Space runs on a 4px base. Radii lean sharp, and shadows are reserved for floating layers. Inline cards get a hairline, not a drop shadow.

Spacing.

--space-sm4px
--space-md8px
--space-lg12px
--space-xl16px
--space-xxl20px
--space-3xl24px
--space-4xl32px
--space-5xl40px
--space-section64px

Control heights.

--control-h-sm · --control-h · --control-h-lg

Focus ring.

--focus-ring. Never remove it.

Radius.

xs · 2
sm · 4 (UI)
md · 6
lg · 8 (cards)
xl · 12

Elevation.

--elev-1
--elev-2
--elev-3
--elev-modal

Directional, never bouncy.

Motion references lines and arrows in motion. Transitions are sharp and directional. There are no springs, no squash and stretch, and no parallax. Press is a 0.98 scale over 80ms.

--motion-instant · 80
--motion-fast · 120
--motion-base · 200
--motion-slow · 240
--motion-deliberate · 360
All five on --ease-standard. Easings: --ease-standard, --ease-emphasized, --ease-enter, --ease-exit, --ease-linear.

Full guidance with live curves: Motion reference.

Components.

Every specimen below is plain HTML on the system's own classes, straight from stylesheet.css. The same classes back the React components in _ds_bundle.js. The component library has every variant and state.

Variants
With icon
Icon buttons carry a tooltip and a label

Button groups filter. They never act.

Button groups →
info
A button group switches a view or scopes a list, with exactly one segment selected. Anything that saves, runs, deletes, or opens is a Button. There are no radio buttons: a single choice is a button group or a select field.
Used for reporting and rule scoping.
Focused: 2px stroke and the focus halo.
Use letters, numbers, and dashes only.

Chips, badges, and switches.

Chips and badges →
Chip: a value the user put there All Live CTV Switch on PROD BYR-4471
Badge: a state the system reports Healthy Degraded Failing Syncing Draft
Switch: applies the moment it flips

Alerts.

Alerts →
info
Sync in progressPulling 14 days of delivery from Magnite.
check_circle
Rule deployedauto-pause-low-fill is live across 6 endpoints.
warning
Approaching QPS limitYou're at 84% of your monthly quota.
error
Authentication failedFreeWheel returned 401. Re-authorize from Integrations.

Tabs and tables.

Table anatomy →
IDRuleEndpointsActions / 24hStatus
314273auto-pause-low-fill6 SSPs142Healthy
594188floor-bid-guard12 SSPs88Healthy
903867weekend-traffic-shape3 SSPs12Degraded
163294brand-safety-quarantineAll7Draft
info
A table is always .table-card with a .table-toolbar, the .table, and .table-pagination. Never ship a bare table.

Tabs swap a panel for views of the same object. To move between areas of the product, use the sidenav.

A count opens its records in place.

Full contract in llms.txt →

When a row counts child objects, the count is a square .count-btn. Clicking it opens those records as a sub-table directly beneath the row, and clicking it again closes it. Try it: open a campaign's demand tags, then its creatives.

Platform IDCampaignProductDemand tagsCreativesStart
1284511Q4 Holiday Homescreen TakeoverHomescreenNov 1, 2026
1284530Black Friday CTV BurstCTVNov 24, 2026
1283977Fall Streaming LaunchCTVOct 5, 2026
info
One level, one sub-table per row. A second count in the same row swaps the sub-table. Past 10 rows the sub-table stops and links to the full list. Zero opens nothing. Counts inside a sub-table are plain numbers, never another expander.

Cards and KPIs.

Active rules

Across 6 SSP integrations

14 rules are running. The last one fired 38 seconds ago.
Prevented spend $2,140
8.4%Last 24h
Fill rate 71.2%
1.1%Last 24h

Every async region has three states.

Feedback states →

Loading: Skeleton shaped like the content.

No matches

Nothing in this view matches your filters.

Modals ask. Drawers assist.

Overlays →

Every page sits in the app shell.

The header pins to the top. The sidenav and the scrolling main region share the row below, and the header's hamburger collapses the nav. A screen outside the shell is unreachable and unthemed.

Page layouts.

LayoutUse it for
List pageBrowse, filter, and act on a collection: ad products, automations, scripts, deals.
List page, tabbedThe same collection split into a few fixed views.
Detail, two-column formCreate or edit one object.
Automation detail, split panelConfigure an automation beside its live output.
Activity pageA chronological record of what agents and people did.
Agent workspaceWorking alongside an agent, with the human in the loop.

Regions, required parts, and rules for each: Page patterns and patterns.json.

Arrows are part of the brand.

Product UI uses Material Symbols Outlined, already loaded by the stylesheet. Marketing uses Lucide. Never mix the two on one surface, and never use emoji.

bolt auto_mode rocket_launch insights rule filter_list handshake radar

Outline by default. Filled only for a selected or active state. 16px in body, 20px in nav, 24px in headers.

+12% ROI →20% API ↗

Unicode arrows at headline weight in metric readouts and CTAs. No icon needed.

The approved subset and reserved Swivel objects: Iconography and icons.json.

Practitioners talking to practitioners.

Confident, authoritative, and empathetic, occasionally sassy. We have been in the chair. AI augments operators and never replaces them.

Write this.

A million decisionS a minute.

Scale your decisions, not your headcount.

You set the rules. Swivel executes against them across every platform you touch, then tells you what it did and why.

Not this.

Fast. Smart. Built for scale.

It's not just automation, it's intelligence.

Staccato fragments and the "not X, it's Y" frame read as marketing filler.

Rules.

  • Every headline ends with a period.
  • No em dashes. Use a comma, a period, a colon, or a rewrite.
  • Every sentence has a subject and a verb. No staccato stabs.
  • Prefer "you" and "we". Write "Loading your data." and not "Data is being loaded."
  • No ALL CAPS body copy, no emoji, and no named customer categories in public copy.

Every rule with its severity: llms.txt, Voice and copy.

Brand assets.

Use the files as they are. Do not alter, rotate, recolor, or add effects to the logo.

Resources.

Humans read the showcase pages. Machines read the data files. Both come from the same source.

Machine-readable.

stylesheet.cssFonts, tokens, and components in one file.
llms.txtThe full contract for agents.
tokens.jsonEvery token, W3C DTCG.
components.jsonVariants, sizes, state matrix.
patterns.jsonApp shell and page layouts.
adherence.rules.yamlUsage rules with fixes.
icons.jsonIcon subset and sizes.
charts.rules.yamlChart rules.
_ds_bundle.jsReact components on a window namespace.

Showcase pages.

Component libraryEvery component, variant, and state.
Colors and tokensRamps, surfaces, semantics.
TypographyScales and usage.
IconographyProduct icons and partners.
MotionDurations and curves.
Page patternsSix canonical layouts.
Date and timePickers and formats.
ChartsChart types and rules.
Data viz paletteSequential and diverging ramps.