rega's console answered the question in one line: "0 pin(s) selected but no rows matched", for both a
language-family selection and a prayer selection, with the pins plainly on screen. Not an id mismatch and
not a missing filter — readSourceFeatures returned an empty list.
THE TWO ENGINES STORE _data DIFFERENTLY. maplibre-gl's GeoJSONSource wraps it:
this._data = typeof options.data === 'string' ? { url: options.data } : { geojson: options.data }
so `data.features` is undefined there. Mapbox stores the GeoJSON directly. This code was written against
Mapbox, where it works, and has been returning nothing on MapLibre ever since — which is the keyless
engine, the one the public builds use.
★ THE PACKET IS THE SMALL HALF. This reader is what zoomToLegendRow uses to answer "which pins does this
legend row select", and it backs research-map, country-posters and doxa-simple-map. On MapLibre every one
of them has been failing to fit the camera to a clicked legend row — silently, because the function is
written to no-op rather than throw when it finds no features. The original comment above it explains that
querySourceFeatures is viewport-clipped and would make off-screen rows "silently no-op"; the replacement
did exactly that on one engine, for a different reason.
The wrapper is unwrapped, and a URL source returns [] explicitly — having no local features to read is a
different fact from finding none, and collapsing the two is how this hid.
Verified: gates:pre 13/13. Needs eyes, and the second one matters more than the first:
· the packet on MapLibre prints the SELECTED groups, cover count no longer the whole list;
· clicking a legend row on MapLibre FITS THE CAMERA to that row — on research-map, country-posters and
doxa-simple-map. If that has been dead on the keyless engine, this is the commit that revives it.