Commit graph

85 commits

Author SHA1 Message Date
doxa-maps-88655c70
a1005869ce Anchor the filter dropdown in every host, not just standalone
Some checks are pending
build-gate / build (push) Waiting to run
The menu is position:fixed with viewport coordinates. That resolves against the
viewport only while nothing establishes a containing block for fixed
descendants. VerticalTabsLayout -- the cap-5 shell that hosts every plugin as a
tab -- sets contain:layout paint on .vtl-content, inside .vtl-main{left:256px}.

Measured at 1600x900, same component, two hosts:
  standalone research-dashboard ...... dLeft=0   dTop=4    six of six
  inside plugin-studio dashboard tab . dLeft=256 dTop=111  every one

256 is the rail width and 111 the header height. Reported as the menu landing
"in a random spot further down to the right"; it was never random.

An earlier probe measured six triggers at four viewport widths and passed, so
the card was closed while the bug was still there. Every number was accurate.
They were answers about a surface the user never looks at -- widening across
more widths could not have found it, because the variable was the host.

Fix measures the containing block instead of assuming it: a fixed probe at 0,0
inserted in the menu's own parent reports the origin the menu resolves against.
When nothing captures, that origin is 0,0 and the standalone numbers are
unchanged bit-for-bit.

Not fixed by dropping contain from the layout: it is load-bearing there,
stopping a rail collapse from reflowing a heavy mounted map.

check:fixed-anchoring measures both hosts and treats an unmeasured host as a
failure. Negative-tested: reverting the subtraction fails the studio host with
dLeft=256 while standalone still passes -- it fails exactly where the old probe
passed.

Also cards a second symptom of the same cause, not yet fixed: fixed-position
modal scrims written inset:0 stretch to the content pane instead of the
viewport, leaving the rail clickable behind an open modal.
2026-09-22 17:22:23 +00:00
doxa-maps-88655c70
e1d27cb476 Record which kind of verification closed each card
Some checks are pending
build-gate / build (push) Waiting to run
A card was closed on an agent measurement while the bug was still visible to
the Driver, and the card had no field in which that disagreement could live.
The board said done and the product said broken, and nothing in the data knew.

Adds fields.verification (agent|human|both) plus verification_kind
(visual|state) and a conflict flag, back-filled across 179 closed cards, and
a gate that refuses an anonymous close.

The gate does not require human sign-off. Gating the board on human review was
tried and it stalled. What it forbids is losing the distinction, so the
question "which of these did a human actually look at?" stays answerable.

The visual/state split encodes the asymmetry the Driver named: human
verification is more reliable on visual bugs, agent verification on non-visual
ones. A headless probe reads geometry, not perception -- it can measure a menu
at dTop=4 and still be blind to it feeling wrong. So a visual card closed on
agent evidence is a hypothesis; a state card closed on agent evidence is a
result. The counts are reported separately.

Negative-tested three ways: stripping a tag, claiming human verification with
no quote, and marking a conflict card done each exit 1 by name.
2026-09-22 17:00:26 +00:00
doxa-maps-88655c70
6189966a89 Give selections a permanent row so the app stops jumping under the cursor
Some checks are pending
build-gate / build (push) Waiting to run
The selections row left the DOM whenever nothing was selected, so it appeared on every
select and vanished on every clear — and the map, the table and the grid moved each
time. That is what made the dashboard hard to use: not where the chips sat, but that
everything below them shifted while you were looking at it.

The row now always renders and only its contents change. Empty it reads "Selected
World", which is also true rather than merely a placeholder: nothing filtered really
does mean the whole world is in scope. Clear-all is simply absent when there is nothing
to clear, instead of the row collapsing around it.

Height is pinned and the row no longer wraps, because wrapping was the other way it
could grow; a long selection scrolls sideways instead of taking a second line. Slim
enough to read as a status strip rather than a tray.

Measured across all three states — empty, selected, cleared — the row height stays 28px
and the map top stays at 186px. Nothing below the row moves.
2026-09-22 16:14:27 +00:00
doxa-maps-88655c70
ec012f45b6 White rings on the pins, one place for selections, and two gates that told the truth
Some checks are pending
build-gate / build (push) Waiting to run
Pins keep their navy but gain a white ring and a radius that shrinks as you zoom out, so
neighbouring dots separate instead of merging into one blue mass. The Driver asked for
rings rather than clustering, explicitly to avoid more logic.

