Measured all seven production maps at 390x844 with touch emulation. 195 controls sat below WCAG 2.5.8's AA minimum of 24x24 CSS px, spread across five maps -- but they were not five owners' bugs. Grouped by class, 195 failures were ten classes, and 119 of them lived in library/: the same PosterWall, PinHint, LegendMobile, SemanticTreeLegend and ResearchMapFilterPanel controls repeated down a list and across four maps. Routing the per-map counts would have filed hundreds of defects against owners who do not own the geometry. Raised the shared controls, scoped to (pointer:coarse). 2.5.8 is a touch ergonomics rule, and these components sit on maps this change does not own: a finger gets the bigger target, the mouse keeps the density those owners designed. The poster row is the reason this matters -- its height was tuned by eye against the card's blue outline, and growing it for a pointer that needs no help would have spent the artwork clearance to fix nothing. min-height states the 24 instead of deriving it. Growing the padding first MEASURED 23.7px and 23.0px -- under by a third of a pixel and by one, because the height is padding plus a line box the renderer computes from a 10.5px font. The declared minimum also survives a font swap or a locale with taller glyphs. The header tape now self-centres like the footer. It hung on top:-11px, half of its then-fixed 22px height, which silently becomes wrong the moment the height changes -- as it just did. top:0 with translate(-50%,-50%) sits on the border at any height, the mechanism the footer already used, and one less number to keep in sync. Two exceptions in 2.5.8 are now encoded in the probe rather than remembered. Inline: 48 .uupg__country-link "failures" are an <a> inside a paragraph, computed display:inline, sized by the line-height of the text around it -- the spec exempts them and the probe now skips display:inline, counting them separately. Equivalent: a .lpb-seg progress segment is 10px tall inside a track that clips overflow, so no hit-area extender can reach 24px; it resolves to a tree node and calls the same selectNode a full-width legend row calls. 195 failures on five maps -> 4 on two. UPG-100 alone went 137 -> 0. The poster tape gate and per-row persistence still pass. |
||
|---|---|---|
| .. | ||
| charts | ||
| hints | ||
| legends | ||
| map-controls | ||
| poster | ||
| qa | ||
| search | ||
| tables | ||
| PeopleGroupDetail.vue | ||
| README.md | ||
| ResearchMapFilterPanel.vue | ||
| ResearchMapSideMenu.vue | ||
| SideMenuDrawer.vue | ||
| ViewSelect.vue | ||
| WARNING.md | ||
library/components/ — shared Vue components
The map UI, built from parameterized pieces every app-profile reuses. Fix one here and every map benefits — never edit a shared component to customize one map.
library/components/
┌───────────────────────────────────────────┐
│ legends/ map-controls/ poster/ │
│ charts/ tables/ │
│ PeopleGroupDetail.vue SideMenuDrawer.vue │
│ ResearchMapFilterPanel.vue …SideMenu.vue │
└───────────────────────────────────────────┘
reused by every app-profile via @map/components/…
legends/,map-controls/,poster/each have their own README.- Every component uses
<script setup>, callsuseShadowStyles(), and reaches stores viainject('mapStore' | 'uiStore' | 'dataStore')— never a direct store import.
Full catalog + conventions:
../../documentation/architecture/components.md ·
per-file roles: ../../documentation/reference.md.