VerticalTabsLayout, header off: on a phone a 44px bar (a real grid row) replaces the floating corner
circle, with the rail toggle at the inline start and a #phone-end slot at the end; on a desktop a
#rail-end slot sits at the bottom of the rail (it receives `collapsed`). Neither renders with a header
on, so header-on consumers and desktop layouts without a filler are unchanged. The --map-fab-* footprint
is no longer published; its readers fall back to their plain insets.
ShellLanguageMenu fills either slot: the switcher's languages plus the current one, a native select
under a globe face. A pick dispatches one cancelable, composed, bubbling doxa-language-request on the
host element (library/utils/languageRequest.js). A host that cancels keeps the language; otherwise the
menu emits 'switch' and writes ?lang= only on a page the tree generated.
check:shell-header (gates:pre, Vite SSR) asserts where the bar and the rail slot render, the event's
shape and count, cancel and no-cancel, the ?lang= rule and the language list; its self-test (gates:post)
refuses 11 planted defects. check:nav-reachable now presses the bar's toggle.
No Vue, no Pinia, no Mapbox. Anything reactive is a composable; anything stateful is a store.
File
Purpose
apiBaseUrl.js
Resolves the API base URL at runtime (window.MAP_APP_API_URL / VITE_API_BASE_URL)
embedBase.js
Share/embed URL ladder — the built bundle derives its tree root from its own script url (profileConfig.shareUrl / embedBaseUrl / window.MAP_EMBED_BASE_URL override) so tree-relative <bundle>/<profile>/index.html links work on any host
geoUtils.js
Centroid, bounds, validation, GeoJSON helpers
ClusterHelpers.js
Shared helpers for the two clustering utilities below
MSTClusteringUtil.js
Minimum-spanning-tree clustering for affinity blocks
NetworkClusteringUtil.js
Network-line clustering — connect nearby pins with edges
No import { ref } from 'vue' and no import mapboxgl in this folder — operate on plain
[lng, lat] arrays.
Named exports (for tree-shaking), JSDoc on every export.
Writing reactive logic or needing Mapbox APIs? That's a composable — move it to ../composables/.