The top header no longer carries selection state. That belongs under the filter toggles,
in the second header, and nowhere else.

The filter menu is anchored to its trigger again. It had been moved to fixed positioning
to escape a scroller that was clipping it out of existence, and viewport coordinates go
stale in ways that put the menu somewhere unrelated to the box that opened it.

A gallery row now carries its identity as an attribute. A Vue key is a reconciliation
hint and is never rendered, so the smoke check read undefined and reported a broken deep
link on a page that works — measured zero occurrences of that attribute in both the
generator and the built page. Asserting on the visible label instead would have coupled
a machine check to display text.

That repaired gate immediately earned its keep: it caught the gallery asking for assets
one directory too deep. The relative asset base was correct while the gallery was the
root page and silently wrong once it moved aside for the studio, and the failure surfaced
as a JSON parse error rather than a 404, because an unknown path answers with HTML.
2026-09-22 16:01:16 +00:00
doxa-maps-88655c70
5725f5b9d9 Let a stacked composite find its siblings in either tree
Some checks are pending
build-gate / build (push) Waiting to run
stack-demo rendered two empty sections in dev. Its sibling bundles were addressed with
a tree-relative path, which the browser resolves against the document URL, so no host
and no attribute can redirect it — correct in the built tree, a 404 in dev. Measured:
the dev entry answers 200 while the path the relative form resolves to answers 404. The
sources now resolve at runtime, so the same file is right in both trees, and the
production branch compiles away to the string it replaces.

That was the third place this defect appeared. Both capability-5 shells carried the same
hardcoded paths and were cured the same way, and each instance was found separately
after the previous one was fixed — because a literal parent-directory path reads as
correct in review and is invisible to a gate that only ever checks the built tree.

Removing the 404 was not enough: the sections were still empty with zero failed
requests. The shared layout injected each bundle with a classic script, and a classic
script pointed at a dev ES module fires its load handler successfully and only then
throws, so the promise resolved while the tag never registered and the wait for
definition quietly timed out. A load handler cannot detect that.

The module rule now lives in the shared layout rather than in a fourth private copy of
the same loader, so the two other composites that inject through it are covered too.
Verified after: both elements define, sixty-six facet rows and twenty-four cards on
stack-demo and on dashboard-plus-grid, zero failed requests on each.
2026-09-22 15:37:41 +00:00
doxa-maps-88655c70
012c79328a Free the filter menu from its clipping ancestor; square the people-group images
FILTER DROPDOWNS WERE INVISIBLE. Opening a filter rendered its options underneath
the surrounding content, making the dashboard's primary control unusable.

The cause was CLIPPING, not stacking order, and that distinction is why an earlier
attempt failed. The filter band is a one-row horizontal scroller authored as
overflow-x:auto with overflow-y:visible — but CSS Overflow 3 coerces a visible axis
to auto when the other axis is not visible, so it computes to auto/auto and clips
vertically. Clipping happens during painting, before stacking order is consulted, so
raising the band to z-index 55 changed nothing: it won a stacking fight that was never
the problem. You cannot re-order pixels that were never generated.

The menu is now position:fixed, anchored to the trigger's viewport rect, which takes it
out of the clip chain entirely. Fixed coordinates go stale whenever anything scrolls or
resizes, so they are recomputed on open and while open, listening in the capture phase
so the dashboard's inner scroll regions are seen too.

PEOPLE-GROUP IMAGES WERE LETTERBOXED. A fixed 130px height against a 220px column
cropped each person to a band. The image is now a square via aspect-ratio, and the
column floor rises to 240px, roughly doubling the visible area. object-fit:cover is
kept deliberately — stretching to a square would distort faces, which is worse than
the letterbox it replaces.
2026-09-22 13:31:11 +00:00
doxa-maps
684b209704 Show the research-map composite instead of Big Picture on a phone
Some checks are pending
build-gate / build (push) Waiting to run
The Driver's ordering: desktop opens on the Big Picture dashboard; mobile opens
on the research map and does not show Big Picture at all. Both capability-4
composites already existed, so this is the shell choosing between them. A row in
the nav model can now declare onlyWhen desktop or mobile; everything below the
first rung is identical on both, which is why only the first two rows carry it.

