Tell the three message types apart without relying on color

Color was the only thing telling the three message types apart, and it was not doing it.

Measured

Against each other rather than against the page:

pair luminance ratio
status vs error 1.03:1
status vs warning 1.31:1
warning vs error 1.28:1

The same darkness. As ink at 0.875rem the only difference was hue carried by letter strokes, which is the weakest place to put it, and a reader with ordinary color vision could not see it either.

What this does

A mark per type, punched out of the text color with a mask, so it takes whatever the palette does and needs no second file per color. The shapes are Claro's: a check for status, a bar and a dot for warning, a circle with a diagonal stroke for error. A booker who also meets a Drupal admin screen reads the same three. Drawn once, in stepper.css, because the seat map's library already depends on it.

Filled blocks on the price list, white on the color, which is what the seat map already did. The color becomes an area instead of letter strokes, and both surfaces say the same thing the same way. Every fill clears 4.5:1 against white text.

What it deliberately does not do

Make the color carry the meaning. Three fills of nearly one darkness stay one shade in grayscale, with colors disabled, or to a booker who cannot separate red from green, and no palette fixes that: a light-tinted alternative in the Claro house style measures 1.04:1, worse than what is here. The mark is what tells them apart, and the sentence says it in words.

Also

The map's messages stop centering their text: a line that starts with a mark and then centers its words leaves the mark hanging away from them. The sentence starts at the mark, the dismiss button holds the far end.

Still open

Naming the type for assistive technology. The issue proposes aria-label, which would be the wrong mechanism, since it replaces the message text rather than adding to it; core uses a visually hidden heading. Doing it in the DOM means giving each line a text-holding child, because the stepper's reconciler compares innerHTML to decide whether a line changed, and that is a hot path carrying both a byte budget and a no-flicker guarantee. Worth its own pass rather than folding in here.

Checked

stylelint adds no error to either file (stepper.css goes from 2 pre-existing to 0). The three inline SVGs parse. Byte budgets in SlotBookingPerformanceTest and PlaceMapPerformanceTest will move and are set from what CI measures, not nudged, the way the comment beside them already asks.

AI-Generated: Yes (Claude Code took the measurements, made these changes and drafted this description. I reviewed them before pushing.)

Merge request reports

Loading
Loading