feat(uix): touch-target — button-like controls hit 44px on coarse pointers

The framework's only axis below industry (ARCHETYPE_COHERENCE_AUDIT flagged it
RED: 0 components guaranteed 44/48px, 0 hit-area, md=36 < the mobile minimum). On
COARSE pointers (touch), grow button-like controls to the 44px target (WCAG 2.5.5
AAA / Apple HIG 44pt / Material 48dp); the desktop (fine pointer) keeps its compact
density — gated out, zero regression.

Transversal rule in archetypes.css: the trigger / close / action archetypes + the
standalone [data-button]. `:not([data-size='lg']):not([data-size='xl'])` does double
duty — skips the already->=44 sizes (so min-* only GROWS xs/sm/md, never shrinks
lg/xl) AND lifts specificity to 0,2,0 to beat the recipes' own min-block-size. Both
axes, so icon-only / short-label controls reach 44x44.

Verified: rule serves; md button + sm trigger match, lg button + item rows don't;
desktop button stays 36px (gate doesn't leak).

Follow-up passes: item/option rows (list-surface height), field-trigger, thumb, and
the small markers (checkbox/radio/switch — their clickable label often already
provides the target).
active-uix
dev 3 months ago
parent b2ca998985
commit a265d39aef

@ -209,3 +209,33 @@
cursor: not-allowed;
opacity: 0.5;
}
/* ── Touch-target (a11y) — coarse pointers ──────────────────────────────────
* On COARSE pointers (touch), grow button-like controls to the 44px mobile
* minimum (WCAG 2.5.5 AAA · Apple HIG 44pt · Material 48dp). The desktop (fine
* pointer) keeps its compact density — zero regression, gated out entirely.
*
* Scoped to the interactive "button" archetypes (trigger / close / action) + the
* standalone `[data-button]`. The `:not([data-size='lg']):not([data-size='xl'])`
* does DOUBLE DUTY: (1) it skips lg (44) / xl (52) — already ≥ 44 — so the `min-*`
* only GROWS the small sizes (xs/sm/md) and never shrinks a larger one; (2) the
* two `:not()` lift specificity to 0,2,0 so this beats the recipes' own
* `min-block-size` (0,1,0) — a plain `:where()` (0,0,0) would lose. Both axes, so
* icon-only / short-label controls reach 44×44 (`min-*` is a floor — wide / block
* controls are unaffected).
*
* NOT covered here (separate passes): `item`/`option` rows (their floor comes from
* the list-surface `--list-item-height` system), `field-trigger` (sits flush inside
* a field that is itself the target), `thumb` (drag, not tap), and the small markers
* (checkbox/radio/switch — their clickable label usually already provides the target). */
@media (pointer: coarse) {
:where(
[data-archetype='trigger'],
[data-archetype='close'],
[data-archetype='action'],
[data-button]
):not([data-size='lg']):not([data-size='xl']) {
min-block-size: 44px;
min-inline-size: 44px;
}
}

Loading…
Cancel
Save

Powered by TurnKey Linux.