One nav model rather than two, so the teaching order lives in one place. Two
parallel models would be two things to keep in sync and the failure would be
silent: a row added to one and forgotten in the other simply never appears.

Crossing the breakpoint can remove the row that is currently active, which would
leave the user on a mounted but unlisted tab with no highlight. The shell now
snaps to the first surviving row, and establishes the viewport class before
opening the first tab so a phone never opens Big Picture for a frame.

Also fixes a pre-existing bug this exposed: with no header there was no way to
open the rail on mobile. The drawer sits off-canvas, the only toggle lives inside
the header, and the collapse control is inside the drawer itself — measured
off-screen at x:-244. Every tab except the one that happened to open was
unreachable. A floating button now appears only when narrow, headerless and shut,
so no existing consumer can see a change.
2026-09-22 08:13:41 +00:00
doxa-maps
40c4cc67d4 Move the eight CARTO basemap styles to OpenFreeMap
Some checks are pending
build-gate / build (push) Waiting to run
Eight of the twelve named styles resolved their MapLibre URL to
basemaps.cartocdn.com. Those are keyless today -- verified live, style JSON
and a real vector tile and a font all 200 with no token -- but CARTO's own
docs reserve the right to extend the key requirement to vector tiles. That
is a future silent outage already shipped, and the same single-point-of-
failure shape we are trying to escape by leaving the URL-restricted Mapbox
token. A dependency that is free today and gated tomorrow is a deferred one.

  dark-matter -> openfreemap dark      (midnight-glow, dusk, ink, wayfinder-night)
  positron    -> openfreemap positron  (paper)
  voyager     -> openfreemap liberty   (satellite, hybrid, wayfinder-day)

Each replacement verified before the swap: 200 keyless, zero keyed URLs in
sources/glyphs/sprite, real tiles serve. Built output now has zero CARTO
references. Embed suite 40/40 pages mount cleanly.

The header records the bar for adding a style here: keyless, commercial use
permitted, self-hostable. MapTiler and Stadia free tiers fail the second.
2026-09-22 02:27:48 +00:00
doxa-maps
7f08d09edc Remove the tile-403 on-screen banner; connect dashboard selections to the grid
Some checks are pending
build-gate / build (push) Waiting to run
Two Driver-reported defects.

1. No more "Basemap tiles blocked" popup on the map. The banner reported an
   operator problem (one Mapbox account setting on one deployment origin) to
   the end user, who can do nothing about it, on every map and every load. The
   console diagnosis stays, because it reaches the person who can act.

2. Selections in the dashboard now filter the grid beneath it. The two halves
   were never connected: research-dashboard had no defineEmits and its bus is a
   per-instance factory that is never provided, while dashboard-plus-grid passed
   the grid no filter props. The grid's receiving end already worked. Added the
   emit, plus a translation layer between the dashboard's snake_case facet keys
   and the grid's camelCase props, mirroring big-picture.

   Proven live: typing "Turk" takes the grid from 24 cards to 22 with wholly
   different rows. Only 4 of 12 facets map; the rest are dropped rather than
   guessed, because religion_family carries a family name while the grid's
   religion prop matches a code, and mapping them would filter to zero rows.
2026-09-22 01:43:56 +00:00
doxa-maps-88655c70
3f103aaae7 pass the real token down from ProfileLoader when tk is absent
Some checks are pending
build-gate / build (push) Waiting to run
ROOT CAUSE, proven by interception rather than inference. A COMPOSITE leaf whose
own root paints no tiles is generated TOKEN_FREE, so its page calls mount('') and
the "tk: token" assignment never runs. Intercepting setAttribute BEFORE Vue could
consume it showed profile-config arriving with keys profile/dataSource/
instanceId/assetsBase and NO tk. ProfileLoader then computed '' and provided it
to every child, so a map nested INSIDE the composite got an empty accessToken and
logged "No Mapbox access token provided" - the error reported at
dashboard-plus-grid.js:605.

