Adds library/components/qa/QaCorner.vue — a bottom-right floating 'QA' button +
panel (OIDC-onboarding shell: 'Log in with Nuxtinator', no key), rendered by
ProfileLoader over any profile. OPT-IN via profile-config.qa (default OFF) so the
same bundles that power partner embeds never show a QA button; the SPA shell sets
qa:true on every mount so it appears on all maps in the power app. Backend (qhoot /
nuxtbase-baas agent bridge + MCP) wired in a later pass — this is the visible shell.
Spec: _qa-cycle/01-ideation-research/qa-loops/qa-embeddable-qa-agent-bridge.md
Add a gatedProfiles config field (default [key-cities]) honored by the tree
generator: a gated bundle's .js still BUILDS via vite, but it never appears in
the staging root, the per-bundle staging pages, or manifest.json — the surfaces
generate-tree emits. This makes key-cities gated in ONE place for every surface
(convert.py already gates the go-base plugin index), instead of relying on the
box-side converter alone. The staging root now shows all 9 bundles + their
elements with no key-cities leak.
The section/subgroup headers are non-interactive group labels; their leading
icon added visual weight without meaning. Render them as plain text so the
sidebar reads as clean labelled separators. Nav ITEMS keep their icons, and
the collapsible Experimental folder keeps its icon+chevron (interactive row).
Rail mode already hides .sect-hdr entirely, so no empty headers there.
- SPA sidebar: suppress the leading section divider on the FIRST nav group.
Every section emitted a `.sep` rule before its header, so Prayer Mobilization
(the first section) drew a 1px line directly under the header with nothing
above it to divide. drawSide() now tracks a firstGroup flag and skips it.
- Research dashboard: when the table under the map collapses, resize the map to
fill the freed space. The ResizeObserver alone missed the grid reflow at the
instant the table cell flips to display:none (v-show), leaving the map canvas
at its old size (gray gap). DashboardMapPanel now also resizes on the
'toggleTable' bus event (rAF + a 280ms settle pass), with clean teardown.
Three fixes for the power-app SPA running as a go-base plugin (sandboxed
iframe, origin 'null' — where localStorage throws and root-absolute asset
paths misresolve under the /plugin-assets/<name>/ subpath):
- localStorage: wrap every theme/preference read+write in try/catch across
the library (ProfileLoader, useMapTheme, uiStore). `typeof localStorage`
is not enough — in a sandbox the object exists but ACCESS throws
SecurityError. Sandboxed maps now boot themeless instead of crashing.
- assets: the SPA shell now injects an absolute assetsBase (derived from its
own document.baseURI) into every mounted element's profile-config, so
bundles fetch tables/vendor (Tabulator) from the correct subpath instead
of a root-absolute /assets that 404s under /plugin-assets/doxa-maps-spa/.
- nav: revert the Prayer Mobilization section icon to 'heart' (the prayer
glyph read as a header it is not).
Rebuilds every bundle (library-wide localStorage change).
Standalone repo that builds embeddable JAMstack map bundles (web components),
composes them into a lazy-loaded SPA via layouts/, and optionally wraps a
Capacitor Android/iOS app — one build, choose your output/CDN. Diátaxis docs.
History reset to a single clean commit; no PII, IPs, or internal terms.