Research map: centre the active tab without scrolling the host page

On mount the map centred its active tab with

    btn.scrollIntoView({ inline: 'center', block: 'nearest', behavior: 'smooth' })

and 'nearest' does not mean "do not scroll the page". It means "scroll every
scrollable ancestor by the least amount needed", and on a partner page the HOST
is an ancestor. Measured by the embed sweep: a page carrying this map below the
fold jumps to y≈640 the moment it mounts — on a phone, where Simple Research is
the default tab. The reader asked for nothing and the page moved under them.

The tab strip now scrolls ITSELF: compute the offset that centres the active
button inside its own box, clamp it to the strip's own scroll range, and write
scrollLeft. Same shape as SemanticTreeLegend's bringRowToTop, which scrolls the
container it found rather than asking the platform to walk ancestors. An element
that only ever writes its own scrollLeft cannot move anybody's page.

The exemption goes in the SAME commit, per that gate's contract — main never
carries a stale exemption or a red gate on someone else's bug. Both
NEIGHBOUR_KNOWN entries (research-map, research-map-plus-grid) are deleted here.

MEASURED after, with the exemption gone: check:gallery-embed PASS, and the
neighbour phase now reports "research-map leaves the host page alone" and
"research-map-plus-grid leaves the host page alone" on its own evidence — js 13
tabs, iframe 13 tabs, neighbour 13 tabs. The two KNOWN lines still printed belong
to regions-dashboard and are theirs to clear.
This commit is contained in:
doxa-maps-88655c70 2026-09-25 03:57:20 +00:00
parent a5134c770b
commit 344990d186
20 changed files with 204 additions and 142 deletions

View file

