Solid green, ink type, and the forward arrow. Every primary carries the arrow, and it leans on hover. The loudest ask on the page, and there is only ever one per view. Works identically on light and dark surfaces.
Solid ink, white type. It sits beside a primary or stands alone for supporting actions. Same size, shape, and motion as primary: only the value changes, so the pair reads as one system at two volumes.
A text link with weight: a mono label plus a 20px ink chip carrying the green arrow. The chip stays constant on every surface; the label takes the surface ink. On hover the chip fills green and the arrow leads.
Type only: no fill, no border, full button metrics. For utility actions that should be findable but never compete: login, filters, dismissals. On hover a soft wash fills behind it: dark on light surfaces, light on dark. It never lifts; it isn't asking.
The ask is never confined to the button. When a card, a row, or a tile leads somewhere, the whole surface is the button: the full area is clickable, the cursor confirms it, and the surface answers as one — it lifts or tints, the title leans, the arrow steps up.
The canonical pair: primary + secondary, green + ink, side by side in a bar. Never two primaries, never green beside green. When the brand’s accent appears in nearby product imagery, the CTA still owns the only solid green/500 on screen.
The web and Figma share one vocabulary. Components reference semantic tokens; primitives live in 03 · Color and the DS Foundations.
| height / radius | --size-button-height --radius-button | 48px / 8px · all tiers, all surfaces |
| padding / gap | --spacing-button-x --spacing-gap-button | 0 16px · 8px label-to-icon gap · label never wraps |
| type | Label/M | IBM Plex Mono 500 · 13px · uppercase |
| primary | --button-primary-bg --button-primary-fg | green/500 #5DE27E on ink #181818 · label + forward arrow · reserved for the ask |
| primary states | --button-primary-bg-hover --button-primary-bg-pressed | hover green/600 #3CCB66 (arrow leads +4px) · pressed green/700 #31AD53 |
| secondary | --button-secondary-bg --button-secondary-fg | gray/850 #282726 · white type · hover +8% white wash |
| state washes | --state-hover --state-hover-inverse | ink 6% on light · white 8% on dark — text buttons & secondary hover |
| tertiary | gray/800 · green/500 | mono label + 20px chip #3A3936, green arrow, 8px gap · hover fills the chip green (white on green surfaces), arrow flips to ink, leads +5px |
| text button | --state-hover | no fill · label takes the surface ink · hover fills the state wash, radius 8 · never lifts |
| focus | --button-focus-ring | #6F90F5 ring · keyboard focus only |
| disabled | --button-primary-bg-disabled --button-primary-fg-disabled | warm/200 #D8CFC9 fill · warm/500 #A8978C label · both tiers |
| hover motion | --dur-micro · --ease-spring | lift −2px · spring ease · no shadow |
| press | — | scale .97 · 150ms |
| entrance | --dur-reveal | wipes on, left → right, see 08 · Motion |