Level 1. A track and a knob: one control that is either on or off and changes something the moment it moves. 3 placements on 3 painted screens, and all three are the same switch, Reverse sort on Favorites, and all three are OFF. Measured 2026-08-08 in a browser, at 390 and 1280, in both pointer branches.
A shelf shows what the screens wear. This control's screens wear one face of
five. Every placement in the product is aria-checked="false" and none is
disabled, so the ON face, the ON hover, the ON press and the disabled face have zero
placements anywhere in ui-visual/ and exist only in the stylesheet. A vitrine
built by walking the screens would show an off switch and stop, and the four rules that decide
what happens when somebody uses it would be invisible to everyone except a person reading
CSS.
The level and the reason for it stay on the atoms page.
filters.css, and it was never part of itUntil 2026-08-05 this control lived in the sort filter's file. A switch and
a sort menu are two families and the only thing they shared was a file name: the menu is a
<details> holding a panel holding a list of labelled radios, which is a
molecule, and this is one control with a knob, which is an atom. The stand was already saying so
out loud by needing two specimens for one component.
It is also what an empty containment is written to catch.
filters contained nothing that the arithmetic could see, so it was called an atom by
a calculation with no information in it, and the inventory and the old vitrine printed that as a
decision somebody had taken. Nobody had.
Two rules did not come with it, and they are a grey-box fossil. The old
file opened with a hairline border, a 10px face, 2/8 padding and a bold weight for the checked
state. Every .toggle in both trees carries role="switch", measured,
zero exceptions, and the [role=switch] rule re-declares the border, the padding and
the cursor and sets font-size:0. So the fossil painted nothing, and the bold
weight was a weight on a 0px face. Deleted rather than carried.
off, and it is the only one with a placement
on, 0 placements
The knob slides from 3 to 19 and the track fills with the flat action colour. It is the one place in this system where brass is a flat ground rather than a gradient, and that single fact is what forces the press below.
disabled, 0 placements
aria-disabled rather than the disabled attribute, so
the control keeps its place in the tab order and can still say why it is unavailable.
The remaining two are hover and press, which no static page can show at all. They are in the table below with the rules that draw them.
| state | what happens |
|---|---|
| hover, off | --bg-control-hover |
| press, off | --bg-pressed, the system's one pressed ground |
| press, on | --color-action-pressed, brass held down |
| hover, on | nothing, deliberately |
| disabled | --opacity-disabled and not-allowed, and both pointer rules exclude it by attribute so a dead switch cannot light up |
An ON switch is a flat action ground, so neither of the system's two press
mechanisms fits it. Settling onto --bg-pressed would read as "it turned itself
off", and there is no gradient angle to reverse because this is the one brass surface that is not
a gradient. It is the only control that asked for a role of its own, so it got one, and
nothing else in the system needs it.
The hover and press rules both exclude [aria-checked=true] as well
as the disabled state, so neither swaps the brass ground out from under a switch that is
on. Before 2026-08-05 the control had no pointer state at all: its only feedback was the knob
sliding, which is the RESULT of the click and not a sign the control is live.
| at 390 | at 1280 | with a finger | |
|---|---|---|---|
| the track | 40x24 | 40x24 | 40x24, unchanged |
| the knob | 16x16, inset 3 from the top and 3 from the left, and 19 from the left when on | ||
It was 40x22 until 2026-08-05, which is two pixels under the smallest floor there is. A switch is a target you hit rather than one you aim at, so the fix was the control's own box and not an invisible pseudo-element stretched over it: a hit area no measurement in this repository can see is a fix nobody can check.
And the token was wrong before it was short. The height read
--icon-22, which is the size of a MARK, asked to be the height of a CONTROL.
--size-24 is a size primitive and is what the other end of the same declaration,
--size-40, already read. The knob is unchanged at 16 and re-centred: inner height 22,
so the inset is 3 rather than 2.
24 clears WCAG 2.5.8 AA with nothing to spare and fails 2.5.5 AAA at
44, and this control is not in the one touch floor in components/base.css.
That was not a decision either: the floor was assembled from the six per-file lists that existed
on the day, and this file had never written one. Three placements, one screen family, and a real
question about whether a 24px switch is reachable with a thumb.
docs/backlog.md 55.
font-size:0 collapses the button's own text to nothing, and the
text is still there: Reverse sort, a real node in the document. A zero font size
is not display:none, so assistive technology still reaches it, and the product
additionally writes an aria-label, which wins.
The name belongs to voice/ and not to this file, which is
why nothing here says what a switch should be called. What this file owns is that the control
HAS a place for a name and does not draw it.
The state is the attribute, and the attribute is the selector.
Everything here is keyed to [role=switch], [aria-checked] and
[aria-disabled], so the drawing and the accessibility tree cannot disagree: there is
no class that could say on while the attribute says off.
A target is the control's own box. Not a pseudo-element, not the label beside it, not a padded ancestor. Anything else is a hit area no reading of the page can find.
A control needs a sign that it is live, and the result of the click is not that sign. The knob arriving is the outcome; the ground answering is the control.
Never take a control's height from an icon token. --icon-22 is the size of a mark. It landed this control two pixels under the smallest accessibility floor there is, and it read as a deliberate 22 to everyone who saw it afterwards.
Never carry a rule across a move without checking that it paints.
Two rules came within one edit of being copied into this file, and both were drawing on a face
with font-size:0 and a border that was already re-declared.
Never let a pointer state reach a control that is on or dead. A hover that replaces the brass ground says the switch turned itself off, and a disabled switch that lights up says it is available.
Never judge this component from the screens. Four of its five faces have no placement in the product, and a stand built by walking screens would have shown one grey oval.
The level and its reason: the atoms page.
The stylesheet: components/toggle.css. The file it left, and the sort menu it was
never part of: components/filters.css. The pressed brass role and every other
colour: components/tokens.css and DESIGN.md. The open question about
its height: docs/backlog.md 55.