Commit graph

1583 commits

Author SHA1 Message Date
Doxa Maps
5cbabe7ffa Cities with Internet and Gospel Resources: "What can this map do?" is the top of their control column
The ⓘ becomes the first round control in each map's own column (MapInfoButton, as Prayer Progress
has it), and each tab's gallery row says trigger: 'control', so there is exactly one ⓘ: the control.
MapInfo keeps its fail-open, so a page where the control never arrives still gets the floating one.

Rebuilds cities-internet, gospel-resources and doxa-maps-spa, with their pages and the two manifests.
2026-09-30 04:44:32 +00:00
Doxa Maps
3d462ec308 The ⓘ control's pointer: once per page load, gone after a click or a tab change, no checkbox
Every map whose ⓘ is its own control (MapInfo trigger 'control') now gets the same pointer:
it shows the first time that control is on screen in a page load, and goes for the rest of the
load once the reader opens the popup or leaves the tab. A full reload shows it again. This is
page-load memory, never storage, so the popup offers no checkbox in control mode: the "Keep
tooltip turned on" box and its string (all 11 locales) are removed, along with the pointerKeep
prop that selected this model per tab. Floating-mode maps keep their stored model and their
"don't point again" box, unchanged.

Leaving the tab is read from the pane (hidden or inert), on the control's intersection change
and the existing 1.5 s measurement tick.

Rebuilt doxa-simple-map (it ships the mapInfo catalogue) and doxa-maps-spa, then tree + SRI.
2026-09-30 04:41:04 +00:00
Doxa Maps
8a271596ce Merge remote-tracking branch 'origin/development' into big-picture-plugin/bp-c3-header
# Conflicts:
#	public/dx-maps/doxa-maps-spa/doxa-maps-spa.js
#	public/dx-maps/doxa-maps-spa/doxa-maps-spa/app/index.html
#	public/dx-maps/doxa-maps-spa/doxa-maps-spa/index.html
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
2026-09-30 04:34:58 +00:00
Doxa Maps
d7b496c6b1 Prayer Progress tells the gallery its ⓘ is coming, so the floating one never flashes on a slow load
Prayer Progress draws its control column only once the style and the people-group data are in,
which on a slow phone can take longer than any fixed wait, and then the gallery's floating ⓘ
appeared and was swapped for the control. Now the map announces at mount that a control is on its
way ('dxmaps:mapinfo-pending'), and MapInfo waits for the map instead of a clock.

- A known failure (the map reports an error) or an unmount before the map is ready withdraws the
  announcement, and the floating ⓘ shows at once.
- While a control is pending, the 30 s wait becomes a 90 s backstop (time on screen), so an
  unreported failure still gets a floating ⓘ.
- A map that never announces anything keeps the 30 s wait, and pages with no MapInfo are unchanged.

Rebuilt doxa-simple-map and doxa-maps-spa, then tree + SRI.
2026-09-30 04:32:55 +00:00
Doxa Maps
d0de376f4a Big Picture header: rounded-square ⓘ left of a rounded-square Share
The dashboard header gains an info button ("What can this map do for you?") to
the left of Share. Both are rounded squares at the vertical tabs' radius
(--vtl-radius), matching the app's own roundedness; map controls stay round.

Built as a reusable, parameterized header-button form so other dashboards adopt
it by prop, not by copy:
- MapControlButton: new shape="rounded-square" (border-radius: var(--vtl-radius,8px)).
- ShareButton / MapInfoButton: a shape prop forwarded to MapControlButton;
  ShareButton also squares its rotating ring so a round ring never wraps a square.
  Defaults stay 'round' — every existing consumer is unchanged in behaviour.
- research-dashboard DashboardTopBar mounts the ⓘ and Share as one header-button
  group, sized to the bar with the 44px tap target kept for both. DOM order
  [ⓘ, Share] puts ⓘ at the logical start: left in English, right of Share in
  Arabic (the flex row reverses under rtl).
- doxa-maps-spa dashboard-plus-grid tab -> trigger:'control', so the tab's
  MapInfo is driven by the header ⓘ and the gallery's floating ⓘ is suppressed:
  exactly one ⓘ, fail-open. No new strings (reuses mapInfo.open, 11 locales).
2026-09-30 04:27:44 +00:00
Doxa Maps
3b933aefd4 Prayer Progress: round, spaced controls again, and no floating ⓘ while the map loads
The control column goes back to the library's round, spaced buttons at every width; the square
grouped card read too compact, on phones most of all. The ⓘ stays the top control.

In control mode, MapInfo no longer shows its floating button before the map's control has
announced itself. The map draws its column only once it is ready (style and people-group data),
so the floating ⓘ appeared for a moment and was then replaced by the control. The wait is bounded
at 30 s of time on screen, counted only while the pane is visible and not inert: measured column
arrival times run from 7 to 19 s on a local serve, so a shorter wait expired inside a normal load
and flashed late. If no control arrives, the floating button shows, so there is still always a way
to open the popup. Once a control has announced itself, measurement alone decides, as before.

MapInfo's plain <script> block (the page-load pointer memory) now sits above <script setup>, so
check:setup-order no longer reads it as used before its definition; its explanation moves into
<script setup> so the library index keeps the component's own description. Compiled output is
unchanged by the move.

Rebuilt doxa-simple-map and doxa-maps-spa (the only bundle that compiles MapInfo.vue), then
tree + SRI.
2026-09-30 04:17:28 +00:00
Doxa Maps
148f3cffe6 Merge origin/development into exp-shepherd/pp-info-control at the landing turn 2026-09-30 03:48:23 +00:00
Doxa Maps
79a426822c Merge remote-tracking branch 'origin/development' into regions/sparse-consistent 2026-09-30 03:41:13 +00:00
Doxa Maps
48a1a747ba Prayer Progress: "What can this map do?" is the top of its own control column
- Prayer Progress's column becomes the engine's square grouped card (controls="square"). Its first
  control is MapInfoButton, which opens the gallery's MapInfo for the tab. The gallery's tabInfo
  'prayer-map' entry now uses trigger 'control', so the floating button hides while that control is
  on screen, and shows again (fail-open) whenever it is not.
- MapInfo, control mode: the first-visit pointer now points at the control. Its place is measured
  against the pane (which scrolls) and goes on the control's physical inner side, so an Arabic page,
  whose column mirrors to the left, gets the pointer on the right with the arrow reversed. It shows at
  every width: the under-1200px rule was measured for the floating pointer crossing each tab's top
  strip, and does not apply here.
- MapInfo, pointerKeep (prayer-map only): the popup offers "Keep tooltip activated" instead of the
  every-map "don't point again" box. It is off by default, and opening the popup retires the pointer.
  Checked, the pointer keeps showing on every load. It is stored per map.
- mapInfo.keepPointer in all 11 locales.
- Rebuilt doxa-simple-map and doxa-maps-spa, then tree and fix:sri.
2026-09-30 03:31:15 +00:00
Doxa Maps
1728372a1e Reshoot the 173 country previews in the SPARSE layout
The country poster previews were the dense layout -- small facts table, both
vision columns, a smaller map -- while every UPG-100 thumbnail is SPARSE. Now
that the click-time print is SPARSE too, the stored country previews have to be,
or the card and the print disagree.

Generated with SPARSE=1 and checked BEFORE any browser time:
  · the generator's own layout guards: 173 of 173 ok, octilinear, 0 diagonals.
  · SPARSE on all 173: 0 sheets draw a dense-table element; all 173 carry the
    bold "N UPG's" count.
  · real values: 0 sheets show 0, NaN or blank population. Worst cases by UPG
    count: Sudan 105 / ~20.7M, Brazil 103 / ~63K, Laos 95 / ~968K.
Shot on the fleet's shared Chromium (no private browser), one page at a time:
173 of 173, 0 failed, all 3000x3000, none blank. Smoke-tested and looked at
first: Sudan shows the bold facts row, no vision columns, "1 of ~170 maps".

