docs: the focus law, and the two-rule collision that hid under it

The bullet claimed --ring was var(--neutral-500) at 4.43:1; it has been
var(--white-40) at 3.77:1 for the whole 0.4.x line. It also described base.css
as shipping ONE :focus-visible rule, which only became true at @hanzo/design
0.4.9 — before that a second, field-specific rule tied it at (0,1,0) and lost
to source order, so focused inputs here drew two indicators.

Records the part the next reader cannot derive: why a local focus override is
still the wrong fix, and why the treatment that rule was applying could not have
worked on this surface at all (its indicator rode on border-color, and
.hanzo-id-input states border unlayered).

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
zooqueen
2026-08-05 06:46:47 -07:00
co-authored by Hanzo Dev
parent 7978f58a23
commit 0504174fc9
+21 -5
View File
@@ -118,11 +118,27 @@ this surface takes the system's answer.
fonts.googleapis.com and the sign-in path can take the typeface with the
colours. Measured on the built bundle: rendered face is Geist, served from
`/assets/Geist-Variable-*.woff2`, zero third-party font requests.
- **The focus rule is DELETED from this file.** `tokens/base.css` ships
`:focus-visible{outline:2px solid var(--ring)}` to every consumer, and 0.3.0
moved `--ring` to `var(--neutral-500)`. Measured in browser: `2px solid
rgb(115,115,115)`, **4.43:1** on `--background` (WCAG 2.4.11 wants 3:1). The
local `--primary` override existed only because `--ring` was 1.66:1.
- **The focus rule is DELETED from this file**, and it stays deleted.
`tokens/base.css` ships `:focus-visible{outline:2px solid var(--ring)}` to
every consumer; `--ring` is `var(--white-40)` in the 0.4.x line, measured
`2px solid rgba(255,255,255,.4)` = **3.77:1** on `--background` (WCAG 2.4.11
wants 3:1). Do not restore a local override — the last one existed only
because `--ring` was 1.66:1, which is fixed upstream.
Until **@hanzo/design 0.4.9** that layer carried a SECOND rule, a
field-specific `:where(input,select,textarea):focus-visible` that suppressed
the outline and drew a brightened edge + halo instead. Both rules computed to
(0,1,0) — `:where()` zeroes what it wraps — so the cascade fell through to
source order, the generic ring was written later, and it overrode the
`outline:none` the field rule stated to prevent it: every focused input here
drew BOTH indicators. Worse, the treatment it was trying to apply could never
have worked on this surface — its indicator rode on `border-color`, and
`.hanzo-id-input` states `border` unlayered, which beats a layer whatever its
specificity, so focused fields sat at the resting `.15` (1.47:1) while both
stylesheets read as correct. 0.4.9 deleted the field rule; one ring now covers
every focusable thing, and an `outline` is immune to the `border` this file
declares. `check-tokens.mjs` fails the build if a second focus rule, an
`outline:none` or a focus `box-shadow` ever returns.
- **Control boundaries are `--border-control`** (0.4.2 onward; this bullet read
`--border-strong` when 0.3.0 briefly cut the control rungs from the neutral
ladder). 0.4.2 put them back on alpha — `--border-control` .15, `--border-focus`