Files
zooqueenandhanzo-dev 9a52b25eb0
publish / publish (push) Successful in 15s
Hanzo CI/CD / cicd (push) Successful in 19s
CI/CD / cicd (push) Successful in 19s
design: one rule decides focus, and it is the one that can be seen (0.4.9)
0.4.8 stopped the generic ring from reaching fields, which fixed the double
indicator and quietly created a worse defect: measured on --background, the
brightened edge it left behind is 1.91:1 and the halo 1.25:1, against the 3:1
this package already gates --ring on. The accidental second ring had been the
only reason a focused field was visible at all.

So the field rule goes entirely and the ring covers everything. Two reasons,
and the second is the one that generalizes:

1. Contrast. 2px at --ring is 3.77:1 and clears the 2px perimeter WCAG 2.4.13
   asks for. The budget was documented as spent entirely on --ring "because
   that is what a keyboard user navigates by" — which was true for a button and
   false for a field for exactly as long as the field rule told fields not to
   use it. Now it is true for both.

2. Suppressibility. The field treatment carried its indicator on border-color,
   so any app that states `border` on its own fields overrode it. @hanzo/id
   does, unlayered, which beats a layer whatever its specificity — its focused
   fields sat at the resting .15 while both stylesheets read as correct. An
   outline is not a border: no app's field styling reaches it, so the ring
   paints whether or not the app has opinions about edges.

check-tokens now enforces the property rather than the ordering: exactly one
rule may paint a focus outline, none may set outline:none, none may add a
box-shadow on focus. It reports both defects against the pre-0.4.9 shape.

--border-focus and --ring-focus stay declared and exported — consumers use
them — but nothing in the token layer spends them on focus any more.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-08-05 06:33:25 -07:00
..