The generator assumed a composite's nested maps each render in their own iframe
leaf running its own token ladder. That is false for dashboard-plus-grid: zero
iframes, and ResearchDashboard / PeopleGroupsGrid are imported as COMPONENTS, so
the nested map runs inside the shell page and needs the token the shell withholds.

ProfileLoader now falls back to window.MAP_TOKEN when config.tk is absent.
STRICTLY ADDITIVE: 10 components inject mapboxToken and today all receive ''
whenever tk is missing; now they receive the real token. An empty string becoming
a valid token cannot break a map that already worked.

Verified: the nested map inside dashboard-plus-grid now carries a real
accessToken instead of ''. Negative-tested both ways - an explicit ?tk= still
WINS over the global (per-instance precedence intact), and with no token anywhere
the code still logs "No Mapbox access token provided" rather than silently
pretending. Full build ALL GUARDS PASS, SRI consistent.

This does not make the generator's classifier correct; see
BUG-COMPOSITE-LEAVES-ARE-TOKEN-FREE-BUT-NEST-REAL-MAPS for the deeper fix.
2026-09-22 00:09:43 +00:00
doxa-maps-88655c70
7ccdc37e8f show the tile-403 on screen, top-left, not only in the console
A console message only helps someone who already suspects a problem and opens
devtools. The reported experience was "I clicked the map and saw nothing", so
the page itself must say why.

The leaf's own #status node is not usable here: done() removes it the moment the
element mounts SUCCESSFULLY, which is exactly what happens in this failure -
mount succeeds, only the tiles 403 afterwards. So the composable creates its own
small banner instead.

A CORNER banner, never a full-cover overlay: the data layer, legend and labels
all render correctly and stay useful. Hiding a working map to report a missing
basemap would trade one blank screen for another.

TOP-LEFT was chosen by LOOKING at a screenshot, not by geometry. A first attempt
at bottom-left rendered underneath the legend panel and was unreadable, while
every numeric check still passed - 442x70px, correct palette, 3% coverage.
The other corners are taken: controls top-right, attribution bottom-right, hint
pill bottom-centre.

Material light only: #fff surface, #3b463d text, #d1d4cd border, #6d766e muted.
No red - this is a configuration notice, not a crash. pointer-events:none so it
can never block map interaction, and the container is only set position:relative
when it is still static, so a profile that positions its own container keeps it.
2026-09-22 00:02:50 +00:00
doxa-maps-88655c70
4c6d8571cf name the tile-403 failure instead of rendering a silent blank void
A URL-restricted Mapbox token returns 200 for the style document AND the fonts,
and 403 only for tilesets. So the element mounts at full height, the legend and
labels paint, the data layer paints - and the basemap silently never arrives.
It reads as a rendering bug in our code. It is not: it is one account setting.

Nothing listened for it. GL-JS fires an "error" event carrying e.status on every
failed tile request, so the information was always there - no one asked. That gap
cost real debugging hours this flight and is the first thing an inheritor
deploying to a NEW domain will hit.

The listener attaches after both engine branches converge, so it covers Mapbox
and MapLibre with one hook, and is wrapped in try/catch so an engine without an
.on() method can never break map creation.

ONE MESSAGE PER MAP, not per tile: a blank basemap 403s every tile in the
viewport, dozens per second while panning, and an unguarded console.error would
bury the page and train the reader to ignore it.

Verified both directions: a restricted map produced 9 tile 403s and exactly 1
diagnostic; the token-free maplibre profile mounted 800px and emitted 0.
Full build ALL GUARDS PASS, SRI consistent.
2026-09-21 23:44:11 +00:00
doxa-maps-88655c70
9dc4dda8cf consolidate docs into documentation/ and deployment shells into deployment/
Some checks are pending
build-gate / build (push) Waiting to run
Driver 2026-09-21: 'a folder called deployment which will store the capacitor
folder, wordpress folder and tauri folder', and 'a folder called documentation
to store the contributing folder so docs are in one place'.

docs/ + contributing/ + CONTRIBUTING.md -> documentation/ (three doc homes into
one). capacitor/ + wordpress/ + src-tauri/ -> deployment/.