ALL 173 CHANGE: 173 source thumbnails, 173 full-size and 173 served previews
differ from development, 0 strays, nothing written to a stray library/ path.

China is deliberately NOT here: its thumbnail stays the dense "map 174 of 174"
it has tonight. Its print becomes SPARSE with "map 1 of 1" via the small-total
guard. The remaining numbering difference is R-CHN-SERIES-TIER, a product call
after the demo.
2026-09-30 03:30:10 +00:00
Doxa Maps
766d829028 Merge origin/development into gospel/cities-legend-fold 2026-09-30 02:57:55 +00:00
Doxa Maps
0288d3d083 Merge remote-tracking branch 'origin/development' into bundler-2/sr-band-first-screen 2026-09-30 02:53:10 +00:00
Doxa Maps
ed374bdb9f Cities with Internet: on a phone the legend folds behind one button, like Gospel Resources'
Fully open, the legend took 297px of a 712px phone map, 86% of its width, with the India-by-state
block and both caveats always showing, and there was no way to shut it. On a phone (under 700px,
Gospel Resources' breakpoint) the title stays and the rest folds behind "Key & notes": folded by
default, remembered for the session, and a remembered choice wins over the width default.
Desktop is unchanged. Two new strings, in all eleven locales.

Rebuilds cities-internet only, with its three pages and the two manifests.
2026-09-30 02:45:14 +00:00
Doxa Maps
b4079cc9d2 Merge remote-tracking branch 'origin/development' into regions/mobile-posters-2up
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/my-upg-100-list/my-upg-100-list.js
#	public/dx-maps/my-upg-100-list/poster-wall/index.html
#	public/dx-maps/my-upg-100-list/upg-100-list/index.html
#	public/dx-maps/my-upg-100-list/upg-100-mfe/index.html
2026-09-30 02:44:56 +00:00
Doxa Maps
c964c79db8 Merge remote-tracking branch 'origin/development' into upg100/status-badge-credits 2026-09-30 02:40:37 +00:00
Doxa Maps
eab8963a20 Regions: two country posters per row on a phone
Reported from a phone: on the Regions tab, "2 posters per row" for the country
posters did not work -- a 390px phone showed ONE per row.

THE CAUSE is a deliberate clamp in PosterWall. The per-row setting is 2, but the
grid is Math.min(perRow, fits) with fits = floor((viewport - 36) / 210), and at
390 that is floor(354 / 210) = 1. So the setting said two and the phone silently
showed one.

★ WHY THE CLAMP EXISTED, AND WHY IT IS SAFE TO RELAX NOW. It was added when a
two-up card (~162-170px) CLIPPED its action labels -- 'Prayer List' and 'Poster
Map' both read 'Pra...', and Romanian's 'Pachet de cartonase' was measured at 54
of 81 controls clipped at ro/390. That was then fixed separately: the labels WRAP
(.pfs > .pbtn, "a label too long for its box wraps"). With wrapping in place the
clamp no longer protects anything; it only costs the phone a column.

★ IT IS OPT-IN, NOT A GLOBAL CHANGE. PosterWall is shared by twelve files,
several of them frozen experimental maps. A new minCardPx prop defaults to 0,
which means the existing 210px clamp, so every wall that does not set it lays out
byte-for-byte as before. Only regions-list sets 150, which gives two per row at
360, 390 and 414, still one at 320 (which genuinely cannot hold two), and no
change on desktop (already capped at the per-row setting of 2).

MEASURED on the regions-list leaf page, this branch served locally, against
FINAL on :4611 -- by hit test and by eye:
  FINAL  @390 en   1 per row, 367px cards
  AFTER  @390 en   2 per row, 169px cards, 0/123 labels clipped
  AFTER  @390 ro   2 per row, 0/123 labels clipped   <- the old clipping corner
  AFTER  @390 ar   2 per row, RTL, 0/84 labels clipped
  AFTER  @1440 en  2 per row, unchanged
0 horizontal overflow and 0 console errors in every cell. The print buttons now
stack three high on a phone card instead of sharing a line.

KNOWN, COSMETIC, NOT CHANGED: at two-up the card's "53 UPG · Show on map" pill
wraps "Show on / map" onto a second line. Readable, not clipped.
2026-09-30 02:33:24 +00:00
Doxa Maps
76ba9c1a6d Simple Research's map band ends on the first screen
On a phone under DX Life's header, the band ran 32px past the fold (y132 to y876 on an 844px
screen). The legend sheet's bottom and its collapsed strip began below the fold, so a reader who
collapsed the legend could not reopen it without scrolling. The band now takes the height that is
visible below its own top, capped at the old 88svh, which is also the fallback. It is measured once,
and again only on a width change, so the URL bar showing and hiding does not resize the map.
2026-09-30 02:32:00 +00:00
Doxa Maps
a83b836160 Merge origin/development into studio/no-campaign 2026-09-30 02:31:41 +00:00
Doxa Maps
8dbad994f9 Merge remote-tracking branch 'origin/development' into upg100/status-badge-credits 2026-09-30 02:25:30 +00:00
Doxa Maps
c1763ebff9 No "campaign" in the DX Maps UI: the near-neighbor planner speaks of movements
The word is a military term, and the Driver asked for "prayer movement(s)" / "mobilization movement"
instead. The five user-facing strings in all eleven locales (55; the translated word too: Kampagne,
campaña, حملة, अभियान, 宣传活动 …) now say movement, in each language's natural church usage: Russian
"движение" with "вдохновить" rather than "мобилизовать", Arabic "حركة" with "تحفيز" rather than "تعبئة",
Chinese "宣教动员" rather than 宣传 (propaganda) or 运动; the Portuguese lines move to Brazilian forms like
the rest of the catalogue. The instance title and the meta note follow, and the CSV exports' column
headers become bridge_language / bridge_language_code (a user sees them in every spreadsheet).
Identifiers stay: the "view":"campaigns" profile-config value (embeds pass it), the i18n key names,
file and function names, and the campaigns-server references.
2026-09-30 02:17:14 +00:00
Doxa Maps
b609202f5c Keep the UPG-100 status badge off the map credits
The badge sat at bottom:10px right:10px, z-index 5: the corner both engines
keep their attribution in. It won every hit point of the OpenStreetMap
credit on both engines in English and Arabic. In Arabic the list panel
mirrors onto that corner, so the badge also covered the panel's pin note,
and the panel itself lay over the top of the credit line.

- The badge sits at the inline end (right in English, left in Arabic),
  6px above --upg-credit-floor: 30px for the tallest single-line credit
  (the Mapbox wordmark) plus the lift LegendMobile gives the engine
  corners on a phone. z-index 1 keeps it under the engine corners, and it
  takes no pointer events.
- On phones (max-width 767px) it is hidden. It always sat under the
  collapsed legend sheet there (0 of 15 of its points visible), so this
  keeps what a phone showed.
- The batch HUD, which stacks above the badge, follows it.
- The desktop legend panel ends above the credit band where a credit
  shares its corner: Arabic on both engines (the attribution) and Mapbox
  in English (the wordmark). MapLibre in English is unchanged. The rule
  is scoped to the desktop slot; unscoped, it collapsed the phone sheet's
  panel on Mapbox.

Measured on a local serve of the upg-100-mfe leaf, 1440 and 390, both
engines, en and ar. Credit hit points before, at 1440: OpenStreetMap
0/15 in all four cases; the Mapbox wordmark 5/15 in English; in Arabic
on MapLibre every credit was 0/15. After: every credit 15/15, except
'© Mapbox' in Arabic, whose right-to-left box spans the whole credit
line and whose points go only to the neighbouring credit links. At 390
all credits are 15/15 before and after, and the sheet's panel is
unchanged (48px).
2026-09-30 01:30:49 +00:00
Doxa Maps
bff75e0995 Gospel Resources: in Arabic the people-group card opens opposite the legend, not on it
The desktop card was placed with right:14px while the legend sits at the inline start. In a
right-to-left page the legend mirrors to the right and the card stayed there, so opening any
people group or country covered the legend at every desktop width. The card now sits at the
inline end, as Cities' copy of the same rule already did. English is unchanged.

