Buttons
Five distinct levels of emphasis. Add .sm for the small size. Every button has live hover, focus, active, and disabled states. Try them with your mouse and keyboard.
Pick the highest-emphasis variant that fits the moment. A page rarely needs more than one primary button per view.
.sm to any variant.sm drops the button to 11px text with tighter padding. Use it inside cards, toolbars, dense rows, and toasts. .btn.link stays the same size; it's already inline-sized.
Hover, focus, and active all work on real HTML. Mouse over the row below; press Tab to walk through with keyboard focus.
| State | Trigger | Visual |
|---|---|---|
| default | .btn |
Resting state. Set by the variant. |
| hover | .btn:hover |
Background and border darken. Primary & accent shift one step; outline and ghost pick up a subtle --paper-2 / --paper wash. |
| focus-visible | .btn:focus-visible |
2px --accent outline at 2px offset. Only shown for keyboard users (mouse clicks suppress it). |
| active | .btn:active |
The press moment. Same direction as hover, slightly tighter (subtle). |
| disabled | .btn[aria-disabled="true"] |
Opacity drops to 45%, cursor turns not-allowed. The button stays in the DOM and remains focusable for screen readers. |
All five states live in wireframe.css so they update everywhere at once. Hover transitions are 120ms. Keep them quiet so the wireframe doesn't feel like a design comp.
aria-disabled="true"Use aria-disabled="true" (not the HTML disabled attribute) so the button stays in the keyboard tab order and screen readers can announce it. Combine with onclick guards in real builds.
The .btn base sets gap: 6px between children, so drop an <i> before or after the label. Set color: inherit on the icon so it follows the button's text color through every state.