The public/ -> dist/ rename the Driver asked about is NOT here: after seeing the
measured blast radius (855 tracked files, 54 source refs, and public/ is the
served web-root four consumers point at) the Driver withdrew it - 'keep the
public folder the same'.

Path references were rewritten mechanically (258 across 87 files), but three
classes needed hand fixes because a prefix regex cannot see them:
  - join(ROOT,'docs',...) in 10 internal scripts - a quoted SEGMENT, not a prefix
  - tauri frontendDist '../public' -> '../../public', since src-tauri is now one
    level deeper; check:tauri caught this exactly as the card predicted
  - the WordPress contract test's dirname(__DIR__,2) -> 3, same reason

Also reverted one over-reach: the rewrite renamed a FINDING-CATEGORY label
'docs' in public-hygiene-check.mjs, which is a rule name in its own header, not
a path.

Verified: full build ALL GUARDS PASS, SRI consistent; check:tauri, check:mobile
(cap sync + webDir OK), check:wp-embed, quoted-scripts, capability-citations,
capability-exemplars, library-index, public-hygiene, parse and drop all pass.
2026-09-21 23:23:23 +00:00
doxa-maps-88655c70
af73dfb3f9 adopt Material nav metrics in VerticalTabsLayout
Driver: "the sidebar is supposed to look like Material UI, like what people are used to...
people are used to the YouTube layout, Google layout is just way better. We do not need
to create custom styles people are not used to."

Measured before: app bar 51px, nav rows 44px with an 8px radius, collapsed rail 60px.
Now app bar 64px desktop and 56px mobile, rows 48px, a full pill active row, and a 72px
mini-variant rail. Nav width was already 256px and is unchanged.

Nothing vendored. The card's law is to imitate the metrics in our own CSS rather than add
Quasar or MUI, which is the same clone-don't-edit rule the library follows elsewhere.

Two traps worth recording. box-sizing:border-box is load-bearing on the app bar: without
it the element is content-box, so min-height:64px measured 81px live once padding and
border were added. And the rail collapse is a translate rather than a width change, so
four numbers are coupled — the nav translate, the content pane's left, and two padding
compensations that keep icons inside the visible strip.

Verified live: app bar 64 desktop and 56 mobile, rows 48 with a 999px radius, rail 256
expanded to 72 collapsed with the content pane starting at exactly 72.
2026-09-21 16:25:43 +00:00
doxa-maps-88655c70
c401a758bb name the legend collapse control and gate every button's accessible name
Last tick's fix covered the shared map-control base. Sweeping the rendered DOM of all 17
bundles found three more unnamed buttons — the same "Collapse legend" control in three
map bundles, again from one shared component. Its only content is an svg caret, so with
title alone its accessible name was empty.

It is a disclosure control, so it now reports aria-expanded as well. Verified by toggling
it: the label flips Collapse/Expand and aria-expanded flips true/false.

The gate measures the rendered DOM through shadow roots, because a source grep cannot
answer this question. There are 132 <button> hits here and most have visible text, which
IS a valid accessible name; aria-label is often on a following line. Only the DOM knows
which buttons ended up nameless. It counts aria-label, a resolved aria-labelledby, or
visible text, and deliberately does not count title, which is the defect it was written
for. Hidden buttons are skipped since assistive tech cannot reach them either.

The sweep went 319/322 before the legend fix to 322/322 after, which is the evidence it
detects real defects rather than passing vacuously.
2026-09-21 13:23:35 +00:00
doxa-maps-88655c70
a5c5cf1910 give every map control an accessible name
The zoom buttons render an icon through a slot and carried only `title`, so their
accessible name was empty: a screen reader announced "button" with no indication of what
it does. title is a tooltip, not an accessible name — unreliably announced, and never
surfaced to touch users.

Found while proving the research-dashboard zoom controls actually work. They do: a click
triggered six tile requests at zoom level 2, so the open-work item is function-verified,
not just present. The probe that matched aria-label found nothing while the probe that
fell back to title found both buttons, and that discrepancy was the defect.

