Theme heading
changedFour different answers to “is this field live?” ship on one screen today, and two surfaces answer it with nothing at all. The fix is not a fourth invention — it is one signal whose fill inverts with the ground it sits on, plus one named exemption. Columns two and three are live CSS, not screenshots: what you see is what the declarations beneath them do.
The ground is already white, so the field tints up to be seen.
--bn-field-edit-fill-on-page--bn-field-edit-edge at 1px
The ground is already coloured, so the field blanks to neutral to be seen.
--bn-field-edit-fill-on-tint--bn-field-edit-edge at 1px
Not “edit this text” but “move this boundary”. Custom by design, one
signal with the burnt-amber brackets. Keeps its yellow, now honestly named
--bn-colour-crop-bg. Do not restyle it to match, and do not
borrow that yellow.
Theme heading
changedOnboarding friction
.editable-text.editing { background: --bn-colour-editing-bg; outline: --bn-colour-editing-border; } /* never matches: React adds no .editing class — only theme/js does, in the static byproduct */
Onboarding friction
.editable-text[contenteditable="true"] { outline: 1px solid --bn-field-edit-edge; outline-offset: --bn-field-edit-offset; background: --bn-field-edit-fill-on-page; border-radius: --bn-field-edit-radius; }
Keys on the attribute, not a class, so it needs no co-operation from the component and cannot fall out of sync again. Resting padding plus equal negative margin means entering the field moves no text.
Theme description
changedWhere people stall in the first run
Where people stall in the first run
Same rule, same class, no second selector. The heading and its description were always siblings in the markup; they are now siblings in the CSS too.
Participant name
unchanged — now tokenised.bn-speaker-editable-name[contenteditable] {
outline: 1px solid --bn-colour-accent;
outline-offset: 1px;
background: --bn-colour-quote-bg;
}
Pixel-identical. This one was already right, which is what made
it the model — the tokens were reverse-engineered from it rather than invented.
Its declarations are deleted from person-badge.css and the class now
joins the shared selector, so there is one rule, not two that happen to agree.
Code group title
changed.group-title-text[contenteditable="true"] { outline: 1px solid --bn-field-edit-edge; outline-offset: --bn-field-edit-offset; background: --bn-field-edit-fill-on-tint; border-radius: --bn-field-edit-radius; }
A tint on a tint reads as nothing — the same 1.01:1 wall the code cursor hit. Blanking to page background is what the code chips three inches below already do: one card, one idiom, whether you are naming the group or naming a code inside it.
The card's own selection edge stands down via
:focus-within as this one lights, so exactly one accent edge is on screen
and it is around the thing taking the keystrokes.
Code group subtitle
changedShares the selector with the title. Keeps its existing
display:inline-block and min-width:12ch — the fix that stopped a
three-word subtitle getting a field four times its length, and that keeps an empty
one from collapsing to a caret with no box.
New code
unchanged — now tokenised.tag-input-box {
border: 1px solid --bn-colour-accent;
background: --bn-colour-bg;
}
Pixel-identical, and the second model the tokens were read off. Border rather than outline because this chip already owns a box — that is a layout mechanism, not a second meaning, and the set deliberately leaves the choice open. Outline is for a span in running prose, where a border would reflow the line.
Rename a code
already aligned.tag-edit-inline {
/* .badge metrics dragged in the
grey fill; the ring was
--bn-focus-ring at 12% alpha */
box-shadow: --bn-focus-ring;
}
This one you already fixed by eye — “whatever you're doing for the brand new tag on first edit feels right”. All that changes now is that it reads the tokens instead of repeating their values, so re-editing and first-typing cannot drift apart again.
Worth keeping as the cautionary specimen: twelve per cent alpha on a tinted card is a ring that technically exists and cannot be seen.
Crop / trim a quote
exempt — do not touch[it just kept spinning and I had no idea if it had worked]
[it just kept spinning and I had no idea if it had worked]
Untouched, deliberately. The verb is different — you are moving a boundary, not retyping a string — and the yellow was designed to read as a single signal with the brackets. A different verb is allowed a different look.
Not one declaration changed. What changed is the name:
--bn-colour-editing-bg is now --bn-colour-crop-bg, because a
token named for a state it must not be used in is how three other surfaces
came to borrow it in the first place. Same hex, same rules, same pixels.
Search, filters, settings
not in the setA different animal, and the distinction is worth stating so nobody
“aligns” these next. A real <input> has a box at rest: it is
visibly a field before you touch it, so focus only needs to promote the resting border
to accent. An inline edit has no box at rest — it is prose until you click it — so
focus has to conjure the field, which is why it needs a fill as well as an edge.
Rule of thumb: if the reader can see it is a field before
interacting, use the resting-border pattern. If they cannot, use the
--bn-field-edit-* set.