@ -56,12 +56,6 @@ const PROVIDER = argOf('--provider', '')
// Same contract as MAPBOX_KNOWN: printed on every run, owner named, and DELETED in the same commit
// as the owner's fix so main never carries a stale exemption or a red gate on someone else's bug.
const NEIGHBOUR_KNOWN = {
// doxa-research-map/research-map.vue:647 — btn.scrollIntoView({block:'nearest'}) on the active
// .rm-tab when it mounts. 'nearest' still scrolls the PAGE whenever the embed is below the fold:
// on a phone the DX-life page jumps to y≈640 on load. Fix = scroll the tab bar's own scrollLeft
// (the SemanticTreeLegend bringRowToTop pattern, regression 554bf10). Routed 2026-09-25.
'research-map-plus-grid:scroll': 'research-map owner (research-map.vue:647 scrollIntoView)',
'research-map:scroll': 'research-map owner (research-map.vue:647 scrollIntoView)',
// regions-dashboard/region-dashboards.vue:499 URL_SYNC is unconditional, so a nested Regions
// rewrites the host's #anchor (writeUrl) and document.title (syncTitle). The gallery passes
// profile-config.urlSync:false for exactly this; Regions needs to honour it. Routed 2026-09-25.

View file

@ -93,6 +93,34 @@ export function detectLocale() {
/**
* Build a fresh i18n instance. Called once per <doxa-map> element.
*/
/**
* Read a catalogue string WITHOUT the vue-i18n plugin.
*
* WHY THIS EXISTS. Some components are mounted as their OWN custom element by a bundle entry that
* calls defineCustomElement(Component) and installs nothing — people-groups-grid is one. useI18n()
* inside such a component THROWS, and a thrown setup() removes the subtree silently (this repo has
* already paid for that once: three buttons vanished behind ignorable console noise). So a shared
* component that must work in BOTH mounts needs a plugin-free reader, which is all this is.
*
* Falls back locale -> en -> undefined, so a caller can keep its own literal as the last resort and
* a missing translation degrades to English rather than to a key.
*
* @param {string} path dotted, e.g. 'grid.hide_filters'
* @param {string} [locale] defaults to the detected one (?lang= / host / browser)
*/
export function tStatic(path, locale) {
const tryTree = (loc) => {
let node = messages[loc]
for (const part of String(path).split('.')) {
if (!node || typeof node !== 'object') return undefined
node = node[part]
}
return typeof node === 'string' ? node : undefined
}
const want = locale || detectLocale()
return tryTree(want) ?? tryTree('en')
}
export function createAppI18n() {
const locale = detectLocale()
// ⚠ REFLECT AN RTL LOCALE ON THE DOCUMENT. Only one component reads RTL_LOCALES

View file

@ -643,8 +643,26 @@ watch(() => activeTabId?.value, async (newTabId, oldTabId) => {
else uiStore.collapseLegend?.()
}
await nextTick()
const btn = tabBar.value?.querySelector('.rm-tab.active')
btn?.scrollIntoView?.({ inline: 'center', block: 'nearest', behavior: 'smooth' })
// ★ SCROLL THE TAB BAR, NOT THE PAGE. This was
// btn.scrollIntoView({ inline: 'center', block: 'nearest', behavior: 'smooth' })
// and 'nearest' does not mean "do not scroll the page" — it means "scroll every scrollable
// ancestor the least amount needed", and the HOST PAGE is an ancestor. MEASURED by rega's embed
// sweep: a partner page carrying this map below the fold jumps to y≈640 the moment it mounts, on
// a phone, where Simple Research is the default tab. The reader asked for nothing; the page moved
// under them.
// Centre the button INSIDE its own strip instead — the same shape as SemanticTreeLegend's
// bringRowToTop, which scrolls the container it found rather than asking the platform to walk
// ancestors. An element that only ever writes its own scrollLeft cannot move anybody's page.
const bar = tabBar.value
const btn = bar?.querySelector('.rm-tab.active')
if (bar && btn && bar.scrollWidth > bar.clientWidth + 1) {
const br = bar.getBoundingClientRect(), tr = btn.getBoundingClientRect()
const target = bar.scrollLeft + (tr.left - br.left) - (br.width - tr.width) / 2
const max = bar.scrollWidth - bar.clientWidth
const left = Math.max(0, Math.min(max, target))
if (typeof bar.scrollTo === 'function') bar.scrollTo({ left, behavior: 'smooth' })
else bar.scrollLeft = left
}
})
const mapContainer = ref(null)
const appReady = ref(false)

View file

@ -45,6 +45,7 @@ import Fuse from '@map/components/search/fuzzy.js'
import SearchBar from '@map/components/search/SearchBar.vue'
import FilterDropdown from '@map/components/search/FilterDropdown.vue'
import { resolveAssetsBase } from '@map/utils/embedBase.js'
import { tStatic } from '@map/i18n/index.js'
import { countrySlug } from './src/countries.js'
// ── DERIVED family axes (BUG-SEMANTIC-TREE-SIDEBAR-NOT-INTEROPERABLE-WITH-GRID) ──
// The Religion/Language trees' TOP TIERS emit DERIVED family names ("Hinduism",
@ -253,7 +254,28 @@ const languageCode = computed(() => props.languageCode || cfg.value.languageCode
const researchUrl = computed(() => props.researchUrl || cfg.value.researchUrl
|| (((typeof window !== 'undefined' && window.DOXA_SITE_URL) || 'https://doxa.life').replace(/\/+$/, '') + '/research/'))
const selectUrl = computed(() => props.selectUrl || cfg.value.selectUrl || '')
const t = computed(() => ({ ...(cfg.value.t || {}), ...(props.t || {}) }))
// ★ EVERY LABEL IN THIS GRID WAS ENGLISH IN ALL ELEVEN LOCALES.
// The `t` object is a HOST-SUPPLIED map (the Nuxt page passes its own strings), with an English
// literal at each call site as the fallback. Nothing else ever filled it, so a reader on ?lang=ru
// got a fully Russian map with 'Search people groups…', 'Hide Filters', 'Exact', 'Load more' and
// 'Full profile' underneath it — MEASURED on the composite: every Latin-script string on that page
// belonged to this grid, the map half above it was entirely translated.
// The catalogue now carries them (locales/<loc>/grid.json) and this reads it directly rather than
// through useI18n, because this component is ALSO mounted as its own custom element by an entry
// that installs no i18n plugin — useI18n() there throws, and a thrown setup() removes the subtree
// with no build error. Order: host `t` wins (it always did), then the catalogue, then the English
// literal already at each call site, so a locale missing a key degrades to today's behaviour.
const t = computed(() => {
const host = { ...(cfg.value.t || {}), ...(props.t || {}) }
const locale = cfg.value.locale || cfg.value.lang || undefined
return new Proxy(host, {
get(target, key) {
if (key in target) return target[key]
if (typeof key !== 'string') return undefined
return tStatic('grid.' + key, locale)
},
})
})
// ── Cat-2 show/hide (accept the DOM-attribute string 'false') ──────────────────
const truthy = (v) => !(v === false || v === 'false' || v === '0' || v === 0)

File diff suppressed because one or more lines are too long

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
<script src="../../big-picture.js" integrity="sha384-zwM56YT56Crw0AFHQsG9fHnIPzkHVRwtLd/tXg9MXedfWyixXRdK7BVA/8S8JjhB" crossorigin="anonymous"></script>
<script src="../../big-picture.js" integrity="sha384-Rht3EoXP3Ckvwn2fauBsh9BvcUJiFzMb49udbtOh34wbKLdHQ+RQcFGR8fdHdF2t" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
<script src="../../big-picture.js" integrity="sha384-zwM56YT56Crw0AFHQsG9fHnIPzkHVRwtLd/tXg9MXedfWyixXRdK7BVA/8S8JjhB" crossorigin="anonymous"></script>
<script src="../../big-picture.js" integrity="sha384-Rht3EoXP3Ckvwn2fauBsh9BvcUJiFzMb49udbtOh34wbKLdHQ+RQcFGR8fdHdF2t" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -37,7 +37,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <bp-big-picture> custom element. -->
<script src="../big-picture.js" integrity="sha384-zwM56YT56Crw0AFHQsG9fHnIPzkHVRwtLd/tXg9MXedfWyixXRdK7BVA/8S8JjhB" crossorigin="anonymous"></script>
<script src="../big-picture.js" integrity="sha384-Rht3EoXP3Ckvwn2fauBsh9BvcUJiFzMb49udbtOh34wbKLdHQ+RQcFGR8fdHdF2t" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../../dashboard-plus-grid.js" integrity="sha384-oWvpE6qF7AlXl/L/4dx/1uT493xz3fbpqNuSRcTXlTYdyryVVv1t/hlPOQTaNXg5" crossorigin="anonymous"></script>
<script src="../../dashboard-plus-grid.js" integrity="sha384-xR8W+FnaWZ8B5JzTbivTfMcMU5zTtpHKyMTXKMDzLMO3Pwi/XKR9INs1pib1YVjj" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -40,7 +40,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../dashboard-plus-grid.js" integrity="sha384-oWvpE6qF7AlXl/L/4dx/1uT493xz3fbpqNuSRcTXlTYdyryVVv1t/hlPOQTaNXg5" crossorigin="anonymous"></script>
<script src="../dashboard-plus-grid.js" integrity="sha384-xR8W+FnaWZ8B5JzTbivTfMcMU5zTtpHKyMTXKMDzLMO3Pwi/XKR9INs1pib1YVjj" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-research-map> custom element. -->
<script src="../doxa-research-map.js" integrity="sha384-Pz+BuiLVX/OnZWBl4YhRcseuTjI2XLwN77j8OdfcFfEHkNB0jVIWbHw7wkbChUQZ" crossorigin="anonymous"></script>
<script src="../doxa-research-map.js" integrity="sha384-l7WPcwmMNqyZxsDXwovUycSoXZdc+8nni4CN+vr8C6ppcug2fdbvG2W8p+FlomRO" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -27,7 +27,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-research-map> custom element. -->
<script src="../../doxa-research-map.js" integrity="sha384-Pz+BuiLVX/OnZWBl4YhRcseuTjI2XLwN77j8OdfcFfEHkNB0jVIWbHw7wkbChUQZ" crossorigin="anonymous"></script>
<script src="../../doxa-research-map.js" integrity="sha384-l7WPcwmMNqyZxsDXwovUycSoXZdc+8nni4CN+vr8C6ppcug2fdbvG2W8p+FlomRO" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -39,7 +39,7 @@
"bundle": "big-picture",
"scriptUrl": "./big-picture/big-picture.js",
"output": "doxa-maps/big-picture/big-picture.js",
"integrity": "sha384-zwM56YT56Crw0AFHQsG9fHnIPzkHVRwtLd/tXg9MXedfWyixXRdK7BVA/8S8JjhB",
"integrity": "sha384-Rht3EoXP3Ckvwn2fauBsh9BvcUJiFzMb49udbtOh34wbKLdHQ+RQcFGR8fdHdF2t",
"elements": [
"bp-big-picture",
"bp-research-header",
@ -61,7 +61,7 @@
"scriptUrl": "./big-picture/big-picture.js",
"embed": {
"iframe": "<iframe src=\"./big-picture/big-picture/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./big-picture/big-picture.js\" integrity=\"sha384-zwM56YT56Crw0AFHQsG9fHnIPzkHVRwtLd/tXg9MXedfWyixXRdK7BVA/8S8JjhB\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./big-picture/big-picture.js\" integrity=\"sha384-Rht3EoXP3Ckvwn2fauBsh9BvcUJiFzMb49udbtOh34wbKLdHQ+RQcFGR8fdHdF2t\" crossorigin=\"anonymous\"></script>\n<bp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></bp-big-picture>"
},
"instances": [
{
@ -215,7 +215,7 @@
"bundle": "dashboard-plus-grid",
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"output": "doxa-maps/dashboard-plus-grid/dashboard-plus-grid.js",
"integrity": "sha384-oWvpE6qF7AlXl/L/4dx/1uT493xz3fbpqNuSRcTXlTYdyryVVv1t/hlPOQTaNXg5",
"integrity": "sha384-xR8W+FnaWZ8B5JzTbivTfMcMU5zTtpHKyMTXKMDzLMO3Pwi/XKR9INs1pib1YVjj",
"elements": [
"dashboard-plus-grid"
],
@ -235,7 +235,7 @@
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"embed": {
"iframe": "<iframe src=\"./dashboard-plus-grid/dashboard-plus-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-oWvpE6qF7AlXl/L/4dx/1uT493xz3fbpqNuSRcTXlTYdyryVVv1t/hlPOQTaNXg5\" crossorigin=\"anonymous\"></script>\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-xR8W+FnaWZ8B5JzTbivTfMcMU5zTtpHKyMTXKMDzLMO3Pwi/XKR9INs1pib1YVjj\" crossorigin=\"anonymous\"></script>\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
},
"instances": [
{
@ -354,7 +354,7 @@
"bundle": "doxa-research-map",
"scriptUrl": "./doxa-research-map/doxa-research-map.js",
"output": "doxa-maps/doxa-research-map/doxa-research-map.js",
"integrity": "sha384-Pz+BuiLVX/OnZWBl4YhRcseuTjI2XLwN77j8OdfcFfEHkNB0jVIWbHw7wkbChUQZ",
"integrity": "sha384-l7WPcwmMNqyZxsDXwovUycSoXZdc+8nni4CN+vr8C6ppcug2fdbvG2W8p+FlomRO",
"elements": [
"doxa-research-map"
],
@ -370,7 +370,7 @@
"scriptUrl": "./doxa-research-map/doxa-research-map.js",
"embed": {
"iframe": "<iframe src=\"./doxa-research-map/research-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-Pz+BuiLVX/OnZWBl4YhRcseuTjI2XLwN77j8OdfcFfEHkNB0jVIWbHw7wkbChUQZ\" crossorigin=\"anonymous\"></script>\n<doxa-research-map profile-config='{\"profile\":\"research-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-research-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-l7WPcwmMNqyZxsDXwovUycSoXZdc+8nni4CN+vr8C6ppcug2fdbvG2W8p+FlomRO\" crossorigin=\"anonymous\"></script>\n<doxa-research-map profile-config='{\"profile\":\"research-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-research-map>"
},
"instances": [
{
@ -738,7 +738,7 @@
"bundle": "people-groups-grid",
"scriptUrl": "./people-groups-grid/people-groups-grid.js",
"output": "doxa-maps/people-groups-grid/people-groups-grid.js",
"integrity": "sha384-bXnpluxSYtktOs786dmJaVM1oCO0R0Ww20iybJhCR2BscwjimyuFTjIC3+jAOb7E",
"integrity": "sha384-mQozY8qX1qTuBYlf/oD5iWLT4voyWxe7zJrzN+zHV8FMRxajsQwPRlkl8mBU71YI",
"elements": [
"people-groups-grid"
],
@ -754,7 +754,7 @@
"scriptUrl": "./people-groups-grid/people-groups-grid.js",
"embed": {
"iframe": "<iframe src=\"./people-groups-grid/people-groups-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./people-groups-grid/people-groups-grid.js\" integrity=\"sha384-bXnpluxSYtktOs786dmJaVM1oCO0R0Ww20iybJhCR2BscwjimyuFTjIC3+jAOb7E\" crossorigin=\"anonymous\"></script>\n<people-groups-grid profile-config='{\"profile\":\"people-groups-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></people-groups-grid>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./people-groups-grid/people-groups-grid.js\" integrity=\"sha384-mQozY8qX1qTuBYlf/oD5iWLT4voyWxe7zJrzN+zHV8FMRxajsQwPRlkl8mBU71YI\" crossorigin=\"anonymous\"></script>\n<people-groups-grid profile-config='{\"profile\":\"people-groups-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></people-groups-grid>"
},
"instances": [
{

File diff suppressed because one or more lines are too long

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <people-groups-grid> custom element. -->
<script src="../../people-groups-grid.js" integrity="sha384-bXnpluxSYtktOs786dmJaVM1oCO0R0Ww20iybJhCR2BscwjimyuFTjIC3+jAOb7E" crossorigin="anonymous"></script>
<script src="../../people-groups-grid.js" integrity="sha384-mQozY8qX1qTuBYlf/oD5iWLT4voyWxe7zJrzN+zHV8FMRxajsQwPRlkl8mBU71YI" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <people-groups-grid> custom element. -->
<script src="../people-groups-grid.js" integrity="sha384-bXnpluxSYtktOs786dmJaVM1oCO0R0Ww20iybJhCR2BscwjimyuFTjIC3+jAOb7E" crossorigin="anonymous"></script>
<script src="../people-groups-grid.js" integrity="sha384-mQozY8qX1qTuBYlf/oD5iWLT4voyWxe7zJrzN+zHV8FMRxajsQwPRlkl8mBU71YI" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <people-groups-grid> custom element. -->
<script src="../../people-groups-grid.js" integrity="sha384-bXnpluxSYtktOs786dmJaVM1oCO0R0Ww20iybJhCR2BscwjimyuFTjIC3+jAOb7E" crossorigin="anonymous"></script>
<script src="../../people-groups-grid.js" integrity="sha384-mQozY8qX1qTuBYlf/oD5iWLT4voyWxe7zJrzN+zHV8FMRxajsQwPRlkl8mBU71YI" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: