diff --git a/plugin-designs/country-posters/countries-map.vue b/plugin-designs/country-posters/countries-map.vue index 4ffcd9574..dc0095387 100644 --- a/plugin-designs/country-posters/countries-map.vue +++ b/plugin-designs/country-posters/countries-map.vue @@ -369,7 +369,7 @@ const profileConfig = inject('profileConfig') // ── SEARCH BAR IS MAPBOX-ONLY, AND ITS ABSENCE MUST NOT LEAVE A HOLE ───────── // Same contract as doxa-research-map (the reference implementation), deliberately copied rather -// than re-invented. Driver 2026-09-24: the geocoder is DEFERRED to Mapbox, because +// than re-invented. Decided 2026-09-24: the geocoder is DEFERRED to Mapbox, because // GeocoderComponent's maplibre path still calls makeMapboxForwardGeocode(accessToken) — the search // REQUEST goes to Mapbox whichever engine draws the tiles, so a keyless map with a search bar is // not keyless and would bill the very key the maplibre option exists to avoid. @@ -382,7 +382,7 @@ const hasGeocoder = computed(() => { }) // SemanticTreeLegend's --stl-top defaults to 60px, and that 60px exists ONLY to reserve room for a // search bar above it. With no bar the legend must RISE into the vacated space instead of leaving a -// dead band — the Driver's explicit requirement. 14px matches the reference. +// dead band — a requirement, not a preference. 14px matches the reference. // How far the legend may rise depends on WHAT ELSE is in the strip the search bar vacated. // LegendTools sits at top:14px on the tabs its predicate allows, so raising the legend to 14 there // prints the toolbar across the legend's header — MEASURED on country-posters. Ask the toolbar's own @@ -1236,8 +1236,8 @@ async function openPacket(variant = 'full') { if (_packetBusy) return _packetBusy = true try { - // ★ THE PACKET PRINTS, AND IT PRINTS THROUGH THE SHARED RENDERER (Driver-lens audit card 2, and - // the Driver's own rule: an export button opens the print dialog, never hands over a file). This + // ★ THE PACKET PRINTS, AND IT PRINTS THROUGH THE SHARED RENDERER (product-lens audit card 2, and + // the product rule: an export button opens the print dialog, never hands over a file). This // built a jsPDF document and downloaded packet.pdf while its poster sibling, two functions up, // already printed. The fix is NOT to wrap that PDF in a dialog — a PDF blob cannot go in the // the in-place print frame uses, and every workaround (embed, object, the browser's own diff --git a/plugin-designs/country-posters/country-posters-mfe.meta.json b/plugin-designs/country-posters/country-posters-mfe.meta.json index 54f667b46..e58a8812b 100644 --- a/plugin-designs/country-posters/country-posters-mfe.meta.json +++ b/plugin-designs/country-posters/country-posters-mfe.meta.json @@ -5,7 +5,7 @@ "country-posters/country-poster-wall", "country-posters/countries-map" ], - "note": "The Driver's 2-tab Country Posters element, structured like my-upg-100-list/upg-100-mfe: a SELECT VIEW switcher (the SHARED library/components/ViewSelect.vue — this is its THIRD consumer, which is why it was extracted rather than copied a third time) over Country Posters at [0,0] and Map at [1,0]. LIST FIRST, MAP SECOND per the Driver's principle that maps are a secondary view. The wall already dispatches 'doxa-country-posters:show-on-map' (country-poster-wall.vue:78); until now only the app shell listened, so the action did nothing in a dropped embed — this shell owns it and swaps to the map tab. pinHint:false: the cloned panes carry no coach-mark, and the composite must declare it because a pane's config comes from here, not from the child's own meta. One ShareButton in the header, sharing the COMPOSITE leaf, per the recorded share policy.", + "note": "The 2-tab Country Posters element, structured like my-upg-100-list/upg-100-mfe: a SELECT VIEW switcher (the SHARED library/components/ViewSelect.vue — this is its THIRD consumer, which is why it was extracted rather than copied a third time) over Country Posters at [0,0] and Map at [1,0]. LIST FIRST, MAP SECOND, on the principle that maps are a secondary view. The wall already dispatches 'doxa-country-posters:show-on-map' (country-poster-wall.vue:78); until now only the app shell listened, so the action did nothing in a dropped embed — this shell owns it and swaps to the map tab. pinHint:false: the cloned panes carry no coach-mark, and the composite must declare it because a pane's config comes from here, not from the child's own meta. One ShareButton in the header, sharing the COMPOSITE leaf, per the recorded share policy.", "config": { "pinHint": false } diff --git a/plugin-designs/country-posters/country-posters-mfe.vue b/plugin-designs/country-posters/country-posters-mfe.vue index 5b5be8bdc..92dc88aab 100644 --- a/plugin-designs/country-posters/country-posters-mfe.vue +++ b/plugin-designs/country-posters/country-posters-mfe.vue @@ -7,8 +7,8 @@ * poster wall behind a single view switcher, structured like the UPG-100 list. The switcher is * the library's shared ViewSelect, not a third hand-rolled copy. * - * Driver: "Country Posters is supposed to have two tabs, structured like the - * UPG-100 list." + * Country Posters has two tabs, structured like the + * UPG-100 list. * * ★ THE CONTROL IS SHARED, NOT COPIED. That is the whole point of the card: this * is the THIRD place the SELECT VIEW switcher is needed, and it uses the library's @@ -25,9 +25,9 @@ * • one ShareButton in the header, per the recorded share policy * (check:share-policy) — the MAP pane must not grow a second one * - * LIST FIRST, MAP SECOND. The Driver's principle, already applied in upg-100-mfe: - * "maps don't have to be primary. You can use lists and grids for the primary view - * and maps as a secondary view… then they transition into the map." The poster wall + * LIST FIRST, MAP SECOND. The principle already applied in upg-100-mfe: a map need + * not be the primary view — a list or a grid can be, with the map secondary and + * reached as a transition from it. The poster wall * is the concrete artefact a newcomer can act on; the map is where it is placed. */ import { ref, computed, inject, onMounted, onBeforeUnmount } from 'vue' @@ -239,7 +239,7 @@ useShadowStyles(PANE_GRID_STYLES + ` no such rule exists and every pane collapses to 0 — the "elements are not embedding" report. Declaring :host makes the element fill its slot in every deploy method. */ :host{ display:block; width:100%; height:100%; min-height:420px; } -/* ── palette: DX-life material light. NO AUTO-DARK (Driver 2026-09-20): a system set to +/* ── palette: DX-life material light. NO AUTO-DARK (decided 2026-09-20): a system set to dark mode must not flip this element. ── */ .cpmfe{ --ui-bg:#ffffff; --ui-bg-elevated:#f3f3f1; --ui-bg-accented:#f3f3f1; diff --git a/plugin-designs/my-upg-100-list/data/legend-tree.js b/plugin-designs/my-upg-100-list/data/legend-tree.js index dd07bdf33..5bb634378 100644 --- a/plugin-designs/my-upg-100-list/data/legend-tree.js +++ b/plugin-designs/my-upg-100-list/data/legend-tree.js @@ -109,7 +109,7 @@ export const REGION_KEY = { export function buildLegendNodes(clusters, opts = {}) { const deafCount = opts.deafCount ?? 123; const records = Array.isArray(opts.records) ? opts.records : null; - // ★ OPTIONAL GENERATED TITLE (Driver, 2026-09-27). `opts.title(zone)` returns a localized title + // ★ OPTIONAL GENERATED TITLE (2026-09-27). `opts.title(zone)` returns a localized title // composed from already-translated parts, or NULL for a zone whose title cannot be generated — see // data/zone-title.js. Passing nothing keeps every hand-written English label exactly as it was, which // is why this is an option rather than a rewrite: the legend, the poster and the packet adopt it diff --git a/plugin-designs/my-upg-100-list/data/zones-for-list.js b/plugin-designs/my-upg-100-list/data/zones-for-list.js index a0e8d4b44..cacb420b1 100644 --- a/plugin-designs/my-upg-100-list/data/zones-for-list.js +++ b/plugin-designs/my-upg-100-list/data/zones-for-list.js @@ -30,7 +30,7 @@ * Then `npm run check:zoning-declared -- --list ` grades the zoning, and the legend, poster wall and * packet all follow, because all three already enumerate through leafZones(buildLegendNodes(zones)). * - * ZONING RULE, from the Driver (2026-09-27), recorded here because it is the judgement the format cannot + * ZONING RULE (2026-09-27), recorded here because it is the judgement the format cannot * capture: cluster by GEOGRAPHY FIRST so the poster maps make sense, balanced with LANGUAGE — languages * usually cluster geographically, so the two mostly agree, and where they disagree geography wins for a * map's sake. UPG-100's own 28 already mix the two: the country_codes zones are geographic, and the 12 @@ -38,8 +38,8 @@ * * ⚠ THE DEAF ZONE IS THE KNOWN EXCEPTION AND MUST NOT BE FORCED. `deaf` is affinity bloc A017: 123 groups * spanning every region, global by construction, and the one poster whose zone cannot be a map extent. It - * breaks the geography-first rule the rest of the pattern rests on, and the Driver has said he has not - * solved it. A list whose clusters include an affinity or language bloc inherits the same open question — + * breaks the geography-first rule the rest of the pattern rests on, and it is recorded as not yet + * solved. A list whose clusters include an affinity or language bloc inherits the same open question — * declare it in bloc_zones so the gate treats it as a second partition, and do NOT invent a geography for * it to make a validator happy. * diff --git a/plugin-designs/my-upg-100-list/poster-wall.vue b/plugin-designs/my-upg-100-list/poster-wall.vue index 328b2b687..fcc024118 100644 --- a/plugin-designs/my-upg-100-list/poster-wall.vue +++ b/plugin-designs/my-upg-100-list/poster-wall.vue @@ -24,10 +24,10 @@ * cardStocks — the reader picks the prayer-card size at print time. * posterAction="print" — open the print dialog instead of saving a file. * hidePrayerListWhenSoon — no "coming soon" placeholder on a wall whose list DOES print. - * The last two are a Driver ruling, not a preference (2026-09-23): "three print buttons, each - * opening an in-browser print dialog, no silent file download as the default action. A raw - * 'Download' button and a 'Prayer List: coming soon' placeholder were exactly the two buttons he - * objected to." + * The last two are a product ruling, not a preference (2026-09-23): three print buttons, each + * opening an in-browser print dialog, and no silent file download as the default action. A raw + * 'Download' button and a 'Prayer List: coming soon' placeholder were exactly the two buttons + * ruled out. * * CROSS-PANE COMMS — unchanged and still the decoupling that matters: this wall NEVER imports the * map. The shared component dispatches the window CustomEvent named below, scoped by instanceId, @@ -210,7 +210,7 @@ const zoneSheet = makeZoneSheet({ allRecords: () => recordsFor.all(), assetsBase // catalogued — I told regions-plugin exactly that, and it was FALSE: this file's three keys are // present in all ELEVEN locales, 0 gaps (enumerated 2026-09-27; the only three, all string literals). // ⚠ IT GUARDS A BARE HOST, NOT A MISSING KEY. Those are different failures and I had them confused. -// Product call taken by dx-shepherd (UPGHK, 2026-09-27) under the Driver's standing goal that the +// Product call taken by dx-shepherd (UPGHK, 2026-09-27) under the standing goal that the // production maps be localized. const t = useOptionalT('') diff --git a/plugin-designs/my-upg-100-list/upg-100-list.vue b/plugin-designs/my-upg-100-list/upg-100-list.vue index 88b004cc1..6b4cb0183 100644 --- a/plugin-designs/my-upg-100-list/upg-100-list.vue +++ b/plugin-designs/my-upg-100-list/upg-100-list.vue @@ -167,7 +167,7 @@ function testHandleKey() { // the ENGINES table in a profile is how two copies of one fact drift apart. const upgProvider = resolveMapProvider(profileConfig) const isMaplibre = upgProvider === 'maplibre' -// The geocoder is deferred to Mapbox by decision (Driver 2026-09-24): GeocoderComponent's maplibre +// The geocoder is deferred to Mapbox by decision (2026-09-24): GeocoderComponent's maplibre // path still calls makeMapboxForwardGeocode(accessToken), so the SEARCH REQUEST goes to Mapbox // whichever engine draws the tiles — a keyless map with a search bar is not keyless. const hasGeocoder = computed(() => { @@ -349,7 +349,7 @@ const geocoderRef = ref(null) // exposed ref // catalog entry, so the labels below are what render. If these tabs are ever translated, add // `upg100Region`/`upg100Zone`/`upg100Group` to tabs.json rather than reusing a generic key. // ★ "Zone" RENAMED, ORDER DELIBERATELY UNCHANGED (2026-09-23). -// Driver: "the user does not know what zones means" — the thing the map paints IS +// A reader does not know what "zones" means — the thing the map paints IS // a UPG-100 list (27 of them); "zone" was our internal word leaking into the UI. // So the LABEL now names what it shows. Region stays as what it actually is: a way // to SORT those lists by world area when you want that. @@ -383,7 +383,7 @@ const LEGEND_TABS = computed(() => [ // MEASURED 2026-09-25 by expanding every caret on the Region tab — 37 rows, 9 at indent 0 and // 28 at indent 1, deepest level 1. There is no level 2, so tab index 2 resolved to an empty set // and the panel rendered its "No data at this level" empty state with the tab ACTIVE. - // The Driver said "it doesn't need to have a People Group tab inside the legend"; the reason is + // The legend does not need a People Group tab; the reason is // that clicking it showed nothing at all. // ⚠ IF PEOPLE-GROUP ROWS ARE EVER WANTED BACK, a third tab is not the mechanism — the tree would // need a third level (list -> group). Re-adding the tab without deepening the data reproduces @@ -442,8 +442,8 @@ function legendOpts(records) { // the caller owns localizing it. MEASURED 2026-09-25 on the live Chinese render: the legend // header read "My UPG 100 List — Legend" in full English inside an otherwise localized panel, // beside translated tabs (区域 · UPG-100 名单) and a translated column header (人口). -// The Driver's gift policy is explicit — "BEAUTIFUL: no clipped text, no placeholders, no English -// leaking" — and an English title on the mobile showcase is exactly that. +// The gift policy is explicit — beautiful: no clipped text, no placeholders, no English +// leaking — and an English title on the mobile showcase is exactly that. // ★ THE HOUSE STYLE FOR A PROPER NOUN INSIDE A TRANSLATED PHRASE ALREADY EXISTS in this catalog: // "Doxa Regions" renders as "Doxa 区域" / "مناطق Doxa" / "Регионы Doxa" — the identifier stays // Latin, the frame translates. "UPG 100" is treated the same way rather than transliterated, so @@ -500,8 +500,8 @@ useShadowStyles( // matches research-map's .rm-legend-*-slot (767px) so the whole map stack // flips at the same width instead of drifting per profile. // ★ The search bar above the legend was REMOVED from this profile, so the legend rises into the - // vacated space (Driver 2026-09-23: "the search bar is removed... the legend needs to be moved - // up so that there's not a gap where the search bar used to be"). --stl-top is the shared + // vacated space (2026-09-23: with the search bar removed, the legend moves + // up so that no gap is left where the search bar used to be). --stl-top is the shared // SemanticTreeLegend's offset-from-map-top; 8px matches its own left inset. Other profiles keep // the 60px default because they still have their search bar. '.upg-legend-desktop-slot{--stl-top:8px}' + @@ -626,12 +626,12 @@ useShadowStyles( 'max-width:380px!important;z-index:1200!important}' + '.mapboxgl-ctrl-top-left .mapboxgl-ctrl{margin:0!important;float:none!important}' + // Push the legend panel BELOW the geocoder pill (legend is top-left here too) — - // ★ BUT ONLY IF THE PILL ACTUALLY RENDERED (Driver 2026-09-23, reported repeatedly: "the search - // bar is removed, so the legend needs to move up — there's a gap where the search bar used to - // be"). MEASURED in both hosts with a real token: the standalone leaf mounts the geocoder + // ★ BUT ONLY IF THE PILL ACTUALLY RENDERED (2026-09-23, reported repeatedly: with the search + // bar removed, the legend must move up — no gap where the search bar used to + // be). MEASURED in both hosts with a real token: the standalone leaf mounts the geocoder // (top 12, h 35) and the legend belongs at 58; the cap-5 shell mounts NO geocoder at all, and // an unconditional 58px stranded the legend below a pill that was not there — the dead gap the - // Driver kept reporting. One host cannot be fixed by breaking the other, so the offset is + // reports kept naming. One host cannot be fixed by breaking the other, so the offset is // conditional on the pill EXISTING: default raised to 8px (matching .stl-panel's own left // inset), pushed down only when a rendered geocoder is actually in the tree. // ★ SET --stl-top, DO NOT SET top DIRECTLY. The library caps the panel at @@ -641,8 +641,8 @@ useShadowStyles( // MEASURED 2026-09-24, upg-100-list hosted in a 420px-tall frame at 390px wide: top resolved to // 58px while max-height resolved to calc(100% - 20px), so the panel ran to 458px in a 420px map // and HUNG 38px PAST THE BOTTOM OF THE MAP — exactly 58 - 20. Same 38px at a 560px frame, because - // the error is the offset mismatch, not the map's size. Driver 2026-09-24: "the upg 100 list - // legend on the map is overflowing beyond the height of the map". + // the error is the offset mismatch, not the map's size. Reported 2026-09-24: the UPG-100 list + // legend on the map overflowed beyond the height of the map. // ⚠ WHY THIS IS INVISIBLE ON EVERY PUBLISHED LEAF: a standalone leaf gives the map the FULL // viewport, and a panel that overflows a full-height map is still inside the screen. It only // shows when a host makes the map SHORTER than the viewport, which is how the element is really @@ -670,7 +670,7 @@ useShadowStyles( // measurement — correctly. rega will read the rows on Simple Research and Prayer Progress, which // have NO override, after landing 5. If they read RTL there, DELETE the two rules below too. // ── the original finding, kept because it explains the shape ──────────────── - // Driver-reported via repo, 2026-09-26, from the README's Arabic picture: under ?lang=ar the legend + // Reported via repo, 2026-09-26, from the README's Arabic picture: under ?lang=ar the legend // panel stayed on the LEFT and the map controls sat on top of its top-left corner. // // ★ THE CAUSE IS ONE COMPONENT BEING RTL-AWARE AND ITS NEIGHBOUR NOT. MapToolbar.vue:42 already uses @@ -1315,15 +1315,15 @@ provide('onSemanticTreeSelect', onLegendSelect) // prop because renders several levels down inside the shell, which is also // why onSemanticTreeSelect above is provided. Without this the mobile sheet rendered its // SemanticTreeLegend with exportEnabled defaulting to FALSE, so a phone reader could browse -// the lists and had no way to print a packet or a poster — the half of this profile the -// Driver called "the only way that map would be usable". +// the lists and had no way to print a packet or a poster — the half of this profile without +// which the map is not usable. provide('onLegendExport', onLegendExport) provide('legendExportCards', true) // the card deck prints for the selected list // ── LEGEND EXPORT (top-right of the legend titlebar) ──────────────────────── // The shared legend emits 'export' with 'poster' | 'packet' for the currently -// SELECTED node — the Driver's ask: "I select one and it gives me print options at -// the top right of the legend... that's the only way that map would be usable." +// SELECTED node — the requirement: select one and its print options appear at +// the top right of the legend; without that the map is not usable. // // Poster serves the SAME pre-rendered artefact the poster wall downloads — one // file, so the legend, the wall and the preview can never show three different @@ -1333,14 +1333,14 @@ provide('legendExportCards', true) // the card deck prints for the selected li // One packet is ~3.5 MB (photos dominate); 28 zones would add ~100 MB to a repo // that ALREADY had a publish blocked at a 74 MB asset tree. Generating on click // costs zero repository bytes, and the photos come from URLs the records already -// carry. This is the Driver's instruction: "instead of fetching the poster from -// the public folder I want the client side code to generate the poster real time -// when you click on the button so it does not take a lot of mb storage." +// carry. The requirement: instead of fetching the poster from +// the public folder, the client generates the poster in real time +// at the click, so it does not cost megabytes of storage. // // The pages themselves come from library/packet/packet-render.js — the SAME module // the build-time generator uses, so the printed packet and the generated one cannot // drift. The card asked for exactly that: reuse, do not grow a fourth print path. -// ★ PRINT STRAIGHT FROM THE MAP — the Driver's "that's the only way that map would be usable". +// ★ PRINT STRAIGHT FROM THE MAP — without it the map is not usable. // Select a UPG-100 list in the legend and its print options appear at the legend's top right. // // ⚠ THE POSTER PATH USED TO HAND-ROLL AN OF THE .webp, which was wrong twice: @@ -1526,7 +1526,7 @@ async function localizedZone(zone) { // Every list across all three cluster buckets, flattened. // -// ★ THE ONE SEAM THE `list` PROP WILL FEED. Driver 2026-09-26 via the shepherd: UPG-100 is the mass +// ★ THE ONE SEAM THE `list` PROP WILL FEED. Decided 2026-09-26: UPG-100 is the mass // prayer mobiliser — a GENERATOR that takes a list in and puts posters, packets and cards out, so a // partner can generate their own. Every list-consuming path in this profile goes through THIS // function (allLists -> selectedLists, printPrayerPacket, the legend, the funnel), so when the @@ -1627,7 +1627,7 @@ async function packetFunnel() { // A confident figure I cannot defend is exactly the defect class I have been removing from other // surfaces all day; this one I put here myself. funnelPage already falls back to the // provenance-only footnote when unassigned is absent, so the page simply stops claiming it. - // Carded for the Driver: 27 geographic / 29 counting deaf, and whether "Central Asia + Pakistan" + // Carded as a product question: 27 geographic / 29 counting deaf, and whether "Central Asia + Pakistan" // (55 groups, contiguous, poster-walled as a real region) is a prayer list rather than a residual. if (listId === LIST_DEFAULT) { // printableZones, not allLists: the count prints on page 1 ("one of N") and at the triangle's @@ -1656,9 +1656,9 @@ async function packetFunnel() { } // ── BATCH SELECTION MAKES A PACKET OR A POSTER ────────────────────────────── -// Driver: the batch tool is "super buggy", and recolouring regions is not what is wanted — -// "the batch selection tool should let you create your own poster or prayer packet based on -// your own selection." So the selection is an INPUT to the two artefacts this app already +// The batch tool was reported very buggy, and recolouring regions is not what is wanted — +// the batch selection tool should let a reader create their own poster or prayer packet from +// their own selection. So the selection is an INPUT to the two artefacts this app already // builds, and neither of these grows a third pipeline: both end in printPrayerPacket / // packetPrints.printPoster, the same calls the legend and the poster wall make. const batchBusy = ref(false); @@ -1747,7 +1747,7 @@ async function selectionAsList() { throw keyedError('upgMap.nothingSelected', 'nothing is selected'); } if (!API_BASE) throw keyedError('wall.hud.noApi', 'no people-groups service is configured'); - // ★ primary_language + imb_gsec FEED THE GENERATED PROFILE DESCRIPTION (Driver brief A1.5 col 2, + // ★ primary_language + imb_gsec FEED THE GENERATED PROFILE DESCRIPTION (brief A1.5 col 2, // 2026-09-28). describeGroup builds a localized sentence — who, where, what language, how reached — // and GSEC is the only reachedness field that is a NUMBER: EvangelicalLevel is English prose from the // API ('2% or Greater but Less than 5%'), so interpolating it would leave every non-English packet @@ -2322,7 +2322,7 @@ onMounted(async () => { // the shadow root v3.3.0, .mapboxgl-canvas-container position:STATIC where Mapbox declares // it absolute, .mapboxgl-canary display:block, and 0 markers. A canvas container with no // positioning context leaves every absolutely-positioned child — the pins — with nothing to - // anchor to. Driver: "the polygons for the map and map colors and pins are not showing up". + // anchor to. Reported: the map's polygons, colours and pins were not showing up. // The comment at the top of this file already says the engine loader is imported rather than // re-declared "because a second copy of one fact drifts"; the stylesheet URL was that second // copy, and it drifted. @@ -2642,9 +2642,9 @@ onMounted(async () => { // nothing here. Sized for the count, not copied from the sibling: 6px at z=1 (+50%), // tapering back to the original 9px by z=8, where geography supplies the context and the // dots no longer need to carry it alone. - // ★ REVERTED TOWARD THE SIBLINGS (Driver 2026-09-23: "the dots are way too big, I never - // asked for them to be that big, they're larger than the dots on most of the other maps"). - // He is right and this was my overcorrection: an earlier pass raised z=1 from 4 to 6 to fix + // ★ REVERTED TOWARD THE SIBLINGS (2026-09-23: the dots were far too big, larger than + // the dots on most of the other maps, and nobody had asked for that size). + // That report is right and this was my overcorrection: an earlier pass raised z=1 from 4 to 6 to fix // "hard to see", reasoning that 100 marks alone on a planet need more presence than // all-people-groups' 12,379. The reasoning was sound but the amount was not — at 6 this map // became the LARGEST of the set (all-people-groups is 2.2 at z=0, 3.4 at z=4), so it read as @@ -2965,9 +2965,9 @@ onBeforeUnmount(() => { - diff --git a/plugin-designs/my-upg-100-list/upg-100-mfe.vue b/plugin-designs/my-upg-100-list/upg-100-mfe.vue index 09af7834e..c610175b2 100644 --- a/plugin-designs/my-upg-100-list/upg-100-mfe.vue +++ b/plugin-designs/my-upg-100-list/upg-100-mfe.vue @@ -62,7 +62,7 @@ import ShareButton from '@map/components/map-controls/ShareButton.vue' // reader's locale and still ends at English. // The four keys this file uses (tabs.map / prayerResources / selectView / views) are present in all // ELEVEN locales, 0 gaps, enumerated 2026-09-27 — nothing here was relying on the fallback. -// Product call taken by dx-shepherd (UPGHK, 2026-09-27) under the Driver's standing goal that the +// Product call taken by dx-shepherd (UPGHK, 2026-09-27) under the standing goal that the // production maps be localized; it changes what seven vue-i18n-less bundles render, which is not a // decision a migration gets to make for itself. const t = useOptionalT('') @@ -103,12 +103,12 @@ const spec = computed(() => ({ instanceId: instanceId.value, ...(cfg.value?.dataSource ? { dataSource: cfg.value.dataSource } : {}), }, - // RESOURCES FIRST, MAP SECOND (Driver 2026-09-23). "By default the first tab - // shouldn't be the map. The first tab should be the prayer resources" — that pane + // RESOURCES FIRST, MAP SECOND (2026-09-23). By default the first tab is not the + // map; it is the prayer resources — that pane // already explains what a UPG-100 list IS at the top and shows the posters, so it - // needs no explanation; a choropleth of zones does. Generalised by him as a design - // principle: "maps don't have to be primary. You can use lists and grids for the - // primary view and maps as a secondary view… then they transition into the map." + // needs no explanation; a choropleth of zones does. Generalised as a design + // principle: a map need not be primary. A list or a grid can be the + // primary view, with the map secondary and reached as a transition from it. // // ORDER LIVES IN `at[0]`, NOT IN THIS ARRAY'S ORDER. buildPaneColumn SORTS by // at[0] (pane-wrapper.js), while ViewSelect renders this array VERBATIM. Swapping @@ -193,15 +193,15 @@ function paneElement(pane) { // `lang` is the alias the page may carry; children read `locale`. if (inherited.locale === undefined && inherited.lang !== undefined) inherited.locale = inherited.lang const pcfg = { ...inherited, ...spec.value.config, ...pane.config } - // ★ NO "TAP A COLOURED DOT" COACH-MARK ON THIS PROFILE, AT ALL (Driver, 2026-09-27). + // ★ NO "TAP A COLOURED DOT" COACH-MARK ON THIS PROFILE, AT ALL (2026-09-27). // ProfileLoader mounts PinHint by default and self-gates it on a map existing, which is a // sound gate for the question it asks ("is there a map here?") and the WRONG question for this // profile. UPG-100's map is a POSTER PREVIEW: the reader is looking at what will be printed, and there // is no per-dot detail to open. So the pill invites a gesture that does nothing, and on the phone the - // Driver's screenshots show it over a page with no coloured dots on it at all. + // reported screenshots show it over a page with no coloured dots on it at all. // ⚠ THIS SUPERSEDES THE inert WORK FOR THIS PROFILE, and that is worth saying plainly rather than // quietly leaving both in: PILLRISK was "the pill shows over the posters", and I fixed WHERE it shows. - // The Driver's answer is that it should not show HERE, full stop — a narrower and more correct claim + // The ruling is that it should not show HERE, full stop — a narrower and more correct claim // than mine. The inert signal stays because it is still right for its own reasons (a stacked pane // should not be in tab order or the a11y tree, and studio's PinHint change serves profiles that DO // want the pill), but it is no longer what keeps this pill off this app. @@ -215,7 +215,7 @@ function paneElement(pane) { // ★ TELL THE INVISIBLE PANE THAT IT IS INVISIBLE. `inert` on every pane except the active one. // -// THE DEFECT, reported by the Driver and traced by repo (PILLRISK, 2026-09-27): PinHint's "Tap a +// THE DEFECT, reported from use and traced by repo (PILLRISK, 2026-09-27): PinHint's "Tap a // coloured dot" pill appeared OVER the Prayer Resources posters on a phone. Its IntersectionObserver // was working correctly — that is the point. The panes are `position:absolute; inset:0` in one // scroll-snap column, so the map pane is STACKED BEHIND the active view at full size: 100% of its @@ -261,9 +261,9 @@ function go(id) { // // ★ SCROLLING WAS ONLY HALF THE HANDOFF, and the missing half was invisible because the // visible part worked: go('map') moved the reader to the map, so the action looked like it -// had happened, while the map still showed all 27 zones. The Driver's brief for this is -// "when I click Show on map it should be basically the same as if I searched that result in -// the search bar" — i.e. ISOLATED, not merely scrolled to. +// had happened, while the map still showed all 27 zones. The requirement is that +// Show on map behaves as if that result had been searched in +// the search bar — i.e. ISOLATED, not merely scrolled to. // // The map half was already built and waiting: upg-100-list.vue listens for 'doxa:select-zone' // ON ITS OWN ELEMENT (not on window, so several embeds never cross-talk) and routes it through @@ -305,7 +305,7 @@ onMounted(() => { paneEls[pane.id] = el column.mountEl(pane.id)?.appendChild(el) } - // ★ THE FRESH-LOAD CASE, which is the one the Driver actually hit. Without this the panes carry no + // ★ THE FRESH-LOAD CASE, which is the one actually reported. Without this the panes carry no // inert attribute at all until the reader touches the switcher, so the pill is over the posters on // ARRIVAL — before any view change has happened. A signal that only fires on transitions never // describes the initial state. @@ -357,7 +357,7 @@ useShadowStyles(PANE_GRID_STYLES + ` background:var(--ui-bg); color:var(--ui-text); font:14px/1.4 -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,system-ui,sans-serif; } -/* NO AUTO-DARK. The DX design pattern is material LIGHT (Driver 2026-09-20): a system set to dark +/* NO AUTO-DARK. The DX design pattern is material LIGHT (decided 2026-09-20): a system set to dark mode must NOT flip this element. The prefers-color-scheme:dark override that used to live here is removed deliberately — the light palette above is the only theme. */ /* ── header: same height/border as the shell; switcher centred; share at right ── */