Rebuilds gospel-resources only, with its five pages and the two manifests.
2026-09-30 01:13:23 +00:00
Doxa Maps
072b1ff216 Regions-tab print: pass the same series as the Country Posters wall
Every country poster printed from the Regions tab read "map 1 of 0" and "This
map is one of a 0-map set called the Country Maps" -- nonsense on a printed
poster, on the demo's showcase flow (Regions -> a country -> Poster Map). Found
by the served check on FINAL.

WHY: makeCountrySheet called generateCountrySheet with no series, so
generateSheet fell back to its default { totalGroups:0, totalLists:0, index:1 }.

NOT A REGRESSION from the one-definition change, and worth recording because it
was first reported as one. The plugin-local copy regions-list used before that
change passed no series either; across it regions-list.vue changed by exactly
one line, the import. The defect has been in the Regions print since 168b1f1bd.
The Country Posters wall was never affected because it computes its own.

THE FIX computes the series exactly as the wall does (country-poster-wall.vue):
the tier is every country printed at the same sheet size, the total is that
tier's length, and the index is the country's position in it by id. It lives in
ONE place, seriesFor() in the library, rather than as a second inline copy of the
wall's formula -- the same duplication this branch's parent removed for the sheet
itself. regions-list passes the FULL country list, not a region's sublist:
indexing a region's own list would print "map 3 of 12" beside a thumbnail that
says "map 57 of 173".

PROVED, rendered with the values seriesFor returns:
  Sudan  index 1 of 173  ->  "map 1 of 173"  |  "one of a 170-map set"
  Chad   index 4 of 173  ->  "map 4 of 173"  |  "one of a 170-map set"
which is exactly the text the wall prints for the same two countries on FINAL,
measured on the served page, and what their thumbnails say. A row with no sheet
tier gets undefined, keeping the renderer's own default rather than a fabricated
position.

KNOWN, NOT CHANGED: China is the only 3x4 sheet, so its tier has one member and
it prints "map 1 of 1" / "a 0-map set" -- here AND on the wall, identically,
because this matches the wall by design. Its thumbnail says "174 of 174". Fixing
it means choosing whole-series numbering over per-tier, which is the carded
174-vs-173 question, not a freeze-night change.
2026-09-30 00:00:00 +00:00
Doxa Maps
5484b844c6 Merge remote-tracking branch 'origin/development' into regions/country-sheet-onedef 2026-09-29 23:34:15 +00:00
Doxa Maps
99783ff0f7 Merge remote-tracking branch 'origin/development' into bundler-2/rm-unmount
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/doxa-research-map/doxa-research-map.js
#	public/dx-maps/doxa-research-map/research-map/index.html
#	public/dx-maps/doxa-research-map/research-map/maplibre/index.html
#	public/dx-maps/manifest.json
2026-09-29 23:29:55 +00:00
Doxa Maps
2eb5b38027 Merge origin/development into exp-shepherd/pp-quiet-cancel at the landing turn 2026-09-29 23:22:56 +00:00
Doxa Maps
087f562e04 Reshoot the 174 country previews with the region hue and ink badges
The poster walls' card THUMBNAILS are stored WebP files, not generated at the
click, and all 174 were last shot on 09-25 -- teal. Since the region hue
landed, the PRINT has been hued, so both Country Posters and the Regions tab
showed a teal thumbnail above a hued poster. The Experimental section shows on
Deep Research, so that mismatch was visible.

Shot in one pass on the shared browser: 174 of 174, 0 failed, 0 retries,
23:00:37-23:10:07Z, one engine, DSF 2. Measured by the shooter: none blank (at
least 1,000 distinct colours each), and the count of sheets by their --zc hue
matches the region census exactly -- 41 Africa, 27 Asia, 27 Europe, 21 Middle
East, 18 Other, 17 Oceania, 14 North America, 9 Latin America. Asia is 27, not
28, because India has no sheet.

★ ALL 174 CHANGE, and that is the check that matters here. make-previews used to
write one directory too high (library/plugin-designs/..., library/data/posters)
while reporting success, so a reshoot could complete, look complete, and change
no served file at all. With that fixed, 174 of 174 source thumbnails, 174 of
174 full-size sources and 174 of 174 served previews differ from development,
with 0 untracked strays.

China was regenerated first with the whole-series count: 'map 174 of 174' and
'one of a 170-map set', where it had printed 'map 1 of 1' and 'a 0-map set'.
2026-09-29 23:18:26 +00:00
Doxa Maps
476989bab5 Merge remote-tracking branch 'origin/development' into regions/country-sheet-onedef
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 23:17:40 +00:00
Doxa Maps
2ddd8dc1e8 Merge origin/development into exp-shepherd/pp-quiet-cancel, and rebuild doxa-simple-map on the merged source 2026-09-29 23:17:05 +00:00
Doxa Maps
67fed8b79f Merge remote-tracking branch 'origin/development' into bundler-2/bp-grid-locale 2026-09-29 23:15:51 +00:00
Doxa Maps
e4b5a3d1b1 Prayer Progress released mid-start no longer reports a failed map
Prayer Progress is a heavy gallery tab: switching away empties its slot. If the map
is still starting, initializeMap returns silently (useMapInstance's liveness
checks) and leaves map.value null. onMounted then logged "[doxa-simple-map] Map
failed to initialize, check token and container": a console error that blamed
the token for a tab switch.

Measured on development's tip, served from its committed tree, on the shared
browser, a phone in Arabic (pp-fastswitch.mjs): switched away 150 and 500 ms after
selecting the tab, 2 runs in 10 logged it. The control runs, switched away after a
full start or never switched away, logged nothing.

Same shape as the research map's quiet cancel (0c263fb60): when the map's
container is gone or detached, both failure paths return quietly. A mounted pane
that really fails still logs.
2026-09-29 23:08:17 +00:00
Doxa Maps
baa60ba647 Merge remote-tracking branch 'origin/development' into regions/country-sheet-onedef
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-dashboard.js
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 22:59:27 +00:00
Doxa Maps
2d764b740d Big Picture's info button sits above its filter bar, so it can be clicked
At top 46px the button lay in the empty end of Big Picture's filter area, but that bar is a
positioned layer (z-index 55) painted over the button (z-index 20): nothing opened on click (rega,
1440, en and ar). The filter area wraps with width, so no spot below it is free at every width (at
1024 the stats row moves under a fixed offset). pos.raise lifts the BUTTON to z-index 60; the one-time
pointer stays under the bar, so no filter is covered even visually. Measured on the built tree: no
interactive element or text under the button, the button topmost at its centre, and a click opens the
popup, at 1440, 1024 and 800, en and ar.
2026-09-29 22:48:21 +00:00
Doxa Maps
0c263fb601 A research map released mid-start no longer reports a failed map
When the reader switches tab while the research map is still starting, the gallery releases the
pane, and initializeMap returns quietly with no map. The handler logged that as "Map failed to
initialize — check token and container", so the console error landed in whichever tab was then open
and blamed the token. A released container is now a quiet cancel.
2026-09-29 22:45:32 +00:00
Doxa Maps
e3c631932f Merge origin/development into studio/batch (upg100's example images) 2026-09-29 22:33:34 +00:00
Doxa Maps
1c5a6bd589 On a phone, Cities' info button takes the corner above its zoom column, like Gospel's
At 390 Cities' legend spans the same width as Gospel's (344px), and side 56px put the button on
the end of the legend title's first line (gospel's measurement; a probe that also counts visible
text under the button reports the same, 236px2). narrow side 4px, as Gospel.
2026-09-29 22:28:52 +00:00
Doxa Maps
f4c026501d Big Picture's grid took its language from the page URL, not from Big Picture
The grid is mounted inside Big Picture as a component, so it shares Big Picture's host, and its
direction is written onto Big Picture itself. Its profile-config carried only the list, so its
language fell through to ?lang= on the page. An English page opened with ?lang=ar therefore laid
the whole of Big Picture out right-to-left, English included.

