System bench

Contrast contexts

The same buttons, link, field and form on the page, in theme islands and on a band the application paints, each measured live: Aa is the text against the fill it sits on (4.5:1), ◎ is the focus line against what surrounds it (3:1). The form row also carries a combobox and a date picker on their token bridges. Switch theme or OS scheme and the numbers follow.

The switch paints the core recipe on every sample at once. A theme that restyles field focus (gradient, material) shows its own line on real keyboard focus: press Tab.

Three intentions, three tools

Change the whole visual context

data-theme on the section, footer or card. Every token recomputes: surfaces, text, fields, validation, intents, focus and native controls. In a branded app, light and dark are the scheme roles of your brand.

Change one component's treatment

A variant (.solid, .soft, .outline, .surface) or a component hook.

Just paint a special background

Application CSS: --surface-solid under --surface. Neutral ink and filled buttons read on it; intent ink and forms keep the page palette, so they stay out.

Every context, same samples

Red marks a pair under its threshold. Every island passes, form, combobox and date picker included. On the painted band, the intent variants that put their ink on it (outline, ghost, link) fail: nothing tunes an intent for a surface the application paints. That is why the band carries no form, and why a band that needs either is an island.

Joined fields need zero adaptation

Each segment draws its focus line inside its own border box, so .join only handles corners, shared edges, stretch and stacking — no rule in join.css mentions focus. A field wrapped one level deep (.input-icon, a combobox, a date picker) is supported generically: the wrapper takes the group corners, the field inherits them and fills the stretched height. Tab through the segments, or show every line at once: none overlaps a neighbour.

Two fields and an action
Addon, field, action
€
Select and field
Icon field and icon action
Invalid segment
Combobox and action
Date picker and action

Focus: one token, two surfaces

Every indicator is a solid --focus-ring-width line in --focus — inset on fields, offset on actions. It never follows an intent or a local surface, so the theme must keep --focus at 3:1 against both surfaces a line can land on. bun run report:theme-contrast prints both pairs per theme.

Which one?