One binding in the shared MapControlButton reaches all eight control buttons — zoom in
and out, fullscreen, location, help, share, hamburger, theme — across seven map bundles,
because every one composes this base. No caller changes: the component does not set
inheritAttrs:false, so a caller passing its own aria-label still wins through normal
fallthrough, and undefined omits the attribute when there is no title to mirror.

Verified across all seven bundles: 34 control buttons, 0 without an accessible name.
2026-09-21 13:02:56 +00:00
doxa-maps-88655c70
88f01b9a95 lift the pin hint into view when its host clips it
The cap-4 composite shipped the coach-mark sliced through the middle of its sentence.
Measured, same component and viewport: the leaf renders the pill at bottom 864 of 900,
the composite at 919 — clipped by 17px, because the composite adds a ~53px header above
its nested child's stage and findMapBox() finds no positioned container to re-parent into.

The component's header promises that case degrades to "stay put — a degraded anchor, never
a crash". A graceful degradation that degrades to invisible is a failure, not a fallback,
so the clamp measures the rendered rect and only ever lifts a pill that is actually clipped.

Two wrong attempts are recorded in the code because the reasons matter. Setting
style.transform would have destroyed the wrapper's translateX(-50%) centring, and the
pill's computed transform also carries the bob animation, so a computed reading is never
just my offset. Adjusting the bottom offset composes with the attribution clearance
instead of fighting it. Clamping only at nextTick also missed: the composite's layout has
not settled then, so the clamp now runs from syncAttribClearance, which already re-fires
from a ResizeObserver, plus a second observer on the pill's own layout parent.

Verified on six surfaces: the composite lifts 30px to bottom 888, every other surface
reports lift 0 and is byte-identical in behaviour, and all six keep centreDelta 0.
2026-09-21 12:30:11 +00:00
doxa-maps-88655c70
2fa4bf992a point docs at library/layouts and fix the stale bunx and provider-ladder claims
The top-level layouts/ directory does not exist; the wrappers live in library/layouts/.
Six references across four docs named the phantom path, including a copy-pasteable
cd command and a README-longform link that resolved to docs/layouts/README.md (a 404).

how-to.md taught bunx for the iOS scaffold. bunx is not on PATH here, which is the
exact failure package.json already documents in cap:sync; point both at the local bin.

