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.
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.
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.
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.
Control heights.
Focus ring.
Radius.
Elevation.
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.
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.
Buttons.
All button states →Button groups filter. They never act.
Button groups →Fields.
Fields and usage →Chips, badges, and switches.
Chips and badges →Alerts.
Alerts →Tabs and tables.
Table anatomy →| ID | Rule | Endpoints | Actions / 24h | Status |
|---|---|---|---|---|
| 314273 | auto-pause-low-fill | 6 SSPs | 142 | Healthy |
| 594188 | floor-bid-guard | 12 SSPs | 88 | Healthy |
| 903867 | weekend-traffic-shape | 3 SSPs | 12 | Degraded |
| 163294 | brand-safety-quarantine | All | 7 | Draft |
.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 ID | Campaign | Product | Demand tags | Creatives | Start |
|---|---|---|---|---|---|
| 1284511 | Q4 Holiday Homescreen Takeover | Homescreen | Nov 1, 2026 | ||
| 1284530 | Black Friday CTV Burst | CTV | Nov 24, 2026 | ||
| 1283977 | Fall Streaming Launch | CTV | Oct 5, 2026 |
Cards and KPIs.
Active rules
Across 6 SSP integrations
Every async region has three states.
Feedback states →No matches
Nothing in this view matches your filters.
Couldn't load automations
The server didn't respond. Nothing has changed.
Modals ask. Drawers assist.
Overlays →Pause auto-pause-low-fill?
This rule fired 142 times in the last 24 hours. Pausing it affects 6 SSP endpoints.
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.
| Layout | Use it for |
|---|---|
| List page | Browse, filter, and act on a collection: ad products, automations, scripts, deals. |
| List page, tabbed | The same collection split into a few fixed views. |
| Detail, two-column form | Create or edit one object. |
| Automation detail, split panel | Configure an automation beside its live output. |
| Activity page | A chronological record of what agents and people did. |
| Agent workspace | Working 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.
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.css | Fonts, tokens, and components in one file. |
| llms.txt | The full contract for agents. |
| tokens.json | Every token, W3C DTCG. |
| components.json | Variants, sizes, state matrix. |
| patterns.json | App shell and page layouts. |
| adherence.rules.yaml | Usage rules with fixes. |
| icons.json | Icon subset and sizes. |
| charts.rules.yaml | Chart rules. |
| _ds_bundle.js | React components on a window namespace. |
Showcase pages.
| Component library | Every component, variant, and state. |
| Colors and tokens | Ramps, surfaces, semantics. |
| Typography | Scales and usage. |
| Iconography | Product icons and partners. |
| Motion | Durations and curves. |
| Page patterns | Six canonical layouts. |
| Date and time | Pickers and formats. |
| Charts | Chart types and rules. |
| Data viz palette | Sequential and diverging ramps. |