doxa-maps/public
doxa-maps-88655c70 02fc4bd45c Regions tab 2: clone DX-life's region dashboard
Tab 2 was a subject band, four tiles and one bar chart. DX-life's /regions/<slug>
is five blocks, and the gap was the whole point of the tab. Ported from
RegionDetail.vue, block for block:

  • back-link / title / summary, centred          RegionDetail.vue:47-51
  • four stat cards                               :53-70
  • three DOXA goal cards in their .switcher      :88-141
      Prayer Coverage — the segmented 100+/1+/none bar with its legend
      Adoption Progress and Engagement Progress — progress bars
      each goal sentence verbatim; they are the DOXA goals, not our copy
  • the five-column country breakdown             :144-171

Every figure comes from the rollup this element already computed, so tab 1 and
tab 2 still cannot disagree about a number. Nothing was invented to fill a card.

WHAT HAPPENS WITH NOTHING SELECTED, which was the open question: DX-life has no
answer to borrow — /regions is the list, /regions/<slug> always has a subject,
and [slug].vue 404s when the slug matches neither. A 2-tab element can't do
that, since tab 2 is reachable before anything is clicked. So it keeps their
invariant (the dashboard always has a subject) and makes the widest honest
subject the default: All Regions, every figure summed, the table switched from
countries to regions so it still compares like with like, and a line saying how
to narrow it. The back-link returns there instead of navigating.

Two substitutions, both forced by Bebas Neue being uncloneable (their font file
is served without CORS) and both measured, not guessed:
  • goal-card h2 pinned to --font-size-2xl (38.147px), the FLOOR of their own
    clamp. Measured: 'Engagement' is 380.1px at their 59.6046px in our stand-in
    face and 243.2px at 38.147px, against 261.55px of inner width. Their size
    made each card's min-content ~490px, so the third wrapped to its own row —
    579/579/1200 instead of their 372/372/372.
  • goal-card figures stepped one rung to --font-size-3xl and pinned nowrap, so
    '21 / 2,107' cannot break after the slash and read as two numbers.
Also min-width:0 on the switcher children: a flex item's automatic minimum is
its min-content, which is what blocked their basis from governing.

Verified against the LIVE site, not against the stylesheet: 33 computed
properties on doxa.life/regions/africa at 1440x1000 are now IDENTICAL, 0 differ,
and the four stat figures match their API exactly (315 / 41 / 43,045,275 / 300).
That diff is also what caught a real error — I had the low end of their 1.33
spacing scale shifted a step (xs is 1rem = 10px, 2xs is 7.5188px, 3xs is
5.6532px), so table cells and stat labels were a step tight. Every ported value
is now exact token math rather than one decimal place.

23 assertions across the three selection states, plus the tab-1 swap: reverting
this file to HEAD and rebuilding fails 21 of them.

Not ported: RegionDetail's CountryMap. It needs a per-region centre/zoom/bounds
rollup and a token-bearing map child, and this profile ships isMap:false — a
separate piece of work, not a detail. The comparison chart stands where their
map goes until it lands.
2026-09-23 23:33:51 +00:00
..
__gallery Legend rises into the removed search bar's space -- but only where it was removed 2026-09-23 18:30:00 +00:00
assets Vendor Vue for the gallery shell, so the self-hosted rung finally exists 2026-09-22 04:59:30 +00:00
doxa-maps Regions tab 2: clone DX-life's region dashboard 2026-09-23 23:33:51 +00:00
.gitignore Keep the development-era internal code name out of shipped files 2026-09-22 22:18:18 +00:00
index.html Land the swarm's work: no iframes anywhere, a tree that keeps its shape, deeper facets 2026-09-22 14:51:52 +00:00