useMapProvider.js's own header listed three resolution rungs, omitting ?provider= and
misnumbering window.MAP_PROVIDER. The function implements four. how-to.md was correct.
2026-09-21 10:43:11 +00:00
doxa-maps-88655c70
981cc40633 Shared layout and legend tools on the DX palette; keep dark-surface ink ramps 2026-09-20 06:15:37 +00:00
doxa-maps-88655c70
12ef4a529b Primary button uses a sage shade that meets WCAG AA for text at its rendered size 2026-09-20 05:24:44 +00:00
doxa-maps-88655c70
eae4e2be4c Restore cap-4 i18n context (configureApp) and re-theme shared search components to the DX palette 2026-09-20 05:15:02 +00:00
doxa-maps-88655c70
85014aad11 Session work: strobe fix, grid layout, stacked tree legend, selection camera, chip bounding, asset inheritance, gates 2026-09-20 04:49:25 +00:00
doxa-maps-88655c70
ea0c47b277 Brand-neutral shared VerticalTabsLayout with lazy nested-element hosting; fix cap-5 prayer tab leaf path; neutralize library identifiers; add Forgejo CI build-gate workflow
Some checks failed
build-gate / build (push) Has been cancelled
2026-09-19 17:24:30 +00:00
doxa-maps-88655c70
2d64e21fbf Complete app-profiles->plugin-designs sweep across comments/docs; build green; layouts kept at root (load-bearing) 2026-09-17 18:18:19 +00:00
doxa-maps-88655c70
1a3925c6a6 Rename app-profiles -> plugin-designs; build green under new naming (load-bearing paths updated, guards pass) 2026-09-17 18:18:18 +00:00
swift-river542
daa32d4c58 Research tabs read at 15px; the status red is a step brighter
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-17 02:38:38 -05:00
swift-river542
f6c86be7a9 Share menu: the multiplication steps read at 14px
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-17 01:59:02 -05:00
swift-river542
030fca67ec Map corners hold after the canvas loads (paint-time clip inside the map); status red lifted a touch 2026-09-17 01:56:36 -05:00
swift-river542
cde3291049 Rounded corners reach the map canvas: the page's radius token rounds the canvas itself, which a compositing layer leaves unclipped 2026-09-17 01:26:21 -05:00
swift-river542
1e83b1e5ff The pin invitation appears on every visit and stays until the reader closes it 2026-09-16 23:22:32 -05:00
swift-river542
832488ea69 The map attribution is tappable: corner controls sit above the scroll-edge gutters 2026-09-16 23:17:58 -05:00
swift-river542
a025b69e14 Phones: the search bar sits in its own header band; the share menu is titled Share and shows its content without scrolling 2026-09-16 23:02:09 -05:00
swift-river542
c229edc66e MapControlMenu: one menu for every map control — inside the map, top and height of the toolbar column, on its inner side, RTL-aware, phone and desktop; the share button is its first consumer 2026-09-16 22:46:21 -05:00
swift-river542
3f99dd8c99 Share menu anchors next to its button on every width 2026-09-16 22:33:53 -05:00
swift-river542
c6b6dce11f Share menu is part of the map: rendered in the map area, placed from its button, top layer on its own; toolbar stays under the legend 2026-09-16 22:30:35 -05:00
swift-river542
9203b2fc87 Share menu is a compact 340px, never wider than the viewport; right-aligned under the toolbar on phones 2026-09-16 22:16:46 -05:00
swift-river542
a391cfb65e Share menu paints above every map layer: the toolbar lifts while a menu is open; the menu stays inside the map's bottom edge; phone band spans the map 2026-09-16 22:14:27 -05:00
swift-river542
dc6bde1fe3 Phones: people-group image back to 16px above the sheet; scroll gutters exactly as wide as the control column 2026-09-16 22:07:36 -05:00
swift-river542
63067ff7e6 Phones: the attribution watermark sits above the collapsed legend strip; an opened sheet covers it 2026-09-16 22:01:42 -05:00
swift-river542
39b5863236 Phones: one attribution watermark bottom-right; corner controls stay at the map bottom under the open sheet 2026-09-16 21:53:27 -05:00
swift-river542
b03553c1b1 Phone sheet: legend rows fill the width (clear button floats at the row edge); logo and attribution share one bottom-right row 2026-09-16 21:37:00 -05:00
swift-river542
db6aabe99f Phones: Mapbox logo and attribution both bottom-right so the detail sheet's image stays clear 2026-09-16 21:26:48 -05:00
swift-river542
9ca6e04fa1 Keep the prayer yellow to the prayer palette; other palettes keep their orange 2026-09-16 21:21:07 -05:00
swift-river542
62da42999c Prayer palette: Has Prayer uses the site's yellow (#f0c64a) so legend, pins and progress bar match the prayer status block 2026-09-16 21:18:56 -05:00
swift-river542
3379fb586c Research map tab reads "People Groups (Affinity)" 2026-09-16 21:12:18 -05:00
swift-river542
a130ad81d2 Research map tab reads "People Groups (Ethnic Affinity)" 2026-09-16 21:09:01 -05:00
swift-river542
09471647cc Research map: religion joins prayer, adoption and engagement on the night look; only people, regions and languages are monochrome day 2026-09-16 21:01:37 -05:00
swift-river542
b024d83d83 Share menu: first tab is "Embed link"; the rainbow ring rotates in every browser 2026-09-16 20:56:35 -05:00
swift-river542
1b22fa419b Basemap follows the tab: prayer stays night, every other map is day in monochrome white
- useMapTheme: one look rule (any prayer strategy → night/default; everything else →
  day/monochrome) applied at boot and on every tab switch in the simple map and the
  research map; an unknown strategy keeps the current look
- Legends and the research search pill are 380px again; desktop numeric columns 70px at
  13px so every row stays on one line with no overlap
- Map containers carry their map instance for gates (no global)
2026-09-16 20:50:51 -05:00
swift-river542
f496453016 Legend export button hidden on every map until the export packet works 2026-09-16 20:34:23 -05:00