The grid now receives the host's language under both keys, locale and lang.
2026-09-29 22:26:49 +00:00
Doxa Maps
838f6c14b6 Merge remote-tracking branch 'origin/development' into upg100/examples 2026-09-29 22:25:44 +00:00
Doxa Maps
8e081cea44 UPG-100's and Simple Research's popups show the packet and the card deck
UPG-100's info popup lists its Middle East Core poster, then the full packet's 12 pages and the 70-card
deck (upg100's pre-generated files). Simple Research shows the same 12 pages, captioned "Example
packet: Middle East Core": same renderer, method and 'full' variant, but a UPG-100 zone's data, so it
is labelled as an example rather than passed off as a Simple Research selection.
2026-09-29 22:18:35 +00:00
Doxa Maps
c8fde78522 Merge remote-tracking branch 'origin/development' into bundler-2/dirclear-ready 2026-09-29 22:18:12 +00:00
Doxa Maps
e704bdbbf8 Merge remote-tracking branch 'origin/development' into upg100/examples 2026-09-29 22:17:24 +00:00
Doxa Maps
99c22caf72 Merge origin/development into studio/examples 2026-09-29 22:14:22 +00:00
Doxa Maps
9c5ac8094b The UPG-100 info popup's examples: Middle East Core's packet pages and card deck
Twelve packet pages and seventy prayer cards, rendered from the current
renderers (people-based knows-Christ page, page-filling grids and charts,
sharp card photos) and shot in the fleet's shared browser: pages at 1500px
reduced to 1200px wide, cards at 480x672, WebP q80, 2.8 MB. They ship under
previews/examples/middle-east-core/, which the existing previews staging
copies into the tree, and the popup's pages and deck examples read them.
Middle East Core is the packet covering the most people in unengaged groups
(IMB GSEC 0-1).
2026-09-29 22:07:17 +00:00
Doxa Maps
b9514d68d3 On a phone the info button takes each tab's free corner
At 390 the desktop offsets landed on each composite's own top chrome: Regions' and UPG-100's view
selector and Gospel's search box (probe, en and ar). A tab's pos can now carry `narrow`, laid over
it while the shell is narrow (max-width:760px): Regions and UPG-100 put the button at the START of
their strip, which is empty on a phone; Gospel takes the corner above its zoom column. The same
probe then reports no interactive element under the button on any tab, 1440 and 390, en and ar.
The one-time pointer still lies over the selector or search box until first opened; it takes no
clicks (pointer-events:none).
2026-09-29 22:02:08 +00:00
Doxa Maps
c79e26a089 Middle East Core's stored poster and preview, regenerated with tonight's renderer
The stored poster (data/posters) and its wall preview predated the ink pin
badge: 57 pin numbers drawn white on the zone hue, 1.44:1. They are what the
UPG-100 info popup shows and opens ("Open full size"). Regenerated from the
current poster-render in its stored 3x4 format (1500x2000) and published;
the pin numbers are now white on #1c1c17, 17.10:1. The preview and the
1500px download are made from a 3000px shot of the regenerated sheet with
make-previews' own sizes and qualities (a 3x4 sheet now makes a 420x560
thumbnail; the wall letterboxes it). The other 27 stored zone posters are
fallback-only and follow after the demo.
2026-09-29 21:50:51 +00:00
Doxa Maps
81a84138c9 Regions and UPG-100: the info button sits clear of their Share button too
A geometry probe (every visible interactive element in every shadow root, intersected with the
button's box, 7 tabs in en and ar at 1440) found the default position covering each composite's Share
button exactly, which no screenshot showed. They take side 56px like the map tabs. With that, the
probe reports no element under the button on any tab in either direction; before this branch it
reported Zoom in/out under it on Prayer Progress, Cities and Gospel and Share on Big Picture.
2026-09-29 21:40:54 +00:00
Doxa Maps
11554f40b6 The info button sits clear of each map's own controls
At the default 12px from the top and the end of the line, the button covered the zoom-in button on
Prayer Progress, Cities with Internet and Gospel Resources (a control nobody could click), Big
Picture's header buttons, and Simple Research's tab bar, in English and, mirrored, in Arabic
(rega's 1440 captures, exp's second read). Each tab now carries its placement in src/tabInfo.js,
passed as MapInfo's own --map-info-top/--map-info-side: 56px from the end beside a zoom column,
46px down below Big Picture's header bar, 56px down below Simple Research's tab bar. Regions and
UPG-100 keep the default. MapInfo itself now places by the logical end of the line (upg100), so the
gallery passes no direction.
2026-09-29 21:12:54 +00:00
Doxa Maps
520973c1d7 One country-sheet definition: the Regions tab's poster was still teal
exp's second read of 1ab8524cf found a real defect on the demo path, and a census
of the tree found the cause was worse than the symptom.

THE SYMPTOM: the Regions tab printed a TEAL country poster and logged a warn,
while Country Posters printed the same country HUED. That is precisely the "two
different posters for one country" the hue change exists to refuse.

THE CAUSE: regions-list.vue:73 imported a plugin-local copy,
src/country-sheet-print.js, byte-identical to library/packet/countrySheet.js
except for the region key. The region forwarding was added to the LIBRARY file,
so countryRegionColor(undefined) returned the old flat teal and warned.

★ AND THE LIBRARY FILE HAD NO IMPORTERS AT ALL. Its own comment claimed two
consumers -- the country-poster wall and <doxa-country-map> -- and a census found
NEITHER was true: regions-list imported the local copy, and
country-poster-wall.vue:94 defines its own inline countrySheet that calls
generateCountrySheet directly (passing the whole record, which is why THAT path
was correctly hued). So the module was an orphan wearing a comment that said
otherwise, and the region key was added where nothing read it. A move that was
never finished, and the duplicate stayed invisible until one copy was edited.

regions-list now imports the library module, the copy is deleted, and the
comment says what is true. Not re-copied: a duplicate of that file is
indistinguishable from it until one side is edited, and then it is a silent
divergence.

CHAIN VERIFIED TO SOURCE, since the hue is only right if the region survives
every hop: POSTER_BY_ISO3 holds country-posters.json records, which all carry a
region; localisedPoster SPREADS the record in both its branches, so the key
survives a locale switch; postersFor passes it; makeCountrySheet forwards it.
ARTIFACT PROOF: the region forwarding in the rebuilt regions-dashboard bundle
goes from 1 occurrence to 2, and POSTER_REGIONS plus the full region-name list
are present in it.

The no-poster fallback branch in postersFor still builds an object without a
region, deliberately: it has no sheet to draw, and it already carries
unsupportedReason.

NOTE ON HISTORY, not rewritten: f6a3f85a2 is titled "Rebuild the three
consumers…" but it also carries SOURCE changes -- the ink .pin-num-bg in the
shared renderer and the warn-once in posterSheets.js. The title understates it.
It is pushed, so it stands; recorded here instead.
2026-09-29 20:55:27 +00:00
Doxa Maps
9cf5a68696 Big Picture's table headers come from mapInfo, so the gallery stops carrying all of 'dashboard'
The four headers are copied verbatim, in all eleven locales, from dashboard.json into mapInfo.col
(peopleGroup, country, region, population); no string is retranslated. Measured with areasForBundle:
doxa-maps-spa carried [buttons, dashboard, grid, mapInfo, messages] and now carries [buttons, grid,
mapInfo, messages]. The bundle drops from 420,172 to 371,064 bytes (136,998 to 124,005 gzipped).
2026-09-29 20:37:39 +00:00
Doxa Maps
1fd562c28e Read the page's own direction at mount, not at our first write
The clear-only-ours fix recorded the host's dir lazily, inside the rtl branch,
the first time it wrote. That is correct only while nothing else has written a
direction first. If anything set dir="rtl" on the host before that moment, the
element recorded rtl as "the page's own declaration" and then faithfully
restored it on every switch away from Arabic -- so the direction never cleared,
which is the defect this whole change exists to remove.

Measured on the Big Picture leaf: ar left rtl, and zh put rtl straight back,
while its three siblings with the same code passed. The difference was not the
code; it was that something writes rtl on that host before the element does.

Reading the attribute on the FIRST call instead, before any write of ours, is
the only moment it is certainly the page's and not ours. A page that genuinely
declares dir still owns that decision and still gets it back.

Five cases driven against the real function in all four files: no dir at boot,
a page declaring ltr, a page declaring rtl, an element mounting while already
Arabic, and -- the case that reproduces the failure -- a FOREIGN writer setting
rtl after mount and before ours. Restoring the lazy capture to one file fails
that fifth case alone and leaves the other four passing.
2026-09-29 20:31:04 +00:00
Doxa Maps
d975337501 Push the locale under both keys, because every reader prefers one of them
The push wrote `lang`. Every reader takes `locale` FIRST and only then falls
back to `lang`: ProfileLoader.vue:189, and people-groups-grid.vue at :273 and
:380. So writing one key is correct exactly while no child config carries the
other, and stops working silently the day one does -- a `locale` left by a boot
copy or a host-list path would shadow every fresh `lang` we push, for the rest
of the session, with both values sitting in the same object.

Writing both keeps them in step whatever put them there.

Not broken today: the nested configs were measured carrying no locale key at
all. This closes the class rather than a symptom, which is worth one line.

Shown by driving the real function: with a stale {lang:'en', locale:'en'} the
push now yields ar in both keys, and a config carrying only `locale` switches
too. Reverting to the lang-only write leaves {lang:'ar', locale:'en'} -- the
exact shadowing above, where the map reads English while holding a fresh lang.
2026-09-29 20:31:04 +00:00
Doxa Maps
77415cf361 Switching from Arabic to Chinese left the page right-to-left
Every element that sets a reading direction did it one way: if the locale was
RTL it wrote dir="rtl", and there was no else. So a reader who moved from an
RTL locale to an LTR one kept the right-to-left layout for the rest of the
session -- Chinese laid out backwards, which reads as a broken page rather than
a stale setting.

The reason the clear was missing is sound and is kept: a host page that
declares its own dir owns that decision, and blindly removing the attribute
would take that with it. So each element now remembers what it found before it
first wrote, restores that value verbatim when the locale stops being RTL, and
removes the attribute only when there was none to begin with. It clears its
own, never the host's.

FOUR elements, not the three the report named: big-picture.vue,
research-map-plus-grid.vue and people-groups-grid.vue all carry it, and so does
dashboard-plus-grid.vue -- the Big Picture composite, same shape, found by
checking the neighbours of the named lines rather than only the lines
themselves.

The comment above each one said "Only ever SET, never cleared". Left alone it
would now describe the opposite of the code, so it says what the code does.

Verified two-sided against all four shipped files, driving the real extracted
function: it clears what it set, preserves a host's own dir, and still sets rtl.
Restoring the one-way body to one file fails exactly the first two and leaves
the third passing, with the other three files unaffected.
2026-09-29 20:31:04 +00:00
Doxa Maps
4a153d5b7b Big Picture's info popup shows real output: an excerpt of its spreadsheet
Big Picture's export is a spreadsheet, so its example is a kind:'table' excerpt (sr): the six largest
groups by population, of 2,107, with the live table's own column keys (dashboard.people_group,
.country, .region, .population), so the popup header and the table's header cannot drift.

