Button catalogue

Every button style that exists in bristlenose/theme/atoms/modal.css, at every size the codebook lens uses, plus three proposals marked NEW. Rendered with the real classes and the real tokens.

Dark follows your system setting.

1 · The Review button today

codebook v2 — framework page, review row (actual)
28 tags on 2 quotes · 4 undecided

It is not styled. The markup is class="bn-btn bn-btn-sm" — no colour variant. The base .bn-btn sets font, padding, radius and border but declares no background, so the button falls through to the browser's own buttonface: measured rgb(239,239,239) with color: rgb(0,0,0) — pure black, not --bn-colour-text.

So "drab and grey, a bit dead" is the accurate reading of an unstyled control. It also explains "low contrast yet too noticeable": the fill is a UA grey that belongs to no palette, and it survives a palette switch unchanged — the one thing on the page that does.

2 · What exists

ClasssmdefaultlgNotes
.bn-btn
bare
Today's Review. No background declared → UA grey.
.bn-btn-secondary Page background + text + hairline. Browse Library uses this at lg.
.bn-btn-cancel Byte-identical to secondary. Two names, one appearance.
.bn-btn-primary Accent fill. The page already spends this on Install.
.bn-btn-danger Frustration orange. Not this — nothing is being destroyed.
:disabled 0.5 opacity on any variant.

Five names, four appearances. cancel and secondary declare the same two properties — worth collapsing, or worth one of them becoming the quiet style below.

The size axis is provisional and scoped. .bn-btn-sm / -lg live in codebook-v2.css under .v2-layout and .section-heading, not in the atom — so they work on this lens and nowhere else. Promoting them to the atom is a separate decision.

3 · Proposals NEW — none of these exist yet

ProposedsmIn situArgument
.bn-btn-quiet
28 tags on 2 quotes · 4 undecided
Accent text, no fill, no border until hover. The macOS plain button — what Finder and Mail use for a verb that is available but not urged. Lightest possible.
.bn-btn-tinted
28 tags on 2 quotes · 4 undecided
Accent text on the accent's own pale wash (--bn-colour-hover). Reads as a control without competing with Install. Closest to macOS 26's tinted style.
.bn-btn-outline
28 tags on 2 quotes · 4 undecided
Accent border and text. More present than tinted; risks reading as a second primary next to Install.

Updated 31 Aug 2026 — the base now carries a background. .bn-btn declared no background, so every bare .bn-btn fell through to the user agent's buttonface: the grey in section 1 was the browser's, not ours. Seven call sites were shipping it, including the Install / Uninstall toggle on every codebook card. The base is now the neutral bordered button — which is what secondary and cancel already described, so those two now restate the default rather than adding to it.

One trap came with the fix and is pinned by tests/test_button_atom.py: giving the base a :hover makes .bn-btn:hover (0,2,0) outrank .bn-btn-primary (0,1,0), so a filled variant washes out to the neutral tint under the pointer unless it restates its fill. Visible only while hovering, which is exactly when nobody is reading the CSS.

4 · Side by side, in the real row

the same row, one option each — scan for which one you stop on
28 tags on 2 quotes · 4 undecided  today (unstyled — reproduced)
28 tags on 2 quotes · 4 undecided  secondary
28 tags on 2 quotes · 4 undecided  quiet NEW
28 tags on 2 quotes · 4 undecided  tinted NEW
28 tags on 2 quotes · 4 undecided  outline NEW
28 tags on 2 quotes · 4 undecided  primary

The competition to judge against: this page already has Browse Library (secondary, lg) in the zone title and Install / Uninstall in the gutter. Review is a third verb on the same screen, and the question is what rank it should hold among them — not whether it looks nice alone.

Two things this catalogue does not settle. Whether the size axis is promoted out of codebook-v2.css into the atom, and whether cancel/secondary collapse into one name. Both are cheap once the appearance is chosen.

Scale note: these are the web type tokens (label 13px, caption 12px). The desktop app substitutes an Apple scale in tokens-desktop-v1.css — caption is 11px there — so every specimen renders a shade smaller in the .app. Relative weights are unchanged.

5 · Install & Uninstall — should they differ at rest?

Settled 31 Aug 2026 — D. bn-btn-primary for Install, bn-btn-secondary for Uninstall, in both codebook lenses. Ranked by what you came to do rather than by danger: this is a catalogue, installing is the frequent intent, and Uninstall is already gated by a sheet that measures what it costs. The destructive reading still arrives on hover via .picker-card-toggle-uninstall.

The question. Today they are byte-identical at rest; .picker-card-toggle-uninstall styles only :hover and :focus-visible (red text, red border). So on a nine-card grid the destructive/constructive distinction arrives at the moment of commitment, not the moment of scanning. One of these adds a codebook; the other destroys 28 tags across 4 quotes.

The counter-argument, which is real. Uninstall is already gated by a confirmation sheet that measures what will be lost. Painting the card button red warns about a thing that cannot happen from this click — and the house rule is that .destructive marks what was not chosen, in the confirm, rather than decorating every route toward it. Option A may simply be right.

hover each pair — the rest state is the thing to judge
A · identical (today, now styled)   distinction on hover only
B · destructive text at rest   red label, neutral border NEW
C · destructive outline at rest   red label + red border NEW
D · install leads, uninstall recedes — SHIPPED   weight by frequency, not danger
E · uninstall is a filled danger   almost certainly too loud for a card

What to weigh. A trusts the confirm sheet and keeps the grid calm — nine cards, no red. B is the smallest change that makes the two scannable and reads as a label, not an alarm. C puts a red rectangle on the grid for every installed codebook, which is a lot of warning for a gated action. D is the interesting one: it ranks by what you came to do rather than by danger, and makes the catalogue read as a place you install from. E is here to be rejected.

All five use existing tokens — --bn-colour-negative, --bn-colour-accent, --bn-colour-muted. Nothing here needs a new value.