Say what a dot means, and that it is not what the country means

The pins landed with no key, so the map shipped two colour systems using the SAME
four hexes for two different claims and nothing telling them apart. A country is an
AVERAGE across its groups; a dot is one group's own language. Red-on-green is the
most interesting case on the map — a group with nothing found inside a well-supplied
country — and with no key it reads as a rendering fault instead of a finding.

The key says so in those words, and the SHAPE now carries the level: squares for the
country average, circles for a single group. Shape is the honest separator here,
because the hexes are deliberately shared — a dot and its country agreeing on what
"nothing found" looks like is the property worth keeping.

Counts are computed from the layer rather than written down: 12,379 dots, 5,109 with
a link. A number typed into a legend rots the first time the data moves.

Verified at 1280x800 on the served tree: the legend renders both key blocks, quotes
12,379/5,109 matching the generator's own tally, and the pin probe still passes
12,379 rendered with both Han Chinese links answering 200.
This commit is contained in:
doxa-maps-88655c70 2026-09-24 03:05:22 +00:00
parent b05d1f13b4
commit 0ebde03046
8 changed files with 56 additions and 30 deletions

View file

@ -145,6 +145,13 @@ const pinRows = shallowRef([]) // [name, lat, lng, iso3, code, population, ti
const pinCodes = ref({}) // ISO 639-3 -> { l, s, f, a, o, ck, un }
const pinCount = ref(0)
// The legend quotes these, so they can never drift from what the layer is drawing.
const pinTally = computed(() => {
const t = [0, 0, 0]
for (const r of pinRows.value) t[r[6]]++
return { none: t[0], partial: t[1], both: t[2], linked: t[1] + t[2], total: pinRows.value.length }
})
async function ensurePeopleGroups() {
if (pgRows.value || pgLoading.value) return
pgLoading.value = true; pgErr.value = null
@ -454,6 +461,11 @@ useShadowStyles(
'.gm-keys{display:flex;flex-wrap:wrap;gap:5px 12px}' +
'.gm-key{display:flex;align-items:center;gap:5px;font-size:11px;white-space:nowrap}' +
'.gm-sw{width:12px;height:12px;border-radius:3px;flex:none}' +
'.gm-dot{width:10px;height:10px;border-radius:50%;flex:none;display:inline-block;' +
'border:1.4px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.18);vertical-align:-1px}' +
'.gm-pinkey{margin-top:7px;padding-top:6px;border-top:1px solid rgba(0,0,0,.12)}' +
'.is-dark .gm-pinkey{border-top-color:rgba(255,255,255,.16)}' +
'.gm-pinkey-h{font-size:11px;font-weight:600;margin-bottom:4px}' +
'.gm-caveat{margin-top:5px;font-size:10.5px;opacity:.72;line-height:1.4}' +
// DETAIL: a bottom sheet on a phone, a corner card on desktop.
'.gm-sheet{position:absolute;left:0;right:0;bottom:0;z-index:6;max-height:62%;overflow-y:auto;' +
@ -552,8 +564,22 @@ useShadowStyles(
<i class="gm-sw" :style="{ background: b.color }"></i>{{ b.label }}
</span>
</div>
<div class="gm-pinkey" v-if="pinTally.total">
<div class="gm-pinkey-h">
Each <i class="gm-dot" style="background:#6d766e"></i> is ONE people group —
{{ fmt(pinTally.total) }} of them, {{ fmt(pinTally.linked) }} with a link
</div>
<div class="gm-keys">
<span class="gm-key"><i class="gm-dot" :style="{ background: PIN_COLOR[2] }"></i>Scripture <em>and</em> film</span>
<span class="gm-key"><i class="gm-dot" :style="{ background: PIN_COLOR[1] }"></i>one of the two</span>
<span class="gm-key"><i class="gm-dot" :style="{ background: PIN_COLOR[0] }"></i>nothing found</span>
</div>
</div>
<div class="gm-caveat">
“None found” = not in the pools checked (eBible + JESUS Film). GRN audio is unchecked — never proof of absence.
<b>A dot and the country under it mean different things.</b> The country is an AVERAGE
across its groups; a dot is that ONE group's own language. So a red dot can sit on a green
country — that is the case worth finding, not a rendering fault.
<br>“None found” = not in the pools checked (eBible + JESUS Film). GRN audio is unchecked — never proof of absence.
<template v-if="mode === 'coverage'">
A “found” colour is equally bounded: it counts what these pools list, not everything that exists.
</template>

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX" 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 <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX" 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

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX" 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

@ -556,7 +556,7 @@
"bundle": "gospel-resources",
"scriptUrl": "./gospel-resources/gospel-resources.js",
"output": "doxa-maps/gospel-resources/gospel-resources.js",
"integrity": "sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG",
"integrity": "sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX",
"elements": [
"gospel-resources-map"
],
@ -572,7 +572,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/charts/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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -586,7 +586,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/data-tables/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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -600,7 +600,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/resources-list/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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -614,7 +614,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/resources-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=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-Pswy8wR6+XZ+jY0S3rkbOGUWyI6uMwACcO+MGP4K/x3M3PYmzNi5RMvbLSVwAfaG\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-S/YNvW/k3D7VkioCifhTgEDsaZ+A71uChoL0qAKRIayEojIh389PztuWxTdibaEX\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
}
]