Cost, measured: those keys bring the 'dashboard' area into the gallery bundle, which grows from
369,635 to 420,172 bytes (123,536 to 136,998 gzipped, +13.5 KB). The alternative, header keys
duplicated into 'mapInfo' in eleven locales, is a translation job for after the demo.
2026-09-29 20:25:42 +00:00
Doxa Maps
fa69209035 The gallery's published section order: Prayer Progress before the UPG-100 List
The Deep Research page publishes the rail as Dashboards (Big Picture, Simple Research, Regions),
Prayer Mobilization (Prayer Progress, UPG-100 List), Gospel Research (Cities with Internet, Gospel
Resources), then the Experimental folder. Only the Prayer Mobilization pair moves. Big Picture now
says "desktop only" on every width, not only once a phone has disabled it.

check:spa-tab-order asserted the old four-name order with UPG-100 first; it now asserts all seven
published rows in order (still relative, with tab 1 positional). It needs a browser: rega runs it.
2026-09-29 20:00:36 +00:00
Doxa Maps
a569868fef Merge remote-tracking branch 'origin/development' into regions/country-map-refetch 2026-09-29 19:44:14 +00:00
Doxa Maps
b3e67c7f2b Merge remote-tracking branch 'origin/development' into bundler-2/panelang 2026-09-29 19:38:36 +00:00
Doxa Maps
2b210b78f0 Merge remote-tracking branch 'origin/development' into regions/country-map-refetch
# Conflicts:
#	package.json
2026-09-29 19:36:16 +00:00
Doxa Maps
cff06fb8e6 Merge origin/development into studio/deep-research 2026-09-29 19:34:32 +00:00
Doxa Maps
b0d08224c1 A live language switch never reached the panes inside Simple Research
The composite re-pushed its FILTER state to the map and the grid on every
change, and nothing else. So a host switching language moved the composite's own
chrome and stopped there: the outer element received the new profile-config,
the push re-parsed each child's EXISTING attribute, and the boot `lang` survived
every write. Measured on a live en to ar switch: the map and the grid both stayed
English while the frame around them changed.

The panes were never at fault. Each child's own chain is fully reactive -- it is
reactive to its own prop, and its prop was frozen.

The map now carries the locale in the same push that carries the filters. The
grid needs its own line, because its three linked facets travel as separate
attributes while its language travels in profile-config, which this composite
set only when a host supplied a list, and never again. And a locale change now
triggers a push at all: the existing watchers cover filter state only.

The grid write is conditional so an unchanged locale writes nothing. That
matters here more than it looks: setting a pane's attribute makes it re-filter
and emit, and the composite reads those emissions -- which is what the `pushing`
guard above exists for, after a measured round trip once cancelled a selection
the composite had just applied.

Verified two-sided by driving the real pushToChildren against stub elements:
the locale reaches both panes, and a repeat at the same locale adds no write.
Removing the map's line fails that assertion alone and leaves the grid's passing.
2026-09-29 19:30:31 +00:00
Doxa Maps
37f3aa1221 All seven gallery tabs carry their info entry; a tab whose text is not bundled shows no button
Each production tab reads mapInfo.tab.<tabId>.lead and .takeaway, and Regions also its note, with
the India/China reasoning beside it. Only files already in the tree are listed as examples (the
UPG-100 poster); the rest join when their shots land. A tab's button renders only when its lead
key resolves in the bundled catalogue, so a key that has not landed yet hides the button instead of
opening a popup of raw key names.
2026-09-29 19:17:42 +00:00
Doxa Maps
a1d9a1e318 Merge origin/development into studio/deep-research (MapInfo as landed; upg100's files take development's side) 2026-09-29 19:16:45 +00:00
Doxa Maps
656503a28d Merge remote-tracking branch 'origin/development' into regions/pane-config-land
# Conflicts:
#	package.json
2026-09-29 19:12:46 +00:00
Doxa Maps
e643e8a30e country-map: key the refetch by value, let only the newest response win, show the wait
Three defects on country-map/country-map, which is production -- DX Life's
country pages. Found by auditing the element rather than from a report.

