3.1 Primary buttonThe one hero action per screen. Pink fill, pink shadow, ink-on-white is never primary. Use no more than one per viewport.
Primary .btn.btn-primary Lift 1px on hover, press back flush on click. Disabled drops opacity without changing colour.
Book a demo
Start free trial
Processing…
<button class ="btn btn-primary" >
Book a demo <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
</button>
.btn {
display: inline-flex; align-items: center; justify-content: center;
gap: var(--s-2);
font: 600 14.5px/1 var(--f-display);
letter-spacing: -0.005em;
padding: 11px var(--s-5);
border: 1px solid transparent;
border-radius: var(--r-md);
cursor: pointer;
transition: background var(--dur-2) var(--ease),
border-color var(--dur-2) var(--ease),
transform var(--dur-2) var(--ease),
box-shadow var(--dur-2) var(--ease),
color var(--dur-2) var(--ease);
user-select: none;
white-space: nowrap;
}
.btn:focus-visible { outline: 0; box-shadow: var(--sh-focus); }
.btn:disabled { opacity: .55; cursor: not-allowed; pointer-events: none; }
.btn-primary {
background: var(--accent); color: var(--paper);
box-shadow: var(--sh-pink);
}
.btn-primary:hover { transform: translateY(-1px); filter: brightness(1.04); }
.btn-primary:active { transform: translateY(0); filter: brightness(0.96); }
3.2 Secondary buttonPartner to the primary. White card surface with a hair border that darkens to ink on hover. Pair with primary in hero rows.
Secondary .btn.btn-secondary
Learn more
See it in action
Coming soon
<button class ="btn btn-secondary" >
Learn more
</button>
.btn-secondary {
background: var(--bg-paper);
color: var(--fg);
border-color: var(--hair);
}
.btn-secondary:hover {
border-color: var(--fg);
background: var(--bg-paper);
transform: translateY(-1px);
}
.btn-secondary:active { transform: translateY(0); }
3.3 Ghost / tertiary buttonThe quietest button. Use for dismiss, cancel, or any low-stakes action inside a dense panel. No fill until hovered.
Ghost .btn.btn-ghost
.btn-ghost {
background: transparent;
color: var(--fg);
border-color: transparent;
}
.btn-ghost:hover {
background: var(--bg-sunk);
border-color: var(--hair);
}
3.4 Danger buttonDestructive actions only. There's only one red in the system — D64545 — and this is where it lives.
Danger + danger-outline .btn-danger · .btn-danger-outline Always confirm destructive actions in a modal before executing.
Delete agent
Remove workspace
.btn-danger {
background: var(--error); color: var(--paper);
}
.btn-danger:hover { filter: brightness(1.05); transform: translateY(-1px); }
.btn-danger-outline {
background: transparent; color: var(--error-text);
border-color: rgba(214, 69, 69, 0.3);
}
.btn-danger-outline:hover {
background: var(--error-soft);
border-color: var(--error);
}
3.5 SizesFour sizes, one default. Hero size is for landing-page CTAs only. Small is for dense UIs (tables, toolbars).
Size scale sm · md · lg · xl
Small
Default
Large
Hero
.btn-sm { padding: 7px var(--s-4); font-size: 13px; border-radius: var(--r-sm); }
.btn { padding: 11px var(--s-5); font-size: 14.5px; } /* default */
.btn-lg { padding: 13px var(--s-6); font-size: 15.5px; }
.btn-xl {
padding: 16px var(--s-7);
font-size: 17px;
border-radius: var(--r-lg);
gap: var(--s-3);
}
3.8 Button groups & splitGrouped secondary buttons form a horizontal bar for utility strips. Split buttons pair a primary action with a chevron for alternates.
Button group + split .btn-group · .btn-split
.btn-group {
display: inline-flex;
}
.btn-group .btn {
border-radius: 0;
border-right-width: 0;
}
.btn-group .btn:first-child { border-top-left-radius: var(--r-md); border-bottom-left-radius: var(--r-md); }
.btn-group .btn:last-child { border-top-right-radius: var(--r-md); border-bottom-right-radius: var(--r-md); border-right-width: 1px; }
.btn-group .btn:hover { z-index: 1; position: relative; }
.btn-split { display: inline-flex; }
.btn-split-main { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.btn-split-icon {
padding: 11px var(--s-3);
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 1px solid rgba(255,255,255,0.25);
}
3.9 Loading stateReplace the trailing icon with a spinner and lock the button. Keep the label — silence feels broken.
Loading .btn-loading
Processing…
Checking availability
.btn-loading { pointer-events: none; }
.spinner {
width: 14px; height: 14px;
border-radius: 50%;
border: 2px solid currentColor;
border-top-color: transparent;
animation: spin 0.8s linear infinite;
opacity: .85;
}
.btn-primary .spinner { border-color: rgba(255,255,255,.45); border-top-color: transparent; }
@keyframes spin { to { transform: rotate(360deg); } }
3.10 Toggle (switch)Two-state settings. Use switch for boolean preferences; use checkbox for selecting items.
3.11 Checkbox · radioPink fill when selected. Checkbox for many-from-many, radio for one-from-many. Never use checkboxes where a switch belongs.
Checkbox & radio .cb · .rb
.cb, .rb {
display: flex; align-items: center; gap: var(--s-3);
font: 400 14.5px/1.3 var(--f-body); color: var(--fg);
cursor: pointer; padding: 6px 0;
user-select: none;
}
.cb input, .rb input { position: absolute; opacity: 0; pointer-events: none; }
.cb-box, .rb-circle {
flex: 0 0 18px;
width: 18px; height: 18px;
background: var(--bg-paper);
border: 1.5px solid var(--hair);
transition: background var(--dur-2) var(--ease),
border-color var(--dur-2) var(--ease);
position: relative;
}
.cb-box { border-radius: var(--r-xs); }
.rb-circle { border-radius: 50%; }
.cb input:checked + .cb-box {
background: var(--accent); border-color: var(--accent);
}
.cb input:checked + .cb-box::after {
content: "";
position: absolute; inset: 0;
background: none;
border-right: 2px solid var(--paper);
border-bottom: 2px solid var(--paper);
width: 5px; height: 10px;
margin: auto; top: -2px; left: 0; right: 0; bottom: 0;
transform: rotate(45deg);
}
.rb input:checked + .rb-circle { border-color: var(--accent); }
.rb input:checked + .rb-circle::after {
content: "";
position: absolute; inset: 3px;
background: var(--accent); border-radius: 50%;
}
.cb input:focus-visible + .cb-box,
.rb input:focus-visible + .rb-circle { box-shadow: var(--sh-focus); }
.cb-disabled { opacity: .5; cursor: not-allowed; }
3.12 Segmented controlPill-shaped tab strip for switching between sibling views. Use when options are few (≤5) and mutually exclusive.
Segmented .seg
Chat
Email
SMS
Voice
Today
Week
Month
.seg {
display: inline-flex;
/* warm-3 (lightest warm) for the rail — warm-5/bg-sunk reads as
"dirty/heavy" against white card surfaces. Dark mode flips back. */
background: var(--warm-3);
border: 1px solid var(--hair);
border-radius: var(--r-pill);
padding: 3px;
gap: 0;
}
body[data-theme="dark"] .seg { background: var(--bg-sunk); }
.seg-btn {
appearance: none; border: 0;
background: transparent;
color: var(--fg-dim);
padding: 7px 14px;
border-radius: var(--r-pill);
font: 500 13px/1 var(--f-body);
cursor: pointer;
transition: color var(--dur-2) var(--ease),
background var(--dur-2) var(--ease);
}
.seg-btn:hover { color: var(--fg); }
.seg-btn.is-active {
background: var(--bg-paper);
color: var(--fg);
box-shadow: var(--sh-1);
}
.seg-sm .seg-btn { padding: 5px 11px; font-size: 12px; }
3.13 Close & dismissA 28×28 pill with just the × glyph. Always paired with aria-label='Close' or 'Dismiss'. Use the soft variant when sitting inside a warning or info surface.
Close button .close-btn
.close-btn {
width: 28px; height: 28px;
display: inline-flex; align-items: center; justify-content: center;
background: transparent;
border: 0;
color: var(--fg-dim);
border-radius: var(--r-sm);
cursor: pointer;
transition: background var(--dur-2) var(--ease),
color var(--dur-2) var(--ease);
}
.close-btn:hover { background: var(--bg-sunk); color: var(--fg); }
.close-btn-soft { background: var(--accent-soft); color: var(--accent-text); }
.close-btn-soft:hover { background: var(--accent); color: var(--paper); }
3.14 Anatomy of the primary buttonSix tokens assemble the hero CTA.
Book a demo
1 1. Fill background: var(--accent);
2 2. Label font-family: var(--f-display); font-weight: 600;
3 3. Gap gap: var(--s-2);
4 4. Padding padding: 11px var(--s-5);
5 5. Radius border-radius: var(--r-md);
6 6. Elevation box-shadow: var(--sh-pink);