code wiki / _hdl_build / nx_uiq_responsive.nx
nx_uiq_responsive.nx
buildroot/runtime/_hdl_build/nx_uiq_responsive.nx
about
nx_uiq_responsive.nx -- THE SEVENTH nx_uiq_* RULER: the responsive-layout auditor the family lacked.
WHY THIS EXISTS (measured 2026-08-10): the estate had SIX nx_uiq_* rulers (contrast/wire/perf/visual/
atree/sentinel) and NOT ONE measured responsive layout. nx_uiq_perf's only "media" reference is
`unsized_media` (a CLS proxy). Consequence, measured on the live site: nx_page_verify returned
VERDICT=GREEN / a11y-issues=0 on nishifamily.com/games while that page's Connect Four board is a
FIXED 368px grid that overflows every phone -- and it had been live for ~53 days.
=> A GREEN FROM AN INSTRUMENT THAT CANNOT SEE THE DEFECT READS AS "THE PAGE IS FINE".
THE RULER IS NOT INVENTED (family doctrine: name a real external bar, never a taste).
PRIMARY : W3C WCAG 2.1 SC 1.4.10 "Reflow" (Level AA) -- content must reflow to 320 CSS px
WITHOUT requiring scrolling in two dimensions. => a fixed-track grid whose own
minimum width exceeds 320px cannot conform, whatever the rest of the page does.
SECONDARY: SC 2.5.8 "Target Size (Minimum)" (AA) = 24x24 CSS px floor for pointer targets.
SECONDARY: SC 1.4.4 "Resize Text" (AA) -- suppressing zoom (user-scalable=no / maximum-scale=1)
fails it outright.
WHAT IT COMPUTES (arithmetic, never a vibe). For every `repeat(<N>,<W>px)` track list it finds the
ENCLOSING RULE BLOCK and sums that grid's own intrinsic minimum width:
min_width = N*W + (N-1)*gap + 2*padding_horizontal
The live Connect Four board is the worked example this organ was built against:
7*46 + 6*5 + 2*8 = 322 + 30 + 16 = 368 > 320 => RED
`repeat(auto-fill,minmax(...))` and other non-numeric counts parse as NOT-FIXED and are skipped --
that shape IS responsive, so counting it would be a false positive.
DECLARED IMPRECISION (family law: document the imprecision or the next reader trusts it as exact):
* The gate compares the grid's OWN min width against 320 and deliberately does NOT add ancestor
container padding. Attributing padding across nesting needs a cascade model a flat scan does not
have, and over-counting it would manufacture false positives. So T1 is a LOWER BOUND on the width
actually required: it fires only when the board ALONE cannot fit. `container_pad_max` is REPORTED
(not gated) so a reader can see the real budget is 320 - that.
* Tap-target sizing is read from blocks declaring `cursor:pointer`. A target sized purely by content
or by a shorthand this scan does not model is reported as UNKNOWN, never as a pass.
* This is a STATIC auditor. It proves the source-visible causes of a reflow failure; it does not
render. A PASS here is NECESSARY, NOT SUFFICIENT -- same honest envelope as nx_uiq_perf.
Composes the family lib (DRY: io + find + syscalls) rather than re-implementing them.
usage: nx_uiq_responsive --kat | <html-file-path>
exit : 0 GREEN | 1 RED | 2 cannot-read <- THE EXIT CODE CARRIES THE VERDICT (family law: a gate
whose exit code does not carry its verdict silently blesses every failure it finds).
dependencies 1 imports · 0 importers
imports: nx_uiq_color.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 43 | const K_MAGIC_2097152: i64 = 2097152 |
| 44 | const RSP_REFLOW_PX: i64 = 320 // WCAG 2.1 SC 1.4.10 Reflow bar |
| 45 | const RSP_TAP_MIN_PX: i64 = 24 // WCAG 2.2 SC 2.5.8 Target Size (Minimum), AA |
functions
| 50 | func rsp_find_from(buf: *u8, n: i64, pat: *u8, from: i64) -> i64 |
| 67 | func rsp_count(buf: *u8, n: i64, pat: *u8) -> i64 |
| 78 | func rsp_sp(buf: *u8, n: i64, i: i64) -> i64 |
| 87 | func rsp_sepc(buf: *u8, n: i64, i: i64) -> i64 called by 1: rsp_grids |
| 99 | func rsp_unit(buf: *u8, n: i64, i: i64) -> i64 called by 1: rsp_prop_px_h |
| 117 | func rsp_num(buf: *u8, n: i64, i: i64, pend: *i64) -> i64 |
| 136 | func rsp_blk_start(buf: *u8, i: i64) -> i64 |
| 144 | func rsp_blk_end(buf: *u8, n: i64, i: i64) -> i64 |
| 154 | func rsp_prop_px(buf: *u8, a: i64, b: i64, prop: *u8) -> i64 |
| 185 | func rsp_prop_px_h(buf: *u8, a: i64, b: i64, prop: *u8) -> i64 |
| 221 | func rsp_container_pad(buf: *u8, n: i64) -> i64 |
| 236 | func rsp_grids(buf: *u8, n: i64, res: *i64) -> i64 called by 2: rsp_auditrsp_selftest calls 7: rsp_find_fromrsp_sepcrsp_numrsp_blk_startrsp_blk_endrsp_prop_px+1 |
| 276 | func rsp_tap_min(buf: *u8, n: i64) -> i64 |
| 297 | func rsp_zoom(buf: *u8, n: i64) -> i64 |
| 307 | func rsp_audit(buf: *u8, n: i64, emit: i64) -> i64 called by 2: rsp_selftestmain calls 7: rsp_gridsrsp_tap_minrsp_zoomrsp_countrsp_container_paduiq_w+1 |
| 358 | func rsp_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8) { n=n+1 } return n } called by 1: rsp_selftest |
| 364 | func rsp_selftest() -> i64 |
| 432 | func rsp_slurp(path: *u8, buf: *u8, cap: i64) -> i64 called by 1: main |
| 445 | func main(argc: i64, argv: *i64) -> i64 |