1. ANY profile-config change refetched all 2,106 records. The watch getter
   returned a NEW ARRAY literal, and Vue compares a watch value with Object.is,
   so a fresh array always reads as changed; both computeds read the injected
   cfg, so the effect re-ran on every config change and the callback then fired
   unconditionally. MEASURED with real Vue: flipping isDark refetched the whole
   endpoint and redrew the map, and so did a host adding pinHint. A joined
   STRING compares by value, so only a real language or country change refetches
   -- which must still refetch, because the API localises the names.
   This was latent waste until the composite re-forward made config writes
   routine. It is now on every upstream locale switch, so the two changes are
   complementary rather than independent.

2. A SLOW EARLIER RESPONSE OVERWROTE A NEWER ONE. loadPoints is async and had no
   sequencing at all -- 0 abort or generation tokens in the file -- so two runs
   could be in flight and the one that STARTED first could FINISH last. Both
   assigned points, so the map showed the previous country's pins with no error
   and nothing for the reader to notice. Every run now takes a ticket and a stale
   ticket writes nothing: not the points, not loadFailed, not the spinner the
   current run is still using. fetch is left to complete rather than aborted,
   because the response is cached for the next switch back.

3. `loading` WAS WRITE-ONLY: assigned in three places and read in none, zero
   template references. A reader on a country page waited on an empty map -- no
   outline, no pins, no message -- which is indistinguishable from a country that
   genuinely has no people groups, and this element fetches the whole list before
   it can draw one pin. "Loading results..." was already in the catalogue in all
   eleven locales, so saying so cost no new string and no parity debt.

check:country-map-refetch guards all three. It drives the REAL reactive chain
with real Vue and takes the watch key expression OUT OF THE SHIPPED SFC, because
bug 1 is entirely a question of what Vue considers changed and is invisible to
any test that fakes reactivity or re-types the watch.

Mutation-tested, 5 mutations, all caught by name. The first version of the gate
MISSED one: a bare /if \(!current\(\)\) return/ grep matched the guard in the
catch block, so removing only the guard before the points write still passed.
The assertions are positional now -- the guard must sit immediately before the
assignment it protects -- and the catch guard is asserted separately. That hole
existed because the behavioural half of the test reproduced the guard's shape
inside the gate instead of reading the component, which is the self-consistent
oracle this repo's other geometry gate explicitly warns against.

Registered in scripts and gates:pre, verified by re-parsing: one key, 107
checks. Bundle rebuilt (BUNDLE=country-map), then tree, then fix:sri.
2026-09-29 19:11:37 +00:00
Doxa Maps
b33d970cd4 The gallery's tab keys live in mapInfo only, so the gallery bundles that one area
A key in a map's own area either renders blank in the gallery or, named literally, pulls that map's
whole catalogue into the gallery bundle (internal/i18n-areas.mjs). Measured with areasForBundle:
development's doxa-maps-spa carries buttons, grid, messages; this branch carries buttons, grid,
mapInfo, messages, and no upgMap. The UPG-100 entry reads mapInfo.tab.upg-100.lead and .takeaway,
which upg100 adds with every tab's strings.
2026-09-29 19:05:52 +00:00
Doxa Maps
32cf3f2354 Merge remote-tracking branch 'origin/development' into exp-shepherd/simple-map-embed 2026-09-29 19:02:39 +00:00
Doxa Maps
462c0babf7 Each gallery tab can explain itself: the MapInfo button, per tab, from src/tabInfo.js
The library MapInfo (an info button, a one-time pointer and a popup of real, pre-generated output)
is mounted in each pane whose tab has an entry in src/tabInfo.js, with the gallery's live locale and
its assets base. UPG-100 is the first entry, with its poster; its packet pages and card deck join
when their files are in the tree, because a missing file would show "not available" to the audience.
Regions and the other tabs follow as their owners' keys land. profile-config info:false removes the
buttons.
2026-09-29 19:00:06 +00:00
Doxa Maps
76f35d8ccd Merge origin/development into studio/deep-research 2026-09-29 18:57:33 +00:00
Doxa Maps
a85afc8b71 Prayer Progress: a multi-tab bar is a tablist, and says which tab is selected
The research page now gives this map three tabs (engagement, prayer,
adoption). With two or more tabs the bar was a row of plain buttons: a screen
reader heard three buttons, with nothing saying they are tabs or which one is
showing. The bar is now role=tablist, each button is role=tab with
aria-selected, and the buttons are type=button. A one-tab instance shows no
bar, so it is unchanged.
2026-09-29 18:56:53 +00:00
Doxa Maps
a2809b31fc Merge origin/development into studio/hygiene 2026-09-29 18:52:35 +00:00
Doxa Maps
f054b487cf A live language switch remounts the gallery's tab, instead of re-setting its attribute
The gallery re-drove the visible tab by re-setting its profile-config, which works only for a map
that re-reads its whole config live. Two production maps do not: Big Picture resolves its tStatic
strings once (2 of 352 changed on en to ar, measured) and Simple Research copies its config into its
panes once (0 of 43, 0 of 105). A fresh element reads the new locale at mount, so the visible tab is
now rebuilt in the new language whatever the map does inside, the way a provider change rebuilds.
View state is lost on a language switch; that is accepted.

Hidden tabs that are still mounted (a light tab stays mounted when hidden, and select() never
remounts a mounted tab) are reset too, so their next open mounts in the new language. The old comment
said they picked it up lazily; for light tabs they did not. Tabs are reset in place, keeping the slot
ref, because a light pane renders once and releaseTab's deleted ref would never come back.
2026-09-29 18:50:13 +00:00
Doxa Maps
9c6347aad6 Mark resources-map production, because a production page already ships it
resources-map.meta.json carried NO stage, so the manifest defaulted it to
experimental — while doxa-maps-spa, the gallery that becomes Deep Research,
mounts it: doxa-maps-spa.meta.json composes "gospel-resources/resources-map"
and TAB_DEFS names it as the Gospel Resources tab. The record disagreed with
what ships, and the record was the part that was wrong.

WHAT THIS CHANGES: the manifest stage, and nothing a reader sees. Verified —
the diff moves one "experimental" to one "production" and ZERO sha384 hashes.
No bundle is rebuilt and no byte of any map changes.

The stricter production gates now apply to this profile and it passes them:
gates:pre 103 PASS / 0 FAIL / 1 NOT MEASURED of 104. That is the part worth
having, because marking something production is only honest if it then has to
meet the production bar.

NOT a decision about which profile the Deep Research page SHOULD show.
gospel-dashboard is the production composite and remains the better end state;
it is not switched to today because its .gd-map is sized 80svh — a viewport
unit inside a pane that is not the viewport — which against rega's measured
panes gives the map 91% of the pane at 1440x900 and 95% at 390x844, and
because it has never been shot inside the gallery. That fix is written and
held local for after the deadline.
2026-09-29 18:42:06 +00:00
Doxa Maps
7d816f5eab Four more gates:post reds, hidden until a failed gate printed why
- research-map.vue's openPacket read and wrote _packetBusy, a name 8ab3dc0f5 replaced with the
  reactive packetBusy ref. Reading an undeclared name throws, so the packet export threw a
  ReferenceError on every click, in doxa-research-map and in research-map-plus-grid, the production
  map that compiles it. It uses packetBusy.value now (check:no-free-identifiers).
- check:list-prop-unit and check:optional-t-equivalence read every entry of library/i18n/locales as
  a locale, and the folder has held a README.md since bba33e783. They read locale FOLDERS now.
- people-groups-grid's regions-look instance previewed two props (filters-toggle, backdrop) of a grid
  merge that is not on development, so the page showed nothing different and
  check:instance-config-keys failed. It returns with that merge.
2026-09-29 18:40:27 +00:00
Doxa Maps
b435a7a548 The gallery is Deep Research, and a host can hide its Experimental folder
DX Life publishes the gallery shell on a hidden page named Deep Research, so that is now the
default heading (profile-config.heading or the heading prop still override it), and the meta,
instance and demo page say the same.

profile-config experimental:false (or "hidden") hides the Experimental folder: the manifest is not
mined for experimental tabs, the folder has no rows, and a tab= request for one falls back to the
first visible tab. It is off only on request, so every other host keeps the folder as before.
2026-09-29 18:37:12 +00:00
Doxa Maps
99816626af Every shadow stylesheet gets its own label, and a gate keeps it that way
useShadowStyles keys its <style> by the label and overwrites an existing
tag with the same key, so two components sharing a label keep only the
last one's CSS in a shared shadow root. The regions list lost its sheet
this way to the region card, which had kept the list's label when it was
extracted.

check:shadow-style-labels-unique (gates:pre) fails any label two calls
share, globally rather than per shadow root, so a copied or forked
component is caught when it is copied. It reads the real parsers,
classifies every reference to the function (a rebinding, .call, a
re-export or a namespace import fails instead of hiding a call),
cross-checks the AST against the token stream, and covers the other
ways two calls share a key: unlabelled calls under the dev server's
per-component key, and a fixed label over CSS that varies per caller.

countries-map.vue, a fork of research-map.vue, carried the same label;
it is now 'countries-map', with the country-posters bundle rebuilt and
the tree regenerated. The composable's JSDoc called the label a
debugging name; it now says it is the key.
2026-09-29 17:42:44 +00:00
Doxa Maps
6493872170 Track every pane's getter, prune detached ones, and say when one throws
Studio's 5B review found a dependency-tracking hole by testing the helper with
real Vue rather than reading it. entries was a plain array, so the watchEffect
tracked only what the FIRST registered getter read: with two panes reading
different refs, changing pane 2's source produced ZERO writes, and pane 2 caught
up only when pane 1's source happened to change. That is this helper's own bug
reappearing for any adopter whose panes read different sources. regions-mfe is
safe today because every getter reads the same cfg and spec -- which is exactly
why a reading could not find it.

entries is now shallowReactive, so register() re-runs the effect and every
getter is tracked. Also from the review:
  - stale entries are PRUNED, not skipped: an adopter that rebuilds its pane
    column would otherwise keep detached elements and re-run their getters on
    every pass forever;
  - a getter that throws is reported once per entry instead of being swallowed,
    since silence recreates the symptom this helper exists to fix;
  - the unused `tag` parameter is gone -- a documented check that does not exist
    misleads the next adopter;
  - the host argument now documents that it must be in the SAME tree as the
    panes, because Element.contains() does not cross a shadow boundary and
    passing the custom element would silently skip every write.

regions-dashboard rebuilt so public/ is servable at this sha for the browser
A/B. It is the only bundle that compiles the helper.
2026-09-29 17:32:33 +00:00
Doxa Maps
89bf1feb54 A composite's panes follow the outer profile-config, instead of freezing at mount
regions-mfe built each pane by creating the child element and writing its
profile-config once, inside onMounted, and nothing rewrote it. The pane is handed
a JSON STRING rather than a reactive object, so a later change to the OUTER
element's profile-config updated the composite's own cfg and reached nothing
below it. regions-dashboard is kept alive by v-show rather than remounted, so the
one code path that would have rewritten the attribute never runs again and the
panes stay in the old language for the whole session.

The leaf was never at fault: ProfileLoader's config is a computed over its prop,
lang is a computed over config, and a watchEffect drives appI18n on every change.
Every link is reactive -- it simply never receives a new prop.

library/composables/usePaneConfig.js owns the missing half: a composite registers
each pane element with a getter for its config, and a watchEffect re-forwards
whenever any reactive source that getter reads changes. It writes only when the
serialised config actually differs, because setting profile-config re-parses it
in the child and can remount what it drives -- an unconditional write per tick
would be a rerender loop. Stale elements (a rebuilt pane column) are skipped.

It is a library helper rather than three copies because regions-mfe, upg-100-mfe
and country-posters-mfe all assemble a config and set the attribute once; they
differ only in which keys they inherit, so each keeps its own
INHERITED_PAGE_KEYS and hands the result to the helper. This commit adopts it in
regions-mfe only; the other two are upg100's to adopt.

Two-sided, headlessly: a check that fails when a composite writes profile-config
on a child without re-forwarding names all THREE composites on development, and
on this branch regions-dashboard reports "re-forwarding=usePaneConfig" while the
other two still fail.

NOT VERIFIED IN A BROWSER YET. rega's LIVEDIAG is the falsifier: the nested
[profile-config] should show the OLD locale on development and the NEW one here.
2026-09-29 17:27:25 +00:00
Doxa Maps
57671ca465 Merge remote-tracking branch 'origin/development' into regions/handoff-integration
# Conflicts:
#	public/dx-maps/cities-internet/cities-internet.js
#	public/dx-maps/cities-internet/connectivity-list/index.html
#	public/dx-maps/cities-internet/connectivity-map/index.html
#	public/dx-maps/cities-internet/data-tables/index.html
#	public/dx-maps/country-map/country-map.js
#	public/dx-maps/country-map/country-map/index.html
#	public/dx-maps/country-posters/countries-map/index.html
#	public/dx-maps/country-posters/country-poster-wall/index.html
#	public/dx-maps/country-posters/country-posters-mfe/index.html
#	public/dx-maps/country-posters/country-posters.js
#	public/dx-maps/demo-map/demo-map.js
#	public/dx-maps/demo-map/demo-map/index.html
#	public/dx-maps/demo-map/demo-map/maplibre/index.html
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/doxa-research-map/doxa-research-map.js
#	public/dx-maps/doxa-research-map/research-map/index.html
#	public/dx-maps/doxa-research-map/research-map/maplibre/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map.js
#	public/dx-maps/doxa-simple-map/doxa-simple-map/adoption/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map/engagement/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map/prayer/index.html
#	public/dx-maps/gospel-internet/board/board/index.html
#	public/dx-maps/gospel-internet/board/index.html
#	public/dx-maps/gospel-internet/board/india-china/index.html
#	public/dx-maps/gospel-internet/board/language-tree/index.html
#	public/dx-maps/gospel-internet/board/platforms/index.html
#	public/dx-maps/gospel-internet/board/project-700/index.html
#	public/dx-maps/gospel-internet/board/zero/index.html
#	public/dx-maps/gospel-internet/gospel-internet.js
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-dashboard.js
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 16:33:55 +00:00
Doxa Maps
e21c4a5d57 Merge remote-tracking branch 'origin/development' into regions/handoff-integration
# Conflicts:
#	public/dx-maps/country-posters/countries-map/index.html
#	public/dx-maps/country-posters/country-poster-wall/index.html
#	public/dx-maps/country-posters/country-posters-mfe/index.html
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 16:12:45 +00:00
Doxa Maps
a6279064c4 Drop the country-map poster wall: +292 KB on every country page
country-map.vue's poster-wall wiring put the poster table, peopleGroupRecords
and the sheet code into the bundle of EVERY DX Life country page, for a wall
that is hidden by default. Measured: country-map.js 391,475 bytes on
development against 683,401 here -- +291,926, a 74% increase -- and with it
removed the bundle is 391,625, back within 150 bytes of development.

Making the three imports lazy does not help, and I measured that rather than
assuming it: with all three behind await import() and the table fetched at
mount, the bundle grew to 684,700. vite.config.js:282 sets
inlineDynamicImports, so a dynamic import is flattened straight back in and only
the wrapper is added. Removing the weight needs the pinned-served-asset pattern
that poster-render.js already uses -- card
PERF-LOAD-THE-PRINTING-SUBSYSTEM-ON-DEMAND.

library/packet/countrySheet.js stays: it is unreached at runtime (0 hits in the
built bundle) so it adds nothing, and it is the library half this element will
use once the printing code loads on demand.

ProfileLoader's comment now names both populations -- 20 of the 25 bundles are
single-profile, 10 of the 17 that actually mount this loader, which are the only
ones the default affects.
2026-09-29 16:10:00 +00:00
Doxa Maps
45d931fa40 Repair what the union resolution duplicated
Resolving package.json conflicts by unioning unique lines is right for a file
that holds one entry per line. Applied to ordinary source it duplicates
declarations, because both sides of a hunk keep their copy and nothing
de-duplicates across the join.

Eleven plugin entry points ended with the same import twice, and the poster
renderer with two identical `const sheet`. Each is a SyntaxError: every one of
those bundles would have failed to build, and the poster export would not run.

Found by parse-checking every changed .js against the merge base, not by the
gates -- gates:pre passed 101 of 102 with all twelve files broken, because its
parse gates do not cover plugin entry points.

One measurement trap worth recording. `node --check` on a .js file parses it as
CommonJS, so a bare `import` is a syntax error and ALL 28 entry points appear
broken, on development too. That reading says the tree is on fire and is simply
wrong. Copying each file to a .mjs and checking that parses it as a module,
which separates the eleven that are genuinely broken here from the rest that
are fine.
2026-09-29 16:01:45 +00:00
Doxa Maps
0417e46fbd Merge remote-tracking branch 'origin/development' into bundler-2/handoff
# Conflicts:
#	internal/check-poster-layout.mjs
#	library/composables/poster/useMapPoster.js
#	package.json
2026-09-29 16:00:18 +00:00
Doxa Maps
212ec20816 Merge remote-tracking branch 'origin/development' into bundler-2/handoff
# Conflicts:
#	package.json
2026-09-29 15:54:16 +00:00
Doxa Maps
14096e19c2 Merge remote-tracking branch 'origin/development' into upg100/merge
# Conflicts:
#	package.json
2026-09-29 15:54:05 +00:00
Doxa Maps
d3ec784c1e Merge remote-tracking branch 'origin/development' into regions/handoff-integration 2026-09-29 15:31:29 +00:00
Doxa Maps
e5b3334ea6 Merge remote-tracking branch 'origin/development' into upg100/merge 2026-09-29 15:21:38 +00:00
Doxa Maps
d5549cf58f Merge development into the gospel handoff branch 2026-09-29 15:19:40 +00:00
Doxa Maps
726f979079 Merge remote-tracking branch 'origin/development' into regions/handoff-integration 2026-09-29 15:01:53 +00:00
Doxa Maps
5539710503 Merge remote-tracking branch 'origin/development' into bundler-2/handoff 2026-09-29 15:01:31 +00:00
Doxa Maps
a8bbc6131e Keep the reason, drop the speaker, in three merged-in comments
The handoff merges brought in three references that name the Driver in shipped
text: two comments in CenteredSetTarget.vue and one _why in the people-groups-grid
instances. Reworded to state the engineering reason without the speaker -- an
open decision now reads as pending a product decision, which is what the rule
asks for. The instances file still parses as JSON.
2026-09-29 14:59:23 +00:00
Doxa Maps
cfd03d0250 PATTERN-A-LIST-OF-ZONES keeps the rule and drops the speaker
Three lines brought in with the list-pattern doc cited the Driver; the
reference gate refuses them. The rule, the scope and the open exception
stay as stated, without the attribution.
2026-09-29 14:54:47 +00:00
Doxa Maps
4dd858fb9a Merge upg100/list-pattern into development (handoff)
# Conflicts:
#	internal/check-ported-globals-identical.mjs
#	internal/fixtures/ported-globals-baseline.json
2026-09-29 14:54:21 +00:00
Doxa Maps
cbdf5546c4 Keep the reason, drop the speaker, in two comments the merge restored
Merging gospel/a5-cpu and gospel/panel-followup brought back two comments that
quote the Driver directly, and check:no-new-driver-references failed on them —
correctly. Development had already swept these; the merge reintroduced them from
an older base.

Both keep their reasoning and lose the attribution: a recording pill that
changes width on every word reads as instability, and on a phone the header can
take most of the panel, leaving the draft unscrollable and its last lines
unreachable. Those are the facts the rules encode; who said them is not.
2026-09-29 14:54:15 +00:00
Doxa Maps
7869f28ebc Merge branch 'regions/grid-merge' into regions/handoff-integration
# Conflicts:
#	package.json
#	plugin-designs/people-groups-grid/people-groups-grid.vue
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/people-groups-grid/people-groups-grid.js
#	public/dx-maps/people-groups-grid/people-groups-grid/driven/index.html
#	public/dx-maps/people-groups-grid/people-groups-grid/index.html
#	public/dx-maps/people-groups-grid/people-groups-grid/people-groups-grid/index.html
2026-09-29 14:53:55 +00:00
Doxa Maps
844fc60d0e Merge upg100/group-set-standard into development (handoff)
# Conflicts:
#	library/scripts/posters/packet.mjs
2026-09-29 14:53:36 +00:00
Doxa Maps
bf07e0eb61 Merge branch 'regions/country-map-posters' into regions/handoff-integration
# Conflicts:
#	plugin-designs/regions-dashboard/regions-list.vue
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-dashboard.js
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 14:53:10 +00:00
Doxa Maps
ed1aa635ce Merge development into the gospel handoff branch 2026-09-29 14:51:04 +00:00
Doxa Maps
bdb74ff69f Merge remote-tracking branch 'origin/development' into bundler-2/handoff 2026-09-29 14:50:51 +00:00
Doxa Maps
506b42fc31 Merge repo/readme-rudder-shot: the Driver's Rudder desktop screenshot in the README (HELD since 01:32Z for his cut-off condition "before you add it to the readme you nee"; merged on the merge-all order) 2026-09-29 14:50:44 +00:00
Doxa Maps
c9ffa34e93 Merge branch 'bundler-2/provide-warnings' into bundler-2/handoff
# Conflicts:
#	internal/check-element-bootstrap.mjs
#	internal/check-provide-shadowing.mjs
#	library/elements/defineMapElement.js
#	library/elements/provide-own.js
#	package.json
#	plugin-designs/all-people-groups/index.js
#	plugin-designs/cities-internet/index.js
#	plugin-designs/country-posters/index.js
#	plugin-designs/doxa-research-map/index.js
#	plugin-designs/gospel-internet/index.js
#	plugin-designs/gospel-resources/index.js
#	plugin-designs/key-cities/index.js
#	plugin-designs/my-upg-100-list/index.js
#	plugin-designs/pplr-data-maps/index.js
#	plugin-designs/regions-dashboard/index.js
#	plugin-designs/upg-neighbor/index.js
2026-09-29 14:50:37 +00:00
Doxa Maps
59345a0aaa Merge gospel/board768 for the handoff (superseded; development's side kept)
# Conflicts:
#	plugin-designs/gospel-internet/src/components/GiBoundedSetMap.vue
#	plugin-designs/gospel-internet/src/components/GiCenteredSetMap.vue
#	plugin-designs/gospel-internet/src/setChartFeatures.js
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/gospel-internet/board/board/index.html
#	public/dx-maps/gospel-internet/board/index.html
#	public/dx-maps/gospel-internet/board/india-china/index.html
#	public/dx-maps/gospel-internet/board/language-tree/index.html
#	public/dx-maps/gospel-internet/board/platforms/index.html
#	public/dx-maps/gospel-internet/board/project-700/index.html
#	public/dx-maps/gospel-internet/board/zero/index.html
#	public/dx-maps/gospel-internet/gospel-internet.js
#	public/dx-maps/manifest.json
2026-09-29 14:50:21 +00:00