@mapmap/maps 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +119 -1
- package/dist/index.js +249 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/diagnostics.ts","../src/coords.ts","../src/effects.ts","../src/logo.ts","../src/nav-design.ts","../src/poi-design.ts","../src/style.ts","../src/map.ts","../src/osrm.ts","../src/route.ts","../src/contrast.ts","../src/puck.ts","../src/daynight.ts","../src/language.ts","../src/probe.ts","../src/places.ts","../src/camera.ts","../src/isochrone.ts","../src/adr.ts","../src/guidance.ts","../src/voice.ts"],"names":["lng","lat","colour","alertSoundUrl","isRecord","maplibregl","EARTH_RADIUS_M","DEFAULT_ZOOM","now","boundsOf","deg","handle","max","fill","synth","iconUrl"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Self-diagnosing map errors - the SDK tells you what went wrong and how\n * to fix it, instead of a silently blank map.\n *\n * `MapMapMap` runs these checks at construction (and listens for tile\n * auth failures); each detected issue produces ONE `console.error` per\n * page with an actionable message and a docs link. Everything here is\n * best-effort and defensive: no check may ever throw or require a DOM\n * (server-side rendering and Node tests just skip the DOM checks).\n *\n * Issues covered - the documented gotchas that burn real integrations:\n * - a container whose height resolves to 0px (MapLibre renders into a\n * 0-tall canvas: no error, no map)\n * - a container element that is not attached to the DOM\n * - two maplibre-gl copies on one page (duplicate dependency /\n * micro-frontends - breaks the shared WebGL context and styles)\n * - WebGL unavailable (headless browsers, blocked GPU, old devices)\n * - missing/invalid API key (a 401 from the tile or routing endpoints)\n * - a basemap tiles URL that 404s (the map loads but renders blank)\n */\n\nconst DOCS = \"https://mapmap.ai/docs\";\n\n/** The distinct issues the diagnostics can report. */\nexport type DiagnosticIssue =\n | \"container-zero-height\"\n | \"container-detached\"\n | \"duplicate-maplibre\"\n | \"webgl-unavailable\"\n | \"invalid-api-key\"\n | \"basemap-not-found\";\n\n/** Issues already reported on this page: one console.error per issue. */\nconst reported = new Set<DiagnosticIssue>();\n\n/**\n * Cross-module registry of maplibre-gl module instances seen on this\n * page. `Symbol.for` + `globalThis` so the registry is shared even when\n * this SDK itself is bundled twice.\n */\nconst MAPLIBRE_REGISTRY_KEY = Symbol.for(\"mapmap.maplibre-instances\");\n\n/** Reset the once-per-page dedup - for tests (and hot-reload tooling). */\nexport function resetDiagnostics(): void {\n reported.clear();\n const holder = globalThis as Record<symbol, unknown>;\n delete holder[MAPLIBRE_REGISTRY_KEY];\n}\n\nfunction report(issue: DiagnosticIssue, message: string): void {\n if (reported.has(issue)) return;\n reported.add(issue);\n console.error(`MapMap [${issue}]: ${message}`);\n}\n\n/** What `runMapDiagnostics` needs; everything optional and structural. */\nexport interface MapDiagnosticsInput {\n /** The `container` option as given: an element or an element id. */\n container?: string | HTMLElement;\n /**\n * The constructed map (or any object with a MapLibre-style `on`). Used\n * to watch for tile-request auth failures.\n */\n map?: unknown;\n /** The maplibre-gl module the SDK is using (duplicate detection). */\n maplibre?: unknown;\n /** The gateway API key, if one was configured. */\n apiKey?: string | undefined;\n}\n\n/** A MapLibre `error` event, structurally. */\ninterface MapErrorEvent {\n error?: { status?: number; message?: string } | undefined;\n /** The source that raised the error, when it came from source loading. */\n sourceId?: string | undefined;\n}\n\n/**\n * Run the construction-time checks and attach the 401 watcher. Called by\n * `MapMapMap` automatically; exported for apps wrapping a raw\n * `maplibregl.Map` that still want the self-diagnosis.\n */\nexport function runMapDiagnostics(input: MapDiagnosticsInput): void {\n checkDuplicateMaplibre(input.maplibre);\n checkWebgl();\n checkContainer(input.container);\n watchForAuthFailures(input.map, input.apiKey);\n}\n\nfunction checkContainer(container: string | HTMLElement | undefined): void {\n if (container === undefined || typeof document === \"undefined\") return;\n let element: HTMLElement | null;\n try {\n element =\n typeof container === \"string\"\n ? document.getElementById(container)\n : container;\n } catch {\n return;\n }\n if (!element) return; // MapLibre throws its own clear error for this\n // Anything that is not element-shaped is MapLibre's problem to reject.\n if (typeof element.isConnected !== \"boolean\") return;\n if (!element.isConnected) {\n report(\n \"container-detached\",\n \"the map container element is not attached to the DOM, so nothing \" +\n \"can render. Append it to the document before constructing the \" +\n `map. ${DOCS}#container`,\n );\n return; // a detached element always measures 0 - skip the height check\n }\n if (element.clientHeight === 0) {\n report(\n \"container-zero-height\",\n \"the map container's height is 0px, so MapLibre is rendering into \" +\n \"an invisible canvas (no error, no map). Give it a real height, \" +\n `e.g. #map { height: 100vh; }. If the height arrives later (CSS ` +\n `load, layout), you can ignore this. ${DOCS}#container-height`,\n );\n }\n}\n\nfunction checkDuplicateMaplibre(maplibre: unknown): void {\n if (typeof maplibre !== \"object\" && typeof maplibre !== \"function\") return;\n if (maplibre === null) return;\n const holder = globalThis as Record<symbol, unknown>;\n const registry = (holder[MAPLIBRE_REGISTRY_KEY] ??=\n new Set<unknown>()) as Set<unknown>;\n registry.add(maplibre);\n // A UMD copy on window that differs from the module copy counts too.\n const windowCopy = (\n globalThis as { maplibregl?: unknown }\n ).maplibregl;\n if (\n windowCopy !== undefined &&\n (typeof windowCopy === \"object\" || typeof windowCopy === \"function\")\n ) {\n registry.add(windowCopy);\n }\n if (registry.size > 1) {\n report(\n \"duplicate-maplibre\",\n \"two different maplibre-gl instances are loaded on this page \" +\n \"(duplicate dependency, a CDN <script> next to the bundled copy, \" +\n \"or micro-frontends). Maps, styles and the pmtiles protocol \" +\n \"registration will not be shared between them. De-duplicate so \" +\n \"the app owns a single maplibre-gl - it is a peerDependency of \" +\n `@mapmap/maps for exactly this reason. ${DOCS}#duplicate-maplibre`,\n );\n }\n}\n\nfunction checkWebgl(): void {\n if (typeof document === \"undefined\") return;\n try {\n const canvas = document.createElement(\"canvas\");\n const gl =\n canvas.getContext(\"webgl2\") ?? canvas.getContext(\"webgl\");\n if (!gl) {\n report(\n \"webgl-unavailable\",\n \"this browser/environment reports no WebGL support, so the map \" +\n \"cannot render. Common causes: headless browsers without \" +\n \"--use-gl, blocked GPU/hardware acceleration, remote desktops. \" +\n `${DOCS}#webgl`,\n );\n }\n } catch {\n /* probe failure is not evidence either way; stay quiet */\n }\n}\n\nfunction watchForAuthFailures(map: unknown, apiKey: string | undefined): void {\n const on = (map as { on?: (event: string, fn: (ev: MapErrorEvent) => void) => void })\n ?.on;\n if (typeof on !== \"function\" || map === null || map === undefined) return;\n try {\n on.call(map, \"error\", (ev: MapErrorEvent) => {\n const status = ev?.error?.status;\n const message = ev?.error?.message ?? \"\";\n\n // A 404 on the basemap tiles source is the classic \"silently blank\n // map\": the style loads fine, MapLibre requests the PMTiles archive,\n // the CDN 404s, and nothing paints. Report it loudly rather than\n // leaving the developer staring at an empty canvas. Scoped to the\n // `territory` source (the basemap) so a missing sprite/glyph 404\n // does not masquerade as a dead basemap.\n const basemapMissing =\n status === 404 &&\n (ev?.sourceId === \"territory\" || /pmtiles|\\.pmtiles/i.test(message));\n if (basemapMissing) {\n report(\n \"basemap-not-found\",\n \"the basemap tiles returned HTTP 404, so the map renders blank. \" +\n \"The territory tiles URL points at a file that does not exist. \" +\n \"Check `territoryTilesUrl` (or your custom `style`) - the default \" +\n \"MapMap tiles are served at the CDN root \" +\n \"(e.g. https://tiles.mapmap.ai/planet.pmtiles), not under a \" +\n `/territories/ prefix. ${DOCS}#tiles`,\n );\n return;\n }\n\n // Only a numeric 401 status or an explicit \"unauthorised\" message\n // counts — a bare \"401\" in message text is as likely to be a tile\n // coordinate (z/x/y) as an HTTP status.\n const unauthorised =\n status === 401 || /unauthori[sz]ed/i.test(message);\n if (!unauthorised) return;\n report(\n \"invalid-api-key\",\n apiKey\n ? \"the gateway rejected your API key (HTTP 401). Check the \" +\n `\\`apiKey\\` for typos or revocation - keys look like ` +\n `\"snk_…\". ${DOCS}#authentication`\n : \"a request was rejected with HTTP 401 and no `apiKey` was \" +\n \"configured. Pass one to the map (`new MapMapMap({ apiKey: \" +\n '\"snk_…\" })`) - issue a free key with ' +\n `POST https://api.mapmap.ai/v1/keys. ${DOCS}#authentication`,\n );\n });\n } catch {\n /* never let diagnostics break map construction */\n }\n}\n","/**\n * Coordinate helpers - pure, browser-free logic.\n *\n * The gateway speaks the OSRM HTTP API: coordinates are `lon,lat` pairs\n * separated by `;`. MapLibre and GeoJSON use `[lng, lat]` order, so the one\n * job here is to normalise the three accepted input shapes into that wire\n * format without ever swapping the axes by accident.\n */\nimport type { LngLatLike } from \"./types.js\";\n\n/** Normalise any accepted shape to a `[lng, lat]` tuple. */\nexport function toLngLat(point: LngLatLike): [number, number] {\n if (Array.isArray(point)) {\n const [lng, lat] = point;\n assertFinite(lng, lat);\n return [lng, lat];\n }\n const lng = \"lng\" in point ? point.lng : point.lon;\n const lat = point.lat;\n assertFinite(lng, lat);\n return [lng, lat];\n}\n\n/** Format one point as an OSRM `lon,lat` coordinate. */\nexport function formatCoord(point: LngLatLike): string {\n const [lng, lat] = toLngLat(point);\n return `${lng},${lat}`;\n}\n\n/**\n * Format an ordered list of points as an OSRM coordinate path\n * (`lon,lat;lon,lat;…`). At least two points are required, matching the\n * gateway, which rejects single-coordinate requests.\n */\nexport function formatCoords(points: LngLatLike[]): string {\n if (points.length < 2) {\n throw new Error(\"at least two coordinates are required for a route\");\n }\n return points.map(formatCoord).join(\";\");\n}\n\n/**\n * Unwrap a line's longitudes onto a continuous range: shift each\n * successive point by ±360° so no consecutive delta exceeds 180°. An\n * antimeridian-crossing line (`…, 179.9, -179.9, …`) then interpolates\n * across the real 0.2° gap instead of spanning the whole world.\n * Latitudes are untouched; unwrapped longitudes may leave [-180, 180],\n * which trigonometric and mercator consumers read as the adjacent world\n * copy (MapLibre's convention).\n */\nexport function unwrapLngs(\n coordinates: [number, number][],\n): [number, number][] {\n const out: [number, number][] = [];\n for (const [lng, lat] of coordinates) {\n const prev = out[out.length - 1];\n let unwrapped = lng;\n if (prev) {\n while (unwrapped - prev[0] > 180) unwrapped -= 360;\n while (unwrapped - prev[0] < -180) unwrapped += 360;\n }\n out.push([unwrapped, lat]);\n }\n return out;\n}\n\nfunction assertFinite(lng: number, lat: number): void {\n if (!Number.isFinite(lng) || !Number.isFinite(lat)) {\n throw new Error(`invalid coordinate: lng=${lng}, lat=${lat}`);\n }\n if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {\n throw new Error(\n `coordinate out of range: lng=${lng} (±180), lat=${lat} (±90) - check lng/lat order`,\n );\n }\n}\n","/**\n * Effects engine - named, geometry-anchored visual effects rendered through\n * MapLibre's stable `CustomLayerInterface` (first-party GLSL, no runtime\n * dependencies). The first effect is `\"flow\"`: an animated energy ribbon\n * along the active route line, drawn as a triangle strip with a flowing\n * pulse gradient driven by a time uniform.\n *\n * Deliberately NOT full-map post-processing: MapLibre has no official\n * post-process hook, so every effect here anchors to geometry and rides the\n * supported custom-layer API. New effects register in {@link ROUTE_EFFECTS}.\n *\n * Accessibility and resilience:\n * - `prefers-reduced-motion: reduce` freezes the ribbon to a static\n * gradient (no animation loop, no repaints).\n * - If WebGL setup for the custom layer fails (shader compile/link, lost\n * context), the effect silently disables itself - the ordinary route\n * line underneath is untouched - and logs a single console warning.\n *\n * The tessellation and colour helpers are pure and unit-tested in Node;\n * only the layer object itself touches WebGL.\n */\nimport type { CustomLayerInterface, Map as MlMap } from \"maplibre-gl\";\nimport { unwrapLngs } from \"./coords.js\";\nimport type { RouteGeometry } from \"./types.js\";\n\n// Kept import-free of route.ts/places.ts on purpose: map.ts imports this\n// module, and both of those import map.ts (cycle), while the pure helpers\n// here must stay loadable in Node without maplibre-gl.\n\n/** MapMap brand signal blue - matches `SIGNAL_BLUE` in route.ts. */\nconst FLOW_COLOUR = \"#3a86ff\";\n\n/** Mean Earth radius in metres (IUGG) - matches places.ts. */\nconst EARTH_RADIUS_M = 6371008.8;\n\n/** Straight-line (haversine) distance between two `[lng, lat]`s, metres. */\nfunction haversineM(a: [number, number], b: [number, number]): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b[1] - a[1]);\n const dLon = rad(b[0] - a[0]);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a[1])) * Math.cos(rad(b[1])) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/** The names the effects registry knows. Grows as effects land. */\nexport type RouteEffectName = \"flow\";\n\n/** Options for the `\"flow\"` route effect (all optional). */\nexport interface RouteFlowOptions {\n /** Ribbon colour (hex or rgb()/rgba()). Defaults to MapMap signal blue. */\n color?: string;\n /** Ribbon width in CSS pixels. Defaults to `10`. */\n width?: number;\n /** Flow speed in pulse cycles per second. Defaults to `0.6`. */\n speed?: number;\n /** MapLibre layer id. Defaults to `\"mapmap-route-effect\"`. */\n id?: string;\n}\n\n/** Floats per ribbon vertex: x, y (mercator), nx, ny (unit normal), progress. */\nexport const RIBBON_FLOATS_PER_VERTEX = 5;\n\n/** A tessellated route ribbon, ready for a `TRIANGLE_STRIP` draw. */\nexport interface RibbonMesh {\n /**\n * Interleaved vertex data, {@link RIBBON_FLOATS_PER_VERTEX} floats per\n * vertex: mercator position, the unit extrusion normal (the shader\n * extrudes `pos + normal * halfWidth`, so width stays zoom-correct\n * without re-tessellating), and progress along the route (0 at the\n * start, 1 at the end - the flowing gradient's coordinate).\n */\n vertices: Float32Array;\n /** Number of vertices (two per route point kept). */\n vertexCount: number;\n}\n\n/**\n * Project a `[lng, lat]` to web-mercator world coordinates in [0, 1]\n * (MapLibre's `MercatorCoordinate` convention: x east, y south).\n */\nexport function lngLatToMercator(lngLat: [number, number]): [number, number] {\n const [lng, lat] = lngLat;\n const x = (lng + 180) / 360;\n const y =\n (1 - Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI) / 360)) / Math.PI) / 2;\n return [x, y];\n}\n\n/**\n * Tessellate a route line into a centreline triangle strip: two vertices\n * per point, each carrying the point's mercator position, a unit extrusion\n * normal (averaged between adjacent segments at joins - a bevel-free miter\n * that slightly thins very sharp corners, which is invisible on a soft\n * glow ribbon), and normalised progress along the line.\n *\n * Pure: no WebGL, no map. Consecutive duplicate points are dropped; fewer\n * than two distinct points yield an empty mesh.\n */\nexport function tessellateRouteRibbon(\n coordinates: [number, number][],\n): RibbonMesh {\n // Unwrap longitudes first so an antimeridian-crossing route projects to\n // adjacent mercator world copies instead of a ribbon spanning the whole\n // world; then project and drop consecutive duplicates (zero-length\n // segments have no direction and would produce NaN normals).\n const points: [number, number][] = [];\n for (const lngLat of unwrapLngs(coordinates)) {\n const p = lngLatToMercator(lngLat);\n const last = points[points.length - 1];\n if (!last || last[0] !== p[0] || last[1] !== p[1]) points.push(p);\n }\n if (points.length < 2) {\n return { vertices: new Float32Array(0), vertexCount: 0 };\n }\n\n // Cumulative mercator distance -> progress 0..1 along the line.\n const cumulative: number[] = [0];\n for (let i = 1; i < points.length; i++) {\n const dx = points[i]![0] - points[i - 1]![0];\n const dy = points[i]![1] - points[i - 1]![1];\n cumulative.push(cumulative[i - 1]! + Math.hypot(dx, dy));\n }\n const total = cumulative[cumulative.length - 1]!;\n\n const vertices = new Float32Array(\n points.length * 2 * RIBBON_FLOATS_PER_VERTEX,\n );\n let out = 0;\n for (let i = 0; i < points.length; i++) {\n const prev = points[i - 1];\n const here = points[i]!;\n const next = points[i + 1];\n // Direction at this point: the segment direction at the ends, the\n // normalised average of both segment directions at interior joins.\n let dirX = 0;\n let dirY = 0;\n if (prev) {\n const len = Math.hypot(here[0] - prev[0], here[1] - prev[1]);\n dirX += (here[0] - prev[0]) / len;\n dirY += (here[1] - prev[1]) / len;\n }\n if (next) {\n const len = Math.hypot(next[0] - here[0], next[1] - here[1]);\n dirX += (next[0] - here[0]) / len;\n dirY += (next[1] - here[1]) / len;\n }\n const dirLen = Math.hypot(dirX, dirY);\n // A perfect 180-degree switchback averages to zero; fall back to the\n // incoming segment's direction.\n if (dirLen < 1e-12 && prev) {\n const len = Math.hypot(here[0] - prev[0], here[1] - prev[1]);\n dirX = (here[0] - prev[0]) / len;\n dirY = (here[1] - prev[1]) / len;\n } else {\n dirX /= dirLen;\n dirY /= dirLen;\n }\n // Left-hand unit normal to the direction of travel.\n const nx = -dirY;\n const ny = dirX;\n const progress = total > 0 ? cumulative[i]! / total : 0;\n // Two strip vertices: one extruded each side of the centreline.\n for (const side of [1, -1]) {\n vertices[out++] = here[0];\n vertices[out++] = here[1];\n vertices[out++] = nx * side;\n vertices[out++] = ny * side;\n vertices[out++] = progress;\n }\n }\n return { vertices, vertexCount: points.length * 2 };\n}\n\n/**\n * Parse a CSS colour to premultiplication-ready `[r, g, b, a]` (0-1\n * channels). Supports the hex forms and `rgb()`/`rgba()`; anything else\n * (named colours, `hsl()`) returns `undefined` and the caller falls back\n * to the default - this runs where no canvas is guaranteed, so no\n * browser colour parser is available.\n */\nexport function parseCssColour(\n colour: string,\n): [number, number, number, number] | undefined {\n const v = colour.trim();\n if (v.startsWith(\"#\")) {\n const hex = v.slice(1);\n if (!/^[0-9a-fA-F]+$/.test(hex)) return undefined;\n if (hex.length === 3 || hex.length === 4) {\n const parts = hex.split(\"\").map((c) => parseInt(c + c, 16) / 255);\n const [r, g, b, a] = parts;\n if (r === undefined || g === undefined || b === undefined) return undefined;\n return [r, g, b, a ?? 1];\n }\n if (hex.length === 6 || hex.length === 8) {\n const chan = (i: number): number =>\n parseInt(hex.slice(i, i + 2), 16) / 255;\n return [chan(0), chan(2), chan(4), hex.length === 8 ? chan(6) : 1];\n }\n return undefined;\n }\n const fn = /^rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*(?:,\\s*([\\d.]+)\\s*)?\\)$/.exec(v);\n if (fn) {\n const r = Number(fn[1]) / 255;\n const g = Number(fn[2]) / 255;\n const b = Number(fn[3]) / 255;\n const a = fn[4] !== undefined ? Number(fn[4]) : 1;\n if ([r, g, b, a].some((c) => !Number.isFinite(c) || c < 0 || c > 1)) {\n return undefined;\n }\n return [r, g, b, a];\n }\n return undefined;\n}\n\n/** Whether the user has asked for reduced motion. Safe without a DOM. */\nexport function prefersReducedMotion(): boolean {\n if (typeof matchMedia !== \"function\") return false;\n try {\n return matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n } catch {\n return false;\n }\n}\n\nconst VERTEX_SHADER = `\nuniform mat4 u_matrix;\nuniform float u_half_width;\nattribute vec2 a_pos;\nattribute vec2 a_normal;\nattribute float a_progress;\nvarying float v_progress;\nvoid main() {\n v_progress = a_progress;\n gl_Position = u_matrix * vec4(a_pos + a_normal * u_half_width, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `\nprecision mediump float;\nuniform vec4 u_color;\nuniform float u_phase;\nuniform float u_repeats;\nvarying float v_progress;\nvoid main() {\n float t = fract(v_progress * u_repeats - u_phase);\n // A soft comet: rises quickly, decays slowly, never fully dark so the\n // ribbon always traces the route.\n float pulse = smoothstep(0.0, 0.25, t) * (1.0 - smoothstep(0.35, 1.0, t));\n float energy = 0.25 + 0.75 * pulse;\n float alpha = u_color.a * energy;\n // Premultiplied alpha, matching MapLibre's framebuffer convention.\n gl_FragColor = vec4(u_color.rgb * alpha, alpha);\n}\n`;\n\n/** Warned-once flag for WebGL setup failures (one line per page, not per frame). */\nlet warnedWebglFailure = false;\n\n/** Test-only reset for the warn-once flag. */\nexport function resetEffectsWarnings(): void {\n warnedWebglFailure = false;\n}\n\n/** Default flow parameters (exported so docs/tests state one truth). */\nexport const FLOW_DEFAULTS = {\n color: FLOW_COLOUR,\n width: 10,\n speed: 0.6,\n} as const;\n\n/** World size in pixels at a zoom, for the pixel->mercator width scale. */\nfunction mercatorUnitsPerPixel(zoom: number): number {\n return 1 / (512 * 2 ** zoom);\n}\n\n/**\n * Great-circle length of a route in metres (drives how many flow pulses\n * fit along it, so short and long routes animate at a similar density).\n */\nfunction routeLengthM(coordinates: [number, number][]): number {\n let length = 0;\n for (let i = 1; i < coordinates.length; i++) {\n length += haversineM(coordinates[i - 1]!, coordinates[i]!);\n }\n return length;\n}\n\n/**\n * A MapLibre custom layer (`CustomLayerInterface`) drawing the flowing\n * route ribbon. Construct via {@link createRouteEffect} (the registry) or\n * use `MapMapMap.setRouteEffect(\"flow\")`, which manages the lifecycle.\n */\nexport class FlowRouteEffectLayer implements CustomLayerInterface {\n readonly id: string;\n readonly type = \"custom\" as const;\n readonly renderingMode = \"2d\" as const;\n\n private geometry: RouteGeometry;\n private readonly colour: [number, number, number, number];\n private readonly widthPx: number;\n private readonly speed: number;\n private readonly animate: boolean;\n\n private mapRef: MlMap | undefined;\n private glRef: WebGLRenderingContext | WebGL2RenderingContext | undefined;\n private program: WebGLProgram | null = null;\n private buffer: WebGLBuffer | null = null;\n private vertexCount = 0;\n private repeats = 8;\n private startedAt = 0;\n private failed = false;\n private aPos = 0;\n private aNormal = 0;\n private aProgress = 0;\n private uMatrix: WebGLUniformLocation | null = null;\n private uHalfWidth: WebGLUniformLocation | null = null;\n private uColor: WebGLUniformLocation | null = null;\n private uPhase: WebGLUniformLocation | null = null;\n private uRepeats: WebGLUniformLocation | null = null;\n\n constructor(geometry: RouteGeometry, options: RouteFlowOptions = {}) {\n this.id = options.id ?? \"mapmap-route-effect\";\n this.geometry = geometry;\n this.colour =\n (options.color !== undefined ? parseCssColour(options.color) : undefined) ??\n (parseCssColour(FLOW_DEFAULTS.color) as [number, number, number, number]);\n this.widthPx = options.width ?? FLOW_DEFAULTS.width;\n this.speed = options.speed ?? FLOW_DEFAULTS.speed;\n // Reduced motion: keep the ribbon (a static gradient still marks the\n // route) but freeze the phase and never request repaints.\n this.animate = !prefersReducedMotion();\n }\n\n /** Swap the ribbon onto a new route line (e.g. after a reroute). */\n setGeometry(geometry: RouteGeometry): void {\n this.geometry = geometry;\n if (this.glRef && !this.failed) this.upload(this.glRef);\n this.mapRef?.triggerRepaint();\n }\n\n onAdd(map: MlMap, gl: WebGLRenderingContext | WebGL2RenderingContext): void {\n this.mapRef = map;\n this.glRef = gl;\n this.startedAt = now();\n try {\n const program = gl.createProgram();\n if (!program) throw new Error(\"createProgram returned null\");\n for (const [kind, source] of [\n [gl.VERTEX_SHADER, VERTEX_SHADER],\n [gl.FRAGMENT_SHADER, FRAGMENT_SHADER],\n ] as const) {\n const shader = gl.createShader(kind);\n if (!shader) throw new Error(\"createShader returned null\");\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error(gl.getShaderInfoLog(shader) ?? \"shader compile failed\");\n }\n gl.attachShader(program, shader);\n }\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(gl.getProgramInfoLog(program) ?? \"program link failed\");\n }\n this.program = program;\n this.aPos = gl.getAttribLocation(program, \"a_pos\");\n this.aNormal = gl.getAttribLocation(program, \"a_normal\");\n this.aProgress = gl.getAttribLocation(program, \"a_progress\");\n this.uMatrix = gl.getUniformLocation(program, \"u_matrix\");\n this.uHalfWidth = gl.getUniformLocation(program, \"u_half_width\");\n this.uColor = gl.getUniformLocation(program, \"u_color\");\n this.uPhase = gl.getUniformLocation(program, \"u_phase\");\n this.uRepeats = gl.getUniformLocation(program, \"u_repeats\");\n this.upload(gl);\n } catch (error) {\n // Static fallback: the plain route line underneath is untouched;\n // the ribbon simply never draws. One warning per page.\n this.failed = true;\n if (!warnedWebglFailure) {\n warnedWebglFailure = true;\n console.warn(\n `MapMap: route effect \"flow\" disabled (WebGL setup failed: ` +\n `${error instanceof Error ? error.message : String(error)}). ` +\n \"Falling back to the plain route line.\",\n );\n }\n }\n }\n\n onRemove(\n _map: MlMap,\n gl: WebGLRenderingContext | WebGL2RenderingContext,\n ): void {\n if (this.buffer) gl.deleteBuffer(this.buffer);\n if (this.program) gl.deleteProgram(this.program);\n this.buffer = null;\n this.program = null;\n this.mapRef = undefined;\n this.glRef = undefined;\n }\n\n render(gl: WebGLRenderingContext | WebGL2RenderingContext, args: unknown): void {\n if (this.failed || !this.program || !this.buffer || this.vertexCount < 3) {\n return;\n }\n const matrix = projectionMatrixOf(args);\n if (!matrix || !this.mapRef) return;\n\n gl.useProgram(this.program);\n gl.uniformMatrix4fv(this.uMatrix, false, matrix);\n const halfWidth =\n (this.widthPx / 2) * mercatorUnitsPerPixel(this.mapRef.getZoom());\n gl.uniform1f(this.uHalfWidth, halfWidth);\n gl.uniform4f(this.uColor, ...this.colour);\n const phase = this.animate\n ? ((now() - this.startedAt) / 1000) * this.speed % 1\n : 0;\n gl.uniform1f(this.uPhase, phase);\n gl.uniform1f(this.uRepeats, this.repeats);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n const stride = RIBBON_FLOATS_PER_VERTEX * 4;\n gl.enableVertexAttribArray(this.aPos);\n gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);\n gl.enableVertexAttribArray(this.aNormal);\n gl.vertexAttribPointer(this.aNormal, 2, gl.FLOAT, false, stride, 8);\n gl.enableVertexAttribArray(this.aProgress);\n gl.vertexAttribPointer(this.aProgress, 1, gl.FLOAT, false, stride, 16);\n\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); // premultiplied alpha\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.vertexCount);\n\n if (this.animate) this.mapRef.triggerRepaint();\n }\n\n private upload(gl: WebGLRenderingContext | WebGL2RenderingContext): void {\n const mesh = tessellateRouteRibbon(this.geometry.coordinates);\n this.vertexCount = mesh.vertexCount;\n // Pulse density scales with route length: one pulse roughly every\n // 500 m, clamped so a short hop still flows and a long haul doesn't\n // strobe.\n this.repeats = Math.min(\n 80,\n Math.max(2, Math.round(routeLengthM(this.geometry.coordinates) / 500)),\n );\n if (!this.buffer) this.buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n gl.bufferData(gl.ARRAY_BUFFER, mesh.vertices, gl.STATIC_DRAW);\n }\n}\n\n/** Monotonic-ish clock that works in browsers and Node tests. */\nfunction now(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n}\n\n/**\n * The main projection matrix out of a custom layer `render` argument:\n * MapLibre v4 passes the matrix itself, v5 passes an args object carrying\n * `defaultProjectionData.mainMatrix`.\n */\nfunction projectionMatrixOf(args: unknown): Float32Array | number[] | undefined {\n if (Array.isArray(args)) return args as number[];\n if (args instanceof Float32Array || args instanceof Float64Array) {\n return args instanceof Float64Array ? new Float32Array(args) : args;\n }\n if (typeof args === \"object\" && args !== null) {\n const data = (args as { defaultProjectionData?: { mainMatrix?: unknown } })\n .defaultProjectionData;\n const main = data?.mainMatrix;\n if (Array.isArray(main)) return main as number[];\n if (main instanceof Float32Array) return main;\n if (main instanceof Float64Array) return new Float32Array(main);\n }\n return undefined;\n}\n\n/** A route effect layer: a custom layer that can retarget its geometry. */\nexport interface RouteEffectLayer extends CustomLayerInterface {\n setGeometry(geometry: RouteGeometry): void;\n}\n\n/**\n * The effect registry: name -> layer factory. New effects (ambient life,\n * seasonal snow, fog-of-exploration) add an entry here and a name to\n * {@link RouteEffectName}.\n */\nexport const ROUTE_EFFECTS: Record<\n RouteEffectName,\n (geometry: RouteGeometry, options?: RouteFlowOptions) => RouteEffectLayer\n> = {\n flow: (geometry, options) => new FlowRouteEffectLayer(geometry, options),\n};\n\n/**\n * Create a named route effect layer. Throws an agent-readable error for\n * unknown names (the accepted list included).\n */\nexport function createRouteEffect(\n name: RouteEffectName,\n geometry: RouteGeometry,\n options?: RouteFlowOptions,\n): RouteEffectLayer {\n const factory = ROUTE_EFFECTS[name];\n if (!factory) {\n throw new Error(\n `unknown route effect ${JSON.stringify(name)}; accepted effects: ` +\n Object.keys(ROUTE_EFFECTS).join(\", \"),\n );\n }\n return factory(geometry, options);\n}\n","/**\n * The MapMap logo control: a small wordmark on the map, the same\n * convention as Google Maps' and Mapbox's marks. On by default in\n * {@link MapMapMap}; positionable, and removable with `logo: false`\n * (attribution itself is separate and never removable).\n *\n * The mark is an inline SVG (no network fetch, works offline and under\n * strict CSPs): the MapMap brand lockup — the three-colour route mark\n * plus the lowercase wordmark. Height stays at 20px so existing layouts\n * hold.\n */\n\n/** Corner positions accepted by the logo control. */\nexport type LogoPosition = \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\";\n\n/** Options for {@link LogoControl}. */\nexport interface LogoOptions {\n /** Corner to render in. Default `bottom-right`, above the attribution. */\n position?: LogoPosition;\n /** Link target when clicked. Default the MapMap site. */\n href?: string;\n}\n\n/**\n * The inline wordmark (height 20px): the outline-light lockup — the\n * line-art route mark plus the dark wordmark — over a white halo stroke\n * so it stays legible on any base map.\n */\nexport const LOGO_SVG =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"85\" height=\"20\" viewBox=\"0 0 156 37\" fill=\"none\" role=\"img\" aria-label=\"MapMap\"><g stroke=\"#ffffff\" stroke-linejoin=\"round\" stroke-linecap=\"round\"><path d=\"M138.576 33.2887V11.4951H142.24V14.1161H142.456C142.649 13.7308 142.92 13.3215 143.269 12.8881C143.619 12.4479 144.093 12.0729 144.69 11.7634C145.287 11.4469 146.048 11.2887 146.975 11.2887C148.196 11.2887 149.297 11.6017 150.279 12.2277C151.267 12.8469 152.049 13.7652 152.625 14.9829C153.209 16.1936 153.5 17.6796 153.5 19.4407C153.5 21.1811 153.215 22.6602 152.646 23.8778C152.076 25.0955 151.301 26.0242 150.32 26.6639C149.339 27.3037 148.227 27.6236 146.985 27.6236C146.079 27.6236 145.328 27.4722 144.731 27.1696C144.134 26.8669 143.654 26.5023 143.29 26.0757C142.933 25.6424 142.655 25.233 142.456 24.8478H142.302V33.2887H138.576ZM142.23 19.42C142.23 20.445 142.374 21.3428 142.662 22.1133C142.957 22.8838 143.379 23.4857 143.928 23.9191C144.484 24.3456 145.156 24.5589 145.946 24.5589C146.769 24.5589 147.458 24.3387 148.014 23.8985C148.57 23.4513 148.989 22.8425 149.27 22.072C149.558 21.2946 149.702 20.4106 149.702 19.42C149.702 18.4363 149.562 17.5626 149.28 16.799C148.999 16.0354 148.58 15.4369 148.025 15.0035C147.469 14.5701 146.776 14.3534 145.946 14.3534C145.15 14.3534 144.474 14.5632 143.918 14.9829C143.362 15.4025 142.94 15.9907 142.652 16.7474C142.371 17.5041 142.23 18.395 142.23 19.42Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M127.352 27.6649C126.35 27.6649 125.448 27.486 124.645 27.1283C123.849 26.7637 123.218 26.2271 122.751 25.5185C122.291 24.81 122.062 23.9363 122.062 22.8975C122.062 22.0032 122.226 21.2637 122.556 20.6789C122.885 20.0942 123.334 19.6264 123.904 19.2756C124.473 18.9247 125.115 18.6599 125.829 18.481C126.549 18.2953 127.293 18.1611 128.062 18.0786C128.988 17.9823 129.74 17.8963 130.316 17.8206C130.892 17.738 131.311 17.6142 131.572 17.4491C131.839 17.2771 131.973 17.0123 131.973 16.6545V16.5926C131.973 15.8153 131.743 15.2133 131.284 14.7868C130.824 14.3603 130.162 14.147 129.297 14.147C128.384 14.147 127.661 14.3465 127.125 14.7455C126.597 15.1445 126.24 15.6158 126.055 16.1592L122.576 15.6639C122.851 14.7008 123.303 13.896 123.935 13.2493C124.566 12.5958 125.338 12.1073 126.251 11.784C127.163 11.4538 128.172 11.2887 129.276 11.2887C130.038 11.2887 130.796 11.3781 131.551 11.557C132.306 11.7359 132.995 12.0317 133.62 12.4444C134.244 12.8503 134.745 13.4041 135.123 14.1058C135.507 14.8075 135.699 15.6846 135.699 16.7371V27.345H132.117V25.1677H131.994C131.767 25.608 131.448 26.0207 131.036 26.406C130.632 26.7843 130.12 27.0904 129.503 27.3243C128.892 27.5514 128.175 27.6649 127.352 27.6649ZM128.319 24.92C129.067 24.92 129.716 24.7721 130.265 24.4763C130.813 24.1736 131.235 23.7746 131.531 23.2793C131.832 22.784 131.983 22.244 131.983 21.6592V19.7915C131.867 19.8878 131.668 19.9773 131.386 20.0598C131.112 20.1424 130.803 20.2146 130.46 20.2765C130.117 20.3384 129.777 20.3934 129.441 20.4416C129.105 20.4898 128.813 20.531 128.566 20.5654C128.011 20.6411 127.513 20.7649 127.074 20.9369C126.635 21.1089 126.288 21.3497 126.034 21.6592C125.781 21.9619 125.654 22.354 125.654 22.8356C125.654 23.5235 125.904 24.0429 126.405 24.3938C126.906 24.7446 127.544 24.92 128.319 24.92Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M97.6602 27.345V11.4951H101.221V14.1883H101.407C101.736 13.2803 102.281 12.5717 103.043 12.0626C103.805 11.5467 104.714 11.2887 105.771 11.2887C106.841 11.2887 107.743 11.5501 108.477 12.0729C109.219 12.5889 109.74 13.294 110.042 14.1883H110.207C110.557 13.3078 111.147 12.6061 111.977 12.0833C112.814 11.5535 113.805 11.2887 114.951 11.2887C116.406 11.2887 117.593 11.7496 118.513 12.6714C119.432 13.5933 119.892 14.9382 119.892 16.7061V27.345H116.156V17.284C116.156 16.3003 115.895 15.5814 115.373 15.1273C114.852 14.6664 114.214 14.436 113.459 14.436C112.56 14.436 111.857 14.718 111.349 15.2821C110.848 15.8394 110.598 16.5651 110.598 17.4594V27.345H106.944V17.1292C106.944 16.3106 106.697 15.6571 106.203 15.1686C105.716 14.6802 105.078 14.436 104.288 14.436C103.753 14.436 103.266 14.5736 102.827 14.8487C102.388 15.117 102.038 15.4988 101.777 15.9941C101.516 16.4826 101.386 17.0535 101.386 17.7071V27.345H97.6602Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M80.416 33.2887V11.4951H84.0801V14.1161H84.2962C84.4884 13.7308 84.7594 13.3215 85.1093 12.8881C85.4593 12.4479 85.9327 12.0729 86.5297 11.7634C87.1267 11.4469 87.8883 11.2887 88.8146 11.2887C90.036 11.2887 91.1373 11.6017 92.1185 12.2277C93.1065 12.8469 93.8888 13.7652 94.4651 14.9829C95.0484 16.1936 95.34 17.6796 95.34 19.4407C95.34 21.1811 95.0552 22.6602 94.4857 23.8778C93.9162 25.0955 93.1408 26.0242 92.1596 26.6639C91.1784 27.3037 90.0668 27.6236 88.8249 27.6236C87.9192 27.6236 87.1678 27.4722 86.5709 27.1696C85.9739 26.8669 85.4936 26.5023 85.1299 26.0757C84.7731 25.6424 84.4952 25.233 84.2962 24.8478H84.1419V33.2887H80.416ZM84.0698 19.42C84.0698 20.445 84.2139 21.3428 84.5021 22.1133C84.7971 22.8838 85.2191 23.4857 85.7681 23.9191C86.3238 24.3456 86.9963 24.5589 87.7854 24.5589C88.6088 24.5589 89.2983 24.3387 89.8541 23.8985C90.4099 23.4513 90.8285 22.8425 91.1098 22.072C91.398 21.2946 91.5421 20.4106 91.5421 19.42C91.5421 18.4363 91.4014 17.5626 91.1201 16.799C90.8388 16.0354 90.4202 15.4369 89.8644 15.0035C89.3086 14.5701 88.6156 14.3534 87.7854 14.3534C86.9894 14.3534 86.3136 14.5632 85.7578 14.9829C85.202 15.4025 84.78 15.9907 84.4918 16.7474C84.2105 17.5041 84.0698 18.395 84.0698 19.42Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M69.1921 27.6649C68.1904 27.6649 67.2881 27.486 66.4852 27.1283C65.6893 26.7637 65.058 26.2271 64.5914 25.5185C64.1317 24.81 63.9019 23.9363 63.9019 22.8975C63.9019 22.0032 64.0665 21.2637 64.3959 20.6789C64.7252 20.0942 65.1747 19.6264 65.7442 19.2756C66.3137 18.9247 66.9553 18.6599 67.6689 18.481C68.3893 18.2953 69.1338 18.1611 69.9023 18.0786C70.8286 17.9823 71.58 17.8963 72.1564 17.8206C72.7327 17.738 73.1513 17.6142 73.412 17.4491C73.6796 17.2771 73.8134 17.0123 73.8134 16.6545V16.5926C73.8134 15.8153 73.5836 15.2133 73.1238 14.7868C72.6641 14.3603 72.002 14.147 71.1374 14.147C70.2248 14.147 69.5009 14.3465 68.9657 14.7455C68.4374 15.1445 68.0806 15.6158 67.8953 16.1592L64.4165 15.6639C64.6909 14.7008 65.1438 13.896 65.7751 13.2493C66.4063 12.5958 67.1783 12.1073 68.0909 11.784C69.0034 11.4538 70.0121 11.2887 71.1168 11.2887C71.8785 11.2887 72.6367 11.3781 73.3914 11.557C74.1462 11.7359 74.8358 12.0317 75.4602 12.4444C76.0846 12.8503 76.5855 13.4041 76.9629 14.1058C77.3471 14.8075 77.5393 15.6846 77.5393 16.7371V27.345H73.9575V25.1677H73.834C73.6076 25.608 73.2885 26.0207 72.8768 26.406C72.472 26.7843 71.9608 27.0904 71.3433 27.3243C70.7326 27.5514 70.0155 27.6649 69.1921 27.6649ZM70.1596 24.92C70.9075 24.92 71.556 24.7721 72.1049 24.4763C72.6538 24.1736 73.0758 23.7746 73.3709 23.2793C73.6728 22.784 73.8237 22.244 73.8237 21.6592V19.7915C73.7071 19.8878 73.5081 19.9773 73.2268 20.0598C72.9523 20.1424 72.6435 20.2146 72.3004 20.2765C71.9574 20.3384 71.6177 20.3934 71.2815 20.4416C70.9453 20.4898 70.6537 20.531 70.4066 20.5654C69.8509 20.6411 69.3534 20.7649 68.9143 20.9369C68.4751 21.1089 68.1286 21.3497 67.8747 21.6592C67.6208 21.9619 67.4939 22.354 67.4939 22.8356C67.4939 23.5235 67.7443 24.0429 68.2452 24.3938C68.7461 24.7446 69.3843 24.92 70.1596 24.92Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M39.5 27.345V11.4951H43.0612V14.1883H43.2464C43.5758 13.2803 44.1213 12.5717 44.8829 12.0626C45.6446 11.5467 46.5537 11.2887 47.6104 11.2887C48.6808 11.2887 49.5831 11.5501 50.3173 12.0729C51.0584 12.5889 51.5798 13.294 51.8817 14.1883H52.0464C52.3964 13.3078 52.9865 12.6061 53.8167 12.0833C54.6538 11.5535 55.6453 11.2887 56.7912 11.2887C58.2459 11.2887 59.4329 11.7496 60.3524 12.6714C61.2718 13.5933 61.7316 14.9382 61.7316 16.7061V27.345H57.9954V17.284C57.9954 16.3003 57.7347 15.5814 57.2132 15.1273C56.6917 14.6664 56.0536 14.436 55.2988 14.436C54.3999 14.436 53.6966 14.718 53.1889 15.2821C52.688 15.8394 52.4375 16.5651 52.4375 17.4594V27.345H48.7837V17.1292C48.7837 16.3106 48.5367 15.6571 48.0427 15.1686C47.5555 14.6802 46.9174 14.436 46.1283 14.436C45.5931 14.436 45.1059 14.5736 44.6668 14.8487C44.2276 15.117 43.8777 15.4988 43.617 15.9941C43.3562 16.4826 43.2258 17.0535 43.2258 17.7071V27.345H39.5Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke-width=\"4.96\"/><path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke-width=\"4.96\"/><path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke-width=\"4.96\"/></g><path d=\"M138.576 33.2887V11.4951H142.24V14.1161H142.456C142.649 13.7308 142.92 13.3215 143.269 12.8881C143.619 12.4479 144.093 12.0729 144.69 11.7634C145.287 11.4469 146.048 11.2887 146.975 11.2887C148.196 11.2887 149.297 11.6017 150.279 12.2277C151.267 12.8469 152.049 13.7652 152.625 14.9829C153.209 16.1936 153.5 17.6796 153.5 19.4407C153.5 21.1811 153.215 22.6602 152.646 23.8778C152.076 25.0955 151.301 26.0242 150.32 26.6639C149.339 27.3037 148.227 27.6236 146.985 27.6236C146.079 27.6236 145.328 27.4722 144.731 27.1696C144.134 26.8669 143.654 26.5023 143.29 26.0757C142.933 25.6424 142.655 25.233 142.456 24.8478H142.302V33.2887H138.576ZM142.23 19.42C142.23 20.445 142.374 21.3428 142.662 22.1133C142.957 22.8838 143.379 23.4857 143.928 23.9191C144.484 24.3456 145.156 24.5589 145.946 24.5589C146.769 24.5589 147.458 24.3387 148.014 23.8985C148.57 23.4513 148.989 22.8425 149.27 22.072C149.558 21.2946 149.702 20.4106 149.702 19.42C149.702 18.4363 149.562 17.5626 149.28 16.799C148.999 16.0354 148.58 15.4369 148.025 15.0035C147.469 14.5701 146.776 14.3534 145.946 14.3534C145.15 14.3534 144.474 14.5632 143.918 14.9829C143.362 15.4025 142.94 15.9907 142.652 16.7474C142.371 17.5041 142.23 18.395 142.23 19.42Z\" fill=\"#26282A\"/><path d=\"M127.352 27.6649C126.35 27.6649 125.448 27.486 124.645 27.1283C123.849 26.7637 123.218 26.2271 122.751 25.5185C122.291 24.81 122.062 23.9363 122.062 22.8975C122.062 22.0032 122.226 21.2637 122.556 20.6789C122.885 20.0942 123.334 19.6264 123.904 19.2756C124.473 18.9247 125.115 18.6599 125.829 18.481C126.549 18.2953 127.293 18.1611 128.062 18.0786C128.988 17.9823 129.74 17.8963 130.316 17.8206C130.892 17.738 131.311 17.6142 131.572 17.4491C131.839 17.2771 131.973 17.0123 131.973 16.6545V16.5926C131.973 15.8153 131.743 15.2133 131.284 14.7868C130.824 14.3603 130.162 14.147 129.297 14.147C128.384 14.147 127.661 14.3465 127.125 14.7455C126.597 15.1445 126.24 15.6158 126.055 16.1592L122.576 15.6639C122.851 14.7008 123.303 13.896 123.935 13.2493C124.566 12.5958 125.338 12.1073 126.251 11.784C127.163 11.4538 128.172 11.2887 129.276 11.2887C130.038 11.2887 130.796 11.3781 131.551 11.557C132.306 11.7359 132.995 12.0317 133.62 12.4444C134.244 12.8503 134.745 13.4041 135.123 14.1058C135.507 14.8075 135.699 15.6846 135.699 16.7371V27.345H132.117V25.1677H131.994C131.767 25.608 131.448 26.0207 131.036 26.406C130.632 26.7843 130.12 27.0904 129.503 27.3243C128.892 27.5514 128.175 27.6649 127.352 27.6649ZM128.319 24.92C129.067 24.92 129.716 24.7721 130.265 24.4763C130.813 24.1736 131.235 23.7746 131.531 23.2793C131.832 22.784 131.983 22.244 131.983 21.6592V19.7915C131.867 19.8878 131.668 19.9773 131.386 20.0598C131.112 20.1424 130.803 20.2146 130.46 20.2765C130.117 20.3384 129.777 20.3934 129.441 20.4416C129.105 20.4898 128.813 20.531 128.566 20.5654C128.011 20.6411 127.513 20.7649 127.074 20.9369C126.635 21.1089 126.288 21.3497 126.034 21.6592C125.781 21.9619 125.654 22.354 125.654 22.8356C125.654 23.5235 125.904 24.0429 126.405 24.3938C126.906 24.7446 127.544 24.92 128.319 24.92Z\" fill=\"#26282A\"/><path d=\"M97.6602 27.345V11.4951H101.221V14.1883H101.407C101.736 13.2803 102.281 12.5717 103.043 12.0626C103.805 11.5467 104.714 11.2887 105.771 11.2887C106.841 11.2887 107.743 11.5501 108.477 12.0729C109.219 12.5889 109.74 13.294 110.042 14.1883H110.207C110.557 13.3078 111.147 12.6061 111.977 12.0833C112.814 11.5535 113.805 11.2887 114.951 11.2887C116.406 11.2887 117.593 11.7496 118.513 12.6714C119.432 13.5933 119.892 14.9382 119.892 16.7061V27.345H116.156V17.284C116.156 16.3003 115.895 15.5814 115.373 15.1273C114.852 14.6664 114.214 14.436 113.459 14.436C112.56 14.436 111.857 14.718 111.349 15.2821C110.848 15.8394 110.598 16.5651 110.598 17.4594V27.345H106.944V17.1292C106.944 16.3106 106.697 15.6571 106.203 15.1686C105.716 14.6802 105.078 14.436 104.288 14.436C103.753 14.436 103.266 14.5736 102.827 14.8487C102.388 15.117 102.038 15.4988 101.777 15.9941C101.516 16.4826 101.386 17.0535 101.386 17.7071V27.345H97.6602Z\" fill=\"#26282A\"/><path d=\"M80.416 33.2887V11.4951H84.0801V14.1161H84.2962C84.4884 13.7308 84.7594 13.3215 85.1093 12.8881C85.4593 12.4479 85.9327 12.0729 86.5297 11.7634C87.1267 11.4469 87.8883 11.2887 88.8146 11.2887C90.036 11.2887 91.1373 11.6017 92.1185 12.2277C93.1065 12.8469 93.8888 13.7652 94.4651 14.9829C95.0484 16.1936 95.34 17.6796 95.34 19.4407C95.34 21.1811 95.0552 22.6602 94.4857 23.8778C93.9162 25.0955 93.1408 26.0242 92.1596 26.6639C91.1784 27.3037 90.0668 27.6236 88.8249 27.6236C87.9192 27.6236 87.1678 27.4722 86.5709 27.1696C85.9739 26.8669 85.4936 26.5023 85.1299 26.0757C84.7731 25.6424 84.4952 25.233 84.2962 24.8478H84.1419V33.2887H80.416ZM84.0698 19.42C84.0698 20.445 84.2139 21.3428 84.5021 22.1133C84.7971 22.8838 85.2191 23.4857 85.7681 23.9191C86.3238 24.3456 86.9963 24.5589 87.7854 24.5589C88.6088 24.5589 89.2983 24.3387 89.8541 23.8985C90.4099 23.4513 90.8285 22.8425 91.1098 22.072C91.398 21.2946 91.5421 20.4106 91.5421 19.42C91.5421 18.4363 91.4014 17.5626 91.1201 16.799C90.8388 16.0354 90.4202 15.4369 89.8644 15.0035C89.3086 14.5701 88.6156 14.3534 87.7854 14.3534C86.9894 14.3534 86.3136 14.5632 85.7578 14.9829C85.202 15.4025 84.78 15.9907 84.4918 16.7474C84.2105 17.5041 84.0698 18.395 84.0698 19.42Z\" fill=\"#26282A\"/><path d=\"M69.1921 27.6649C68.1904 27.6649 67.2881 27.486 66.4852 27.1283C65.6893 26.7637 65.058 26.2271 64.5914 25.5185C64.1317 24.81 63.9019 23.9363 63.9019 22.8975C63.9019 22.0032 64.0665 21.2637 64.3959 20.6789C64.7252 20.0942 65.1747 19.6264 65.7442 19.2756C66.3137 18.9247 66.9553 18.6599 67.6689 18.481C68.3893 18.2953 69.1338 18.1611 69.9023 18.0786C70.8286 17.9823 71.58 17.8963 72.1564 17.8206C72.7327 17.738 73.1513 17.6142 73.412 17.4491C73.6796 17.2771 73.8134 17.0123 73.8134 16.6545V16.5926C73.8134 15.8153 73.5836 15.2133 73.1238 14.7868C72.6641 14.3603 72.002 14.147 71.1374 14.147C70.2248 14.147 69.5009 14.3465 68.9657 14.7455C68.4374 15.1445 68.0806 15.6158 67.8953 16.1592L64.4165 15.6639C64.6909 14.7008 65.1438 13.896 65.7751 13.2493C66.4063 12.5958 67.1783 12.1073 68.0909 11.784C69.0034 11.4538 70.0121 11.2887 71.1168 11.2887C71.8785 11.2887 72.6367 11.3781 73.3914 11.557C74.1462 11.7359 74.8358 12.0317 75.4602 12.4444C76.0846 12.8503 76.5855 13.4041 76.9629 14.1058C77.3471 14.8075 77.5393 15.6846 77.5393 16.7371V27.345H73.9575V25.1677H73.834C73.6076 25.608 73.2885 26.0207 72.8768 26.406C72.472 26.7843 71.9608 27.0904 71.3433 27.3243C70.7326 27.5514 70.0155 27.6649 69.1921 27.6649ZM70.1596 24.92C70.9075 24.92 71.556 24.7721 72.1049 24.4763C72.6538 24.1736 73.0758 23.7746 73.3709 23.2793C73.6728 22.784 73.8237 22.244 73.8237 21.6592V19.7915C73.7071 19.8878 73.5081 19.9773 73.2268 20.0598C72.9523 20.1424 72.6435 20.2146 72.3004 20.2765C71.9574 20.3384 71.6177 20.3934 71.2815 20.4416C70.9453 20.4898 70.6537 20.531 70.4066 20.5654C69.8509 20.6411 69.3534 20.7649 68.9143 20.9369C68.4751 21.1089 68.1286 21.3497 67.8747 21.6592C67.6208 21.9619 67.4939 22.354 67.4939 22.8356C67.4939 23.5235 67.7443 24.0429 68.2452 24.3938C68.7461 24.7446 69.3843 24.92 70.1596 24.92Z\" fill=\"#26282A\"/><path d=\"M39.5 27.345V11.4951H43.0612V14.1883H43.2464C43.5758 13.2803 44.1213 12.5717 44.8829 12.0626C45.6446 11.5467 46.5537 11.2887 47.6104 11.2887C48.6808 11.2887 49.5831 11.5501 50.3173 12.0729C51.0584 12.5889 51.5798 13.294 51.8817 14.1883H52.0464C52.3964 13.3078 52.9865 12.6061 53.8167 12.0833C54.6538 11.5535 55.6453 11.2887 56.7912 11.2887C58.2459 11.2887 59.4329 11.7496 60.3524 12.6714C61.2718 13.5933 61.7316 14.9382 61.7316 16.7061V27.345H57.9954V17.284C57.9954 16.3003 57.7347 15.5814 57.2132 15.1273C56.6917 14.6664 56.0536 14.436 55.2988 14.436C54.3999 14.436 53.6966 14.718 53.1889 15.2821C52.688 15.8394 52.4375 16.5651 52.4375 17.4594V27.345H48.7837V17.1292C48.7837 16.3106 48.5367 15.6571 48.0427 15.1686C47.5555 14.6802 46.9174 14.436 46.1283 14.436C45.5931 14.436 45.1059 14.5736 44.6668 14.8487C44.2276 15.117 43.8777 15.4988 43.617 15.9941C43.3562 16.4826 43.2258 17.0535 43.2258 17.7071V27.345H39.5Z\" fill=\"#26282A\"/><path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/><path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/><path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/></svg>';\n\nconst DEFAULT_HREF = \"https://mapmap.ai\";\n\n/**\n * A MapLibre `IControl` rendering the MapMap wordmark. Typed structurally\n * (`onAdd`/`onRemove`) so it needs no maplibre-gl import and works with\n * any instance the host app bundles.\n */\nexport class LogoControl {\n private container: HTMLElement | undefined;\n private readonly href: string;\n\n constructor(options: LogoOptions = {}) {\n this.href = options.href ?? DEFAULT_HREF;\n }\n\n onAdd(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"LogoControl requires a DOM environment\");\n const link = doc.createElement(\"a\");\n link.className = \"maplibregl-ctrl mapmap-logo\";\n link.href = this.href;\n link.target = \"_blank\";\n link.rel = \"noopener\";\n link.setAttribute(\"aria-label\", \"MapMap\");\n link.style.cssText =\n \"display:block;line-height:0;margin:0 8px 4px 8px;opacity:0.9;pointer-events:auto\";\n // LOGO_SVG is a compile-time constant, parsed rather than assigned to\n // innerHTML so no HTML-injection surface exists even if it changes.\n const svg = new DOMParser().parseFromString(LOGO_SVG, \"image/svg+xml\").documentElement;\n link.appendChild(doc.importNode(svg, true));\n this.container = link;\n return link;\n }\n\n onRemove(): void {\n this.container?.remove();\n this.container = undefined;\n }\n}\n","/**\n * Studio navigation-design block (`extra.nav`) - types, defaults and parser.\n *\n * MapMap Studio's Navigation panel designs the turn-by-turn look - route\n * line, current-position puck and banner instruction - and stores the result\n * as a small design-token block under `extra.nav` in the theme JSON it\n * downloads/copies. This module reads that block so the same theme file\n * styles real navigation UI: `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` all accept a design from it.\n *\n * LOCKSTEP: this file mirrors `website/lib/studio-nav.ts` (the Studio\n * reference parser) - identical interfaces, defaults, clamps and URL rules.\n * Keep the two in sync so a theme previews in Studio exactly as the SDK\n * renders it. Not imported from the website because the packages do not\n * depend on each other.\n *\n * PUBLISH NOTE: the block travels with the THEME DOCUMENT, never with the\n * compiled `style.json`. That includes hosted publishing: the canonical\n * `sn_style` crate stores `extra` verbatim (bounded at 256 KB serialised)\n * and the gateway serves it back from `GET /styles/{id}/theme`, so a design\n * survives Studio's publish flow too. Read it from a theme file you pass to\n * `createMap` / `buildStyle`, or fetch it from a hosted style with\n * {@link navDesignFromThemeUrl} — a compiled style URL alone never carries\n * it.\n */\nimport type { Theme } from \"./style.js\";\n\n/** Route-line tokens (defaults match {@link RouteLayer}'s built-in look). */\nexport interface NavRouteDesign {\n /** Line colour. Default is MapMap signal blue (`SIGNAL_BLUE`). */\n color: string;\n /** Line width in px at mid zoom. */\n width: number;\n /** Line opacity, 0-1. */\n opacity: number;\n /** Casing (outline) colour drawn under the line. */\n casingColor: string;\n}\n\n/** Current-position puck tokens. */\nexport interface NavPuckDesign {\n /** Puck fill colour. */\n color: string;\n /** Puck diameter in px. */\n size: number;\n /** Whether the heading arrow is drawn on the puck. */\n headingArrow: boolean;\n /**\n * Optional custom puck image (`https:` or `data:` URI, PNG/SVG). When set\n * it replaces the built-in dot + arrow; `size` still scales it. Optional\n * since v1 - themes saved without it load unchanged.\n */\n imageUrl?: string;\n}\n\n/** Banner-instruction tokens (defaults match {@link GuidanceBanner}). */\nexport interface NavBannerDesign {\n /** Banner background colour. */\n background: string;\n /** Banner text (and arrow) colour. */\n textColor: string;\n /** Primary text size in px. */\n fontSize: number;\n /** Whether the lane diagram row is shown when lanes are present. */\n showLanes: boolean;\n /** Inner padding in px, 6-24. Optional since v1; default 10. */\n padding?: number;\n /** Corner radius in px, 0-24. Optional since v1; default 10. */\n cornerRadius?: number;\n /** Maximum banner width in px, 200-520. Optional since v1; default 340. */\n maxWidth?: number;\n /**\n * Banner height in px, 40-120. Optional since v1; unset means auto -\n * the banner takes its natural content height (old themes keep theirs).\n */\n height?: number;\n}\n\n/**\n * Drive-camera tokens: how the chase cam frames a turn-by-turn drive.\n * The whole block is optional since v1 - themes saved without it load\n * unchanged and the SDK keeps its built-in framing. Every field is itself\n * optional (absent = the documented default). `NavigationCamera` reads\n * `pitch`/`zoom` as its option defaults; `speedMps` drives Studio's demo\n * drive (and any route simulator) - a camera following real GPS fixes\n * ignores it.\n */\nexport interface NavCameraDesign {\n /** Chase-cam tilt in degrees, 0-85. Default 60. */\n pitch?: number;\n /** Chase-cam zoom, 14-20. Default 17.5. */\n zoom?: number;\n /** Drive speed in metres per second, 2-40. Default 12 (~43 km/h). */\n speedMps?: number;\n}\n\n/**\n * Defaults for the optional `camera` block. LOCKSTEP: mirrors\n * `NAV_CAMERA_DEFAULTS` in `website/lib/studio-nav.ts`.\n */\nexport const NAV_CAMERA_DEFAULTS = {\n pitch: 60,\n zoom: 17.5,\n speedMps: 12,\n} as const;\n\n/**\n * Safety-camera kinds a design can style, matching the kind the data model\n * already carries per camera. LOCKSTEP: mirrors `NAV_CAMERA_KINDS` in\n * `website/lib/studio-nav.ts`.\n *\n * WIRE NOTE: the gateway serialises `sn_safety::CameraKind` lowercase\n * (`fixed` / `average` / `redlight` / `unknown`); `mobile_site` is a\n * product-level kind a host may classify itself (the sidecar deliberately\n * leaves an OSM `speed_camera=mobile` node as `unknown` rather than\n * overclaiming a fixed installation). Normalise a wire value with\n * {@link navCameraKind} before indexing a design.\n */\nexport const NAV_CAMERA_KINDS = [\n \"fixed\",\n \"average\",\n \"red_light\",\n \"mobile_site\",\n \"unknown\",\n] as const;\n\n/** One safety-camera kind. */\nexport type NavCameraKind = (typeof NAV_CAMERA_KINDS)[number];\n\n/**\n * Normalises a camera kind from the wire (or any host classifier) onto a\n * {@link NavCameraKind}. Unrecognised values become `\"unknown\"`, never a\n * guess: a mislabelled camera would alert a driver about the wrong thing.\n */\nexport function navCameraKind(value: unknown): NavCameraKind {\n if (typeof value !== \"string\") return \"unknown\";\n switch (value.trim().toLowerCase()) {\n case \"fixed\":\n case \"permanent\":\n return \"fixed\";\n case \"average\":\n case \"average_speed\":\n case \"section\":\n case \"section_control\":\n return \"average\";\n case \"red_light\":\n case \"redlight\":\n case \"traffic_signals\":\n return \"red_light\";\n case \"mobile\":\n case \"mobile_site\":\n return \"mobile_site\";\n default:\n return \"unknown\";\n }\n}\n\n/** Curated icon sets a design can pick for the alert chip and map pins. */\nexport const NAV_ALERT_ICON_SETS = [\"european\", \"us\", \"minimal\", \"brand\"] as const;\n\n/** One curated icon set. `\"brand\"` means \"use my `iconUrlOverrides`\". */\nexport type NavAlertIconSet = (typeof NAV_ALERT_ICON_SETS)[number];\n\n/**\n * When a kind alerts AUDIBLY while driving.\n *\n * The visual chip is governed by `alertWhileDriving` and is deliberately\n * unconditional and calm; audio is the escalation channel (the shipping\n * model: the pop-up always appears, the sound only when the driver is over\n * the limit). UI labels must describe the behaviour - \"Always alert\",\n * \"Warn if speeding\", \"Never alert\" - and must never say \"Auto\", which\n * Organic Maps relabelled after users could not tell what it did.\n */\nexport const NAV_ALERT_MODES = [\"always\", \"whenSpeeding\", \"never\"] as const;\n\n/** One alert mode. */\nexport type NavAlertMode = (typeof NAV_ALERT_MODES)[number];\n\n/**\n * Audio channel for a kind: silent, a non-verbal earcon, or an earcon\n * followed by speech naming the kind. Kind is carried in the ICON and in\n * SPEECH, never in the earcon's identity - urgency lives in timbre, so the\n * escalated state is the same motif made more insistent, not a new sound.\n */\nexport const NAV_ALERT_AUDIO_MODES = [\"off\", \"earcon\", \"earcon_and_speech\"] as const;\n\n/** One audio mode. */\nexport type NavAlertAudioMode = (typeof NAV_ALERT_AUDIO_MODES)[number];\n\n/**\n * The built-in earcon library, as a curated enum rather than a free URL.\n *\n * A design picks ONE sound for the calm alert and ONE for its escalated\n * variant - never one per camera kind. Kind is carried by the icon and by\n * speech; urgency is carried by timbre, so the escalated state is the same\n * motif made more insistent. Per-kind sounds would ask a driver to learn\n * five timbres at 70 mph, which no shipping product does.\n *\n * `zoneEnter` / `zoneClear` are the average-speed corridor pair a host\n * plays at the entry and exit of a corridor. They are offered here too so\n * a design can borrow their timbre, but the corridor itself always uses\n * the pair - it is a boundary crossing, not a point alert.\n */\nexport const NAV_ALERT_SOUNDS = [\n \"cameraCalm\",\n \"cameraUrgent\",\n \"overspeedSoft\",\n \"zoneEnter\",\n \"zoneClear\",\n] as const;\n\n/** One built-in earcon. */\nexport type NavAlertSound = (typeof NAV_ALERT_SOUNDS)[number];\n\n/**\n * File name of each built-in earcon, relative to\n * {@link NAV_ALERT_SOUND_BASE_URL}. Mono, ~0.5-0.9 s, mixed dry with no\n * reverb tail so they stay crisp over road noise and never trail into the\n * spoken instruction that follows.\n */\nexport const NAV_ALERT_SOUND_FILES: Record<NavAlertSound, string> = {\n cameraCalm: \"earcon-camera-calm.mp3\",\n cameraUrgent: \"earcon-camera-urgent.mp3\",\n overspeedSoft: \"earcon-overspeed-soft.mp3\",\n zoneEnter: \"earcon-zone-enter.mp3\",\n zoneClear: \"earcon-zone-clear.mp3\",\n};\n\n/**\n * Where the built-in earcons are hosted. Public, unmetered and immutable\n * (the files are content-stable; a new sound gets a new name). Pass your\n * own base to {@link navAlertSoundUrl} to self-host them - the SDK bundles\n * no audio, exactly like `VoiceGuidance`'s earcon URLs.\n */\nexport const NAV_ALERT_SOUND_BASE_URL = \"https://mapmap.ai/earcons/\";\n\n/**\n * Absolute URL for a built-in earcon. An unrecognised value falls back to\n * `cameraCalm` rather than returning nothing: a missing alert sound is a\n * silent failure a driver cannot see.\n */\nexport function navAlertSoundUrl(\n sound: unknown,\n baseUrl: string = NAV_ALERT_SOUND_BASE_URL,\n): string {\n const name = (NAV_ALERT_SOUNDS as readonly string[]).includes(sound as string)\n ? (sound as NavAlertSound)\n : \"cameraCalm\";\n return `${baseUrl.replace(/\\/*$/, \"/\")}${NAV_ALERT_SOUND_FILES[name]}`;\n}\n\n/** Lead-distance presets. Not a free number: see {@link NAV_ALERT_LEAD_DISTANCE_M}. */\nexport const NAV_ALERT_LEAD_DISTANCES = [\"short\", \"standard\", \"long\"] as const;\n\n/** One lead-distance preset. */\nexport type NavAlertLeadDistance = (typeof NAV_ALERT_LEAD_DISTANCES)[number];\n\n/**\n * Metres before the camera at which the alert may first appear, per preset.\n * These are FLOORS, not targets: a host may announce earlier (a motorway\n * closing speed eats 400 m in nine seconds) but never later. Exposed as an\n * enum rather than a numeric field precisely so no design can set a lead\n * below the safety floor.\n */\nexport const NAV_ALERT_LEAD_DISTANCE_M: Record<NavAlertLeadDistance, number> = {\n short: 150,\n standard: 250,\n long: 400,\n};\n\n/** Metres of lead for a preset (garbage falls back to `standard`). */\nexport function navAlertLeadDistanceM(preset: unknown): number {\n return NAV_ALERT_LEAD_DISTANCE_M[\n (NAV_ALERT_LEAD_DISTANCES as readonly string[]).includes(preset as string)\n ? (preset as NavAlertLeadDistance)\n : \"standard\"\n ];\n}\n\n/**\n * Where the chip sits. Constrained slots, never free x/y: the chip must not\n * occlude the current speed or the limit. Covering exactly the two numbers\n * the alert is telling the driver to act on has been the single\n * most-complained-about defect in the category since 2023, and a free\n * position would let a customer reintroduce it.\n */\nexport const NAV_ALERT_CHIP_POSITIONS = [\"aboveSpeed\", \"topLeading\", \"topTrailing\"] as const;\n\n/** One chip position slot. */\nexport type NavAlertChipPosition = (typeof NAV_ALERT_CHIP_POSITIONS)[number];\n\n/**\n * Per-kind surfaces and channels. The three booleans are orthogonal: a\n * kind can appear on the map without alerting, alert without appearing on\n * the map, or be listed in the route preview only.\n */\nexport interface NavAlertKindDesign {\n /**\n * Draw a pin for this kind while BROWSING the map (no active guidance).\n *\n * Kept as the browse-mode field under its original name so themes saved\n * before the browse/navigate split round-trip unchanged.\n */\n showOnMap: boolean;\n /**\n * Draw a pin for this kind on the map DURING active navigation.\n *\n * Separate from {@link showOnMap} because the two are genuinely\n * different decisions: a fleet product may want a clean driving map and\n * a fully annotated planning map, or the reverse. Defaults to `true`,\n * and absent in an older theme reads as `true` - the market shows\n * cameras with or without a planned route, so gating map display behind\n * guidance would be more restrictive than every product a driver has\n * used.\n */\n showOnMapWhileNavigating: boolean;\n /** Show the alert chip for this kind while driving. */\n alertWhileDriving: boolean;\n /** List this kind in the pre-drive route preview. */\n showInRoutePreview: boolean;\n /** When the AUDIBLE alert fires. The chip itself follows `alertWhileDriving`. */\n alertMode: NavAlertMode;\n /** Which audio channel this kind uses. */\n audioMode: NavAlertAudioMode;\n}\n\n/**\n * Safety-alert tokens (`extra.nav.alerts`): the camera alert chip, its\n * escalated state, per-kind icons and surfaces, and the average-speed\n * corridor highlight.\n *\n * The whole block is optional since v1 - themes saved without it load\n * unchanged and hosts keep their built-in look - but a block that IS\n * present is always complete: every field, including both escalated\n * tokens, parses to a value. The escalated state can be restyled, never\n * removed.\n *\n * Two states only, calm and escalated. There is no amber tier: no shipping\n * navigation product uses a three-colour alert state and drivers have no\n * learned mapping for one.\n *\n * NOT STYLEABLE HERE: whether cameras may be shown at all. That is a\n * server-side jurisdiction policy applied before any camera leaves the\n * gateway. A design styles what the policy permits and nothing more.\n */\nexport interface NavAlertsDesign {\n /** Chip background in the calm (default) state. */\n background: string;\n /** Chip text and icon colour in the calm state. */\n textColor: string;\n /** Chip outline colour (both states). */\n outlineColor: string;\n /** Chip corner radius in px, 0-24. */\n cornerRadius: number;\n /** Chip outline width in px, 0-4. */\n outlineWidth: number;\n /** Chip background when escalated (driver over the limit). */\n escalatedBackground: string;\n /** Chip text and icon colour when escalated. */\n escalatedTextColor: string;\n /** Curated icon set for the chip and map pins. */\n iconSet: NavAlertIconSet;\n /**\n * Per-kind icon overrides (`https:` or `data:` URIs only). Any kind left\n * out keeps `iconSet`'s icon. Absent when no kind is overridden.\n */\n iconUrlOverrides?: Partial<Record<NavCameraKind, string>>;\n /**\n * The earcon played for a calm alert. One sound for the whole design,\n * never one per kind - see {@link NAV_ALERT_SOUNDS}.\n */\n alertSound: NavAlertSound;\n /**\n * Optional replacement for the calm earcon (`https:` or `data:` URIs\n * only, same rule as `iconUrlOverrides`). Absent = the built-in\n * {@link alertSound}.\n */\n alertSoundUrl?: string;\n /**\n * The earcon played when the driver is over the limit. The escalated\n * state is not removable - it can be restyled and its sound chosen, but\n * a design cannot silence the escalation itself (set the kind's\n * `audioMode` to `off` if you want no audio at all).\n */\n escalatedSound: NavAlertSound;\n /** Optional replacement for the escalated earcon; same URL rule. */\n escalatedSoundUrl?: string;\n /** Map pin size as a multiplier of the default ramp, 0.75-1.5. */\n mapIconSize: number;\n /** Lowest zoom at which map pins are drawn, 9-14. */\n mapMinZoom: number;\n /** Lead-distance preset; see {@link NAV_ALERT_LEAD_DISTANCE_M}. */\n leadDistance: NavAlertLeadDistance;\n /** Which constrained slot the chip occupies. */\n chipPosition: NavAlertChipPosition;\n /** Colour of the average-speed corridor highlight on the route line. */\n corridorColor: string;\n /** Corridor highlight opacity, 0-1. */\n corridorOpacity: number;\n /** Per-kind surfaces and channels; always all five kinds. */\n kinds: Record<NavCameraKind, NavAlertKindDesign>;\n}\n\n/** The `extra.nav` block: navigation design tokens for the SDKs. */\nexport interface NavDesign {\n /** Block schema version; currently always 1. */\n version: 1;\n route: NavRouteDesign;\n puck: NavPuckDesign;\n banner: NavBannerDesign;\n /**\n * Optional since v1: drive-camera framing (pitch/zoom) and speed. Absent\n * means \"SDK built-ins\" - the block stays `version: 1` either way.\n */\n camera?: NavCameraDesign;\n /**\n * Optional since v1: safety-alert chip, per-kind surfaces and corridor\n * highlight. Absent means \"SDK built-ins\"; the block stays `version: 1`.\n */\n alerts?: NavAlertsDesign;\n}\n\n/**\n * Defaults for the optional `alerts` block. LOCKSTEP: mirrors\n * `defaultNavAlertsDesign` in `website/lib/studio-nav.ts`.\n *\n * Calm chip = the banner's dark pill, so an unstyled alert already matches\n * the rest of the guidance surface. Escalated = a red that clears 4.5:1\n * against white text.\n *\n * Per-kind defaults follow the \"visual always, audio conditional\" rule:\n * the three confidently classified kinds alert unconditionally, a mobile\n * site (a location where enforcement sometimes happens, not a device)\n * warns only if speeding, and an unclassified camera stays on the map but\n * does not interrupt a drive.\n */\nexport function defaultNavAlertsDesign(): NavAlertsDesign {\n const alertingKind = (\n alertMode: NavAlertMode,\n audioMode: NavAlertAudioMode,\n showInRoutePreview: boolean,\n alertWhileDriving = true,\n ): NavAlertKindDesign => ({\n showOnMap: true,\n showOnMapWhileNavigating: true,\n alertWhileDriving,\n showInRoutePreview,\n alertMode,\n audioMode,\n });\n return {\n background: \"#101418\",\n textColor: \"#ffffff\",\n outlineColor: \"#ffffff\",\n cornerRadius: 10,\n outlineWidth: 1.5,\n escalatedBackground: \"#c0392b\",\n escalatedTextColor: \"#ffffff\",\n iconSet: \"european\",\n alertSound: \"cameraCalm\",\n escalatedSound: \"cameraUrgent\",\n mapIconSize: 1,\n mapMinZoom: 12,\n leadDistance: \"standard\",\n chipPosition: \"aboveSpeed\",\n corridorColor: \"#e05c6c\",\n corridorOpacity: 0.55,\n kinds: {\n fixed: alertingKind(\"always\", \"earcon\", true),\n average: alertingKind(\"always\", \"earcon_and_speech\", true),\n red_light: alertingKind(\"always\", \"earcon\", true),\n mobile_site: alertingKind(\"whenSpeeding\", \"earcon\", false),\n unknown: alertingKind(\"whenSpeeding\", \"off\", false, false),\n },\n };\n}\n\n/**\n * Defaults mirror what the SDK draws today with no design: `RouteLayer`'s\n * signal-blue line over a dark casing, and `GuidanceBanner`'s dark pill.\n */\nexport function defaultNavDesign(): NavDesign {\n return {\n version: 1,\n route: { color: \"#3a86ff\", width: 4.5, opacity: 1, casingColor: \"#1f438a\" },\n puck: { color: \"#1f6fff\", size: 14, headingArrow: true },\n banner: {\n background: \"#101418\",\n textColor: \"#ffffff\",\n fontSize: 16,\n showLanes: true,\n padding: 10,\n cornerRadius: 10,\n maxWidth: 340,\n },\n };\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction str(v: unknown, fallback: string): string {\n return typeof v === \"string\" && v.trim() !== \"\" ? v : fallback;\n}\n\nfunction num(v: unknown, fallback: number, min: number, max: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : fallback;\n}\n\n/** Optional clamped number: absent/malformed stays `undefined` (= auto). */\nfunction optNum(v: unknown, min: number, max: number): number | undefined {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : undefined;\n}\n\nfunction bool(v: unknown, fallback: boolean): boolean {\n return typeof v === \"boolean\" ? v : fallback;\n}\n\n/**\n * Optional puck-image URL: only `https:` or `data:` URIs are accepted;\n * anything else (including absence) yields `undefined` - the built-in puck.\n */\nfunction puckImageUrl(v: unknown): string | undefined {\n return assetUrl(v);\n}\n\n/** Same URL rule as {@link puckImageUrl}, for alert icon overrides. */\nfunction iconUrl(v: unknown): string | undefined {\n return assetUrl(v);\n}\n\n/**\n * The one asset-URL rule the whole block uses: only `https:` or `data:`\n * URIs are accepted, so a theme can never point a driver-facing surface at\n * plaintext `http:`, a `javascript:` payload or a `file:` path. Anything\n * else (including absence) yields `undefined` - the built-in asset.\n */\nfunction assetUrl(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n return /^(https:|data:)/i.test(t) ? t : undefined;\n}\n\n/** One of `allowed`, or `fallback` for anything else (including absence). */\nfunction oneOf<T extends string>(v: unknown, allowed: readonly T[], fallback: T): T {\n return typeof v === \"string\" && (allowed as readonly string[]).includes(v) ? (v as T) : fallback;\n}\n\n/** Lenient parse of one kind's surfaces and channels. */\nfunction parseNavAlertKind(value: unknown, d: NavAlertKindDesign): NavAlertKindDesign {\n const k = isRecord(value) ? value : {};\n return {\n showOnMap: bool(k.showOnMap, d.showOnMap),\n showOnMapWhileNavigating: bool(k.showOnMapWhileNavigating, d.showOnMapWhileNavigating),\n alertWhileDriving: bool(k.alertWhileDriving, d.alertWhileDriving),\n showInRoutePreview: bool(k.showInRoutePreview, d.showInRoutePreview),\n alertMode: oneOf(k.alertMode, NAV_ALERT_MODES, d.alertMode),\n audioMode: oneOf(k.audioMode, NAV_ALERT_AUDIO_MODES, d.audioMode),\n };\n}\n\n/**\n * Lenient parse of an `extra.nav.alerts` value. Every numeric is clamped,\n * every enum validated, and garbage falls back per field to the defaults -\n * so a hand-edited or older theme can never produce an alert that is\n * unreadable, positioned over the speed readout, or missing its escalated\n * state. The escalated tokens in particular always come back set, even\n * when the input omits or nulls them: a driver-facing escalation is not a\n * removable feature.\n */\nexport function parseNavAlertsDesign(value: unknown): NavAlertsDesign {\n const d = defaultNavAlertsDesign();\n const a = isRecord(value) ? value : {};\n const kindsIn = isRecord(a.kinds) ? a.kinds : {};\n const kinds = {} as Record<NavCameraKind, NavAlertKindDesign>;\n for (const kind of NAV_CAMERA_KINDS) {\n kinds[kind] = parseNavAlertKind(kindsIn[kind], d.kinds[kind]);\n }\n // Icon overrides are dropped entirely when nothing survives validation,\n // so a default design stays free of an empty object (and round-trips).\n const overridesIn = isRecord(a.iconUrlOverrides) ? a.iconUrlOverrides : {};\n const iconUrlOverrides: Partial<Record<NavCameraKind, string>> = {};\n for (const kind of NAV_CAMERA_KINDS) {\n const url = iconUrl(overridesIn[kind]);\n if (url !== undefined) iconUrlOverrides[kind] = url;\n }\n // Sound overrides follow the icon-override rule exactly: only `https:`\n // or `data:` URIs survive, and a rejected one silently falls back to the\n // chosen built-in rather than leaving the alert mute.\n const alertSoundUrl = assetUrl(a.alertSoundUrl);\n const escalatedSoundUrl = assetUrl(a.escalatedSoundUrl);\n return {\n background: str(a.background, d.background),\n textColor: str(a.textColor, d.textColor),\n outlineColor: str(a.outlineColor, d.outlineColor),\n cornerRadius: num(a.cornerRadius, d.cornerRadius, 0, 24),\n outlineWidth: num(a.outlineWidth, d.outlineWidth, 0, 4),\n escalatedBackground: str(a.escalatedBackground, d.escalatedBackground),\n escalatedTextColor: str(a.escalatedTextColor, d.escalatedTextColor),\n iconSet: oneOf(a.iconSet, NAV_ALERT_ICON_SETS, d.iconSet),\n ...(Object.keys(iconUrlOverrides).length > 0 ? { iconUrlOverrides } : {}),\n alertSound: oneOf(a.alertSound, NAV_ALERT_SOUNDS, d.alertSound),\n ...(alertSoundUrl !== undefined ? { alertSoundUrl } : {}),\n escalatedSound: oneOf(a.escalatedSound, NAV_ALERT_SOUNDS, d.escalatedSound),\n ...(escalatedSoundUrl !== undefined ? { escalatedSoundUrl } : {}),\n mapIconSize: num(a.mapIconSize, d.mapIconSize, 0.75, 1.5),\n mapMinZoom: num(a.mapMinZoom, d.mapMinZoom, 9, 14),\n leadDistance: oneOf(a.leadDistance, NAV_ALERT_LEAD_DISTANCES, d.leadDistance),\n chipPosition: oneOf(a.chipPosition, NAV_ALERT_CHIP_POSITIONS, d.chipPosition),\n corridorColor: str(a.corridorColor, d.corridorColor),\n corridorOpacity: num(a.corridorOpacity, d.corridorOpacity, 0, 1),\n kinds,\n };\n}\n\n/**\n * Lenient parse of an `extra.nav` value: unknown or malformed fields fall\n * back to the defaults, so an imported theme never fails on its nav block.\n * LOCKSTEP: identical semantics to `parseNavDesign` in\n * `website/lib/studio-nav.ts` (same clamps, same fallbacks).\n */\nexport function parseNavDesign(value: unknown): NavDesign {\n const d = defaultNavDesign();\n if (!isRecord(value)) return d;\n const route = isRecord(value.route) ? value.route : {};\n const puck = isRecord(value.puck) ? value.puck : {};\n const banner = isRecord(value.banner) ? value.banner : {};\n return {\n version: 1,\n route: {\n color: str(route.color, d.route.color),\n width: num(route.width, d.route.width, 0.5, 20),\n opacity: num(route.opacity, d.route.opacity, 0, 1),\n casingColor: str(route.casingColor, d.route.casingColor),\n },\n puck: {\n color: str(puck.color, d.puck.color),\n size: num(puck.size, d.puck.size, 6, 40),\n headingArrow: bool(puck.headingArrow, d.puck.headingArrow),\n imageUrl: puckImageUrl(puck.imageUrl),\n },\n banner: {\n background: str(banner.background, d.banner.background),\n textColor: str(banner.textColor, d.banner.textColor),\n fontSize: num(banner.fontSize, d.banner.fontSize, 10, 32),\n showLanes: bool(banner.showLanes, d.banner.showLanes),\n padding: num(banner.padding, d.banner.padding ?? 10, 6, 24),\n cornerRadius: num(banner.cornerRadius, d.banner.cornerRadius ?? 10, 0, 24),\n maxWidth: num(banner.maxWidth, d.banner.maxWidth ?? 340, 200, 520),\n height: optNum(banner.height, 40, 120),\n },\n // Camera is optional since v1: absent (or malformed) stays undefined so\n // old themes round-trip byte-identical; a present block clamps per\n // field, each absent field meaning \"use the default\".\n ...(isRecord(value.camera)\n ? {\n camera: {\n pitch: optNum(value.camera.pitch, 0, 85),\n zoom: optNum(value.camera.zoom, 14, 20),\n speedMps: optNum(value.camera.speedMps, 2, 40),\n },\n }\n : {}),\n // Alerts is optional since v1 on the same terms as camera: absent (or\n // malformed) stays undefined so old themes round-trip byte-identical.\n // Unlike camera, a PRESENT block always parses complete - every field\n // filled from the defaults - because half an alert design is a safety\n // defect, not a partial style.\n ...(isRecord(value.alerts) ? { alerts: parseNavAlertsDesign(value.alerts) } : {}),\n };\n}\n\n/**\n * Reads and parses the `extra.nav` block from a Studio theme document.\n * Returns `undefined` when the theme carries no nav block at all (so\n * callers can tell \"no design\" apart from \"default design\"); a present but\n * malformed block parses leniently to the defaults.\n */\nexport function navDesignFromTheme(theme: Theme | undefined | null): NavDesign | undefined {\n const extra = theme?.extra;\n if (typeof extra !== \"object\" || extra === null || !(\"nav\" in extra)) {\n return undefined;\n }\n return parseNavDesign((extra as { nav?: unknown }).nav);\n}\n\n/**\n * Fetches a hosted theme document and reads its `extra.nav` block.\n *\n * Point it at the gateway's theme endpoint - the design a Studio publish\n * stores alongside the compiled style:\n *\n * ```ts\n * const design = await navDesignFromThemeUrl(\n * \"https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme\",\n * );\n * ```\n *\n * The endpoint is public (no API key) and never cached, so this always\n * reflects the latest published version. Returns `undefined` when the\n * theme carries no nav block (same contract as {@link navDesignFromTheme});\n * throws on network failure, a non-2xx response or a non-JSON body.\n *\n * @param fetchImpl Optional `fetch` replacement (tests, Node polyfills).\n * Defaults to the global `fetch`.\n */\nexport async function navDesignFromThemeUrl(\n url: string,\n fetchImpl?: typeof fetch,\n): Promise<NavDesign | undefined> {\n // Wrap rather than alias the global so browsers keep their `this` binding.\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL) => globalThis.fetch(input));\n const response = await doFetch(url);\n if (!response.ok) {\n throw new Error(`fetching theme ${url}: HTTP ${response.status}`);\n }\n const theme = (await response.json()) as Theme;\n return navDesignFromTheme(theme);\n}\n","/**\n * Studio POI category-design block (`extra.poi`) - types, defaults, parser\n * and appliers.\n *\n * MapMap Studio's POIs panel colours the ~8 POI categories - the coloured\n * category dot drawn under a POI label, and the `poi-labels` text colour -\n * and stores the result as a small design-token block under `extra.poi` in\n * the theme JSON it downloads/copies/publishes, exactly like the navigation\n * design under `extra.nav` (see nav-design.ts). This module reads that\n * block and applies the label-text part to a live MapLibre map; the dot\n * images themselves are runtime-rasterised by their host (the MapMap\n * website today - sprite-based icons arrive with marker packs).\n *\n * LOCKSTEP: this file mirrors `website/lib/studio-poi.ts` (the Studio\n * reference parser) - identical category ids, built-in colours, leniency\n * and expression building. The class->category mapping mirrors\n * `website/lib/poi-icons.ts` (`POI_CLASS_CATEGORIES`). Keep them in sync so\n * a theme previews in Studio exactly as the SDK applies it. Not imported\n * from the website because the packages do not depend on each other.\n *\n * PUBLISH NOTE: the block travels with the THEME DOCUMENT, never with the\n * compiled `style.json`. The canonical `sn_style` crate stores `extra`\n * verbatim (bounded at 256 KB serialised) and the gateway serves it back\n * from `GET /styles/{id}/theme`, so a design survives Studio's publish\n * flow. Read it from a theme file you pass to `createMap` / `buildStyle`,\n * or fetch it from a hosted style with {@link poiDesignFromThemeUrl} - a\n * compiled style URL alone never carries it.\n */\nimport type { Theme } from \"./style.js\";\n\n/** One category's overrides. Both fields optional: absent = built-in. */\nexport interface PoiCategoryDesign {\n /** Dot fill colour (replaces the built-in category brand colour). */\n color?: string;\n /** Label text colour for this category (replaces `textSecondary`). */\n textColor?: string;\n}\n\n/** The `extra.poi` block: POI category design. */\nexport interface PoiDesign {\n /** Block schema version; currently always 1. */\n version: 1;\n /** Overrides by category id; empty = all built-in. */\n categories: Record<string, PoiCategoryDesign>;\n}\n\n/**\n * The valid category ids with their built-in dot colours, in presentation\n * order. LOCKSTEP: mirrors `POI_CATEGORIES` in `website/lib/poi-icons.ts`.\n */\nexport const POI_CATEGORY_COLORS: readonly (readonly [string, string])[] = [\n [\"food_drink\", \"#e8734a\"],\n [\"shopping\", \"#4a90d9\"],\n [\"transport\", \"#3a86ff\"],\n [\"lodging\", \"#9b6dd6\"],\n [\"health\", \"#e05c6c\"],\n [\"culture_leisure\", \"#3aa675\"],\n [\"education\", \"#d9a13a\"],\n [\"services\", \"#7a8699\"],\n];\n\n/** The valid category ids, in presentation order. */\nexport const POI_CATEGORY_IDS: readonly string[] = POI_CATEGORY_COLORS.map(([id]) => id);\n\n/**\n * OpenMapTiles `poi` layer `class` values grouped into the categories\n * above; every class not listed falls through to `services`. LOCKSTEP:\n * mirrors `POI_CLASS_CATEGORIES` in `website/lib/poi-icons.ts`.\n */\nexport const POI_CLASS_CATEGORIES: Record<string, string[]> = {\n food_drink: [\n \"restaurant\",\n \"fast_food\",\n \"cafe\",\n \"bar\",\n \"pub\",\n \"biergarten\",\n \"food_court\",\n \"alcohol_shop\",\n ],\n shopping: [\n \"shop\",\n \"grocery\",\n \"supermarket\",\n \"clothing_store\",\n \"mall\",\n \"department_store\",\n \"convenience\",\n \"bakery\",\n \"marketplace\",\n ],\n transport: [\n \"railway\",\n \"railway_station\",\n \"subway\",\n \"bus\",\n \"bus_station\",\n \"ferry_terminal\",\n \"aerodrome\",\n \"airport\",\n \"airfield\",\n ],\n lodging: [\n \"lodging\",\n \"hotel\",\n \"motel\",\n \"hostel\",\n \"guest_house\",\n \"camp_site\",\n \"caravan_site\",\n \"alpine_hut\",\n ],\n health: [\"hospital\", \"pharmacy\", \"doctors\", \"dentist\", \"veterinary\", \"clinic\"],\n culture_leisure: [\n \"museum\",\n \"theatre\",\n \"cinema\",\n \"attraction\",\n \"park\",\n \"stadium\",\n \"art_gallery\",\n \"zoo\",\n \"swimming_pool\",\n \"golf\",\n \"playground\",\n \"cemetery\",\n \"garden\",\n \"picnic_site\",\n \"viewpoint\",\n ],\n education: [\"school\", \"college\", \"university\", \"library\", \"kindergarten\"],\n services: [\n \"bank\",\n \"post\",\n \"police\",\n \"town_hall\",\n \"place_of_worship\",\n \"courthouse\",\n \"embassy\",\n \"fire_station\",\n \"community_centre\",\n \"toilet\",\n \"telephone\",\n \"atm\",\n ],\n};\n\n/** The built-in dot colour for a category id. */\nexport function builtInPoiColor(categoryId: string): string | undefined {\n return POI_CATEGORY_COLORS.find(([id]) => id === categoryId)?.[1];\n}\n\n/** No overrides: every category keeps its built-in dot and label colours. */\nexport function defaultPoiDesign(): PoiDesign {\n return { version: 1, categories: {} };\n}\n\n/** True when the design changes nothing. */\nexport function poiDesignIsDefault(design: PoiDesign): boolean {\n return Object.keys(design.categories).length === 0;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/**\n * Cheap CSS colour check (hex forms + functional notations), mirroring\n * `isCssColour` in style.ts / `website/lib/studio-style.ts`.\n */\nfunction colour(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n if (t.startsWith(\"#\")) {\n const hex = t.slice(1);\n return [3, 4, 6, 8].includes(hex.length) && /^[0-9a-fA-F]+$/.test(hex) ? t : undefined;\n }\n for (const prefix of [\"rgb(\", \"rgba(\", \"hsl(\", \"hsla(\"]) {\n if (t.startsWith(prefix) && t.endsWith(\")\")) return t;\n }\n return undefined;\n}\n\n/**\n * Lenient parse of an `extra.poi` value: unknown category ids and invalid\n * colours are dropped rather than failing, so an imported theme never\n * breaks on its POI block. LOCKSTEP: identical semantics to\n * `parsePoiDesign` in `website/lib/studio-poi.ts`.\n */\nexport function parsePoiDesign(value: unknown): PoiDesign {\n const design = defaultPoiDesign();\n if (!isRecord(value) || !isRecord(value.categories)) return design;\n for (const id of POI_CATEGORY_IDS) {\n const raw = value.categories[id];\n if (!isRecord(raw)) continue;\n const category: PoiCategoryDesign = {};\n const color = colour(raw.color);\n const textColor = colour(raw.textColor);\n if (color !== undefined) category.color = color;\n if (textColor !== undefined) category.textColor = textColor;\n if (Object.keys(category).length > 0) design.categories[id] = category;\n }\n return design;\n}\n\n/**\n * Reads and parses the `extra.poi` block from a Studio theme document.\n * Returns `undefined` when the theme carries no poi block at all (so\n * callers can tell \"no design\" apart from \"default design\"); a present but\n * malformed block parses leniently to the defaults. Same contract as\n * `navDesignFromTheme`.\n */\nexport function poiDesignFromTheme(theme: Theme | undefined | null): PoiDesign | undefined {\n const extra = theme?.extra;\n if (typeof extra !== \"object\" || extra === null || !(\"poi\" in extra)) {\n return undefined;\n }\n return parsePoiDesign((extra as { poi?: unknown }).poi);\n}\n\n/**\n * Fetches a hosted theme document and reads its `extra.poi` block - point\n * it at the gateway's public, never-cached theme endpoint, e.g.\n * `https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme`. Returns\n * `undefined` when the theme carries no poi block; throws on network\n * failure, a non-2xx response or a non-JSON body. Same contract as\n * {@link navDesignFromThemeUrl}.\n *\n * @param fetchImpl Optional `fetch` replacement (tests, Node polyfills).\n */\nexport async function poiDesignFromThemeUrl(\n url: string,\n fetchImpl?: typeof fetch,\n): Promise<PoiDesign | undefined> {\n // Wrap rather than alias the global so browsers keep their `this` binding.\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL) => globalThis.fetch(input));\n const response = await doFetch(url);\n if (!response.ok) {\n throw new Error(`fetching theme ${url}: HTTP ${response.status}`);\n }\n const theme = (await response.json()) as Theme;\n return poiDesignFromTheme(theme);\n}\n\n/**\n * The `poi-labels` `text-color` value for a design: the plain fallback\n * colour when no category overrides label text, otherwise a `match`\n * expression keyed on the tile's `class` property. Every non-services\n * category always gets an arm (override or fallback) so unmatched classes\n * - the `services` fallback arm - never inherit another category's colour.\n * LOCKSTEP: mirrors `poiTextColorExpression` in `website/lib/studio-poi.ts`.\n */\nexport function poiTextColorExpression(design: PoiDesign, fallback: string): unknown {\n if (!POI_CATEGORY_IDS.some((id) => design.categories[id]?.textColor)) return fallback;\n const arms = POI_CATEGORY_IDS.filter((id) => id !== \"services\").flatMap((id) => [\n POI_CLASS_CATEGORIES[id],\n design.categories[id]?.textColor ?? fallback,\n ]);\n return [\n \"match\",\n [\"get\", \"class\"],\n ...arms,\n design.categories.services?.textColor ?? fallback,\n ];\n}\n\n/** The subset of the MapLibre map surface {@link applyPoiDesign} touches. */\ninterface PoiPaintMap {\n getStyle(): { layers?: { id: string; type?: string }[] } | undefined;\n setPaintProperty(layerId: string, name: string, value: unknown): unknown;\n}\n\n/**\n * Applies a design's per-category label text colours to every `poi-labels`\n * layer on a live map (including per-territory clones named\n * `poi-labels@<territory>`). `fallbackTextColor` is the colour\n * non-overridden categories keep - pass the style's `poi-labels` text\n * colour (the theme's `textSecondary` slot; defaults to the light-base\n * value). A default design restores the plain fallback, so this is safe to\n * call on every design change.\n *\n * NOTE: runtime paint changes do not survive a later `setStyle`; re-apply\n * after style swaps (the MapMap website bakes the expression into the\n * style object instead for exactly this reason).\n */\nexport function applyPoiDesign(\n map: PoiPaintMap,\n design: PoiDesign,\n fallbackTextColor = \"#6b6b6b\",\n): void {\n const value = poiTextColorExpression(design, fallbackTextColor);\n for (const layer of map.getStyle()?.layers ?? []) {\n if (layer.id === \"poi-labels\" || layer.id.startsWith(\"poi-labels@\")) {\n map.setPaintProperty(layer.id, \"text-color\", value);\n }\n }\n}\n","/**\n * MapMap style assembly - pure, browser-free port of the `sn-style` crate.\n *\n * This module mirrors `crates/sn-style` (theme.rs + compile.rs), the\n * canonical MapMap Studio theme engine, so client-side and build-side\n * styles compile identically. A {@link Theme} is a small, agent-friendly\n * JSON document (named palette slots + per-layer overrides) that\n * {@link buildStyle} turns into a full MapLibre style-spec v8 style over\n * the MapMap territory tiles (OpenMapTiles schema, as emitted by\n * `sn-factory`'s Planetiler stage and served as PMTiles).\n *\n * The `pmtiles://` URL prefix is resolved by the pmtiles protocol handler\n * that {@link registerPmtilesProtocol} installs on the MapLibre instance.\n *\n * Attribution: \"© OpenStreetMap contributors\" (ODbL) and \"© OpenMapTiles\"\n * (CC-BY 4.0 schema) are legally required and stamped on every compiled\n * style's tile source. There is no theme field that can remove them.\n */\nimport type { StyleSpecification } from \"maplibre-gl\";\n\n/** A loose JSON object - skeleton layers are assembled as plain JSON. */\ntype JsonObject = Record<string, unknown>;\n\n/** Which built-in palette a theme starts from. */\nexport type MapMapTheme = \"light\" | \"dark\";\n\n/** The OSM attribution string. Legally required (ODbL) - never removed. */\nexport const OSM_ATTRIBUTION = \"© OpenStreetMap contributors\";\n\n/** The OpenMapTiles schema attribution (CC-BY 4.0). */\nexport const OPENMAPTILES_ATTRIBUTION = \"© OpenMapTiles\";\n\n/**\n * Combined attribution stamped on every compiled style's tile source.\n * Legally required (ODbL + CC-BY) - enforced, not themable: no theme\n * field can remove it.\n */\nexport const FULL_ATTRIBUTION = \"© OpenStreetMap contributors © OpenMapTiles\";\n\n/** Default glyph endpoint (PBF fontstacks), mirroring `sn_style::DEFAULT_GLYPHS_URL`. */\nexport const DEFAULT_GLYPHS_URL = \"https://fonts.mapmap.ai/{fontstack}/{range}.pbf\";\n\n/** A sensible default territory tiles URL (overridable per map). */\nexport const DEFAULT_TERRITORY_TILES_URL =\n \"pmtiles://https://tiles.mapmap.ai/planet.pmtiles\";\n\n/**\n * Every source-layer the Planetiler (OpenMapTiles-schema) tiles emit.\n * The style skeleton covers all of them; extra layers referencing anything\n * else are rejected. Mirrors `sn_style::SOURCE_LAYERS`.\n */\nexport const SOURCE_LAYERS: readonly string[] = [\n \"aerodrome_label\",\n \"aeroway\",\n \"boundary\",\n \"building\",\n \"housenumber\",\n \"landcover\",\n \"landuse\",\n \"mountain_peak\",\n \"park\",\n \"place\",\n \"poi\",\n \"transportation\",\n \"transportation_name\",\n \"water\",\n \"water_name\",\n \"waterway\",\n];\n\n/**\n * The named palette slots as `[slot, lightDefault, darkDefault]`, mirroring\n * `sn_style::palette_slots()`. Order is stable and documentation-worthy: it\n * is the order a Studio UI should present them in.\n */\nexport const PALETTE_SLOTS: readonly (readonly [string, string, string])[] = [\n [\"background\", \"#f4f2ee\", \"#12161c\"],\n [\"water\", \"#a8c8e8\", \"#1b2c40\"],\n [\"waterway\", \"#a8c8e8\", \"#1b2c40\"],\n [\"landcover\", \"#e3e8dd\", \"#182029\"],\n [\"landuse\", \"#ece8e1\", \"#171e26\"],\n [\"park\", \"#c8e2bf\", \"#1a2a1f\"],\n [\"building\", \"#e0d6c4\", \"#252d37\"],\n [\"aeroway\", \"#dcd9d2\", \"#232b34\"],\n [\"road\", \"#ffffff\", \"#2b333d\"],\n [\"roadMajor\", \"#f6d9a0\", \"#4a5461\"],\n [\"path\", \"#d9d4ca\", \"#2a323c\"],\n [\"rail\", \"#d0cbc2\", \"#262e37\"],\n [\"boundary\", \"#b9a6c9\", \"#4a3d57\"],\n [\"boundaryMinor\", \"#c9bcd6\", \"#3a3247\"],\n [\"textPrimary\", \"#3a3a3a\", \"#d6dbe1\"],\n [\"textSecondary\", \"#6b6b6b\", \"#9aa3ad\"],\n [\"textHalo\", \"#ffffff\", \"#12161c\"],\n];\n\n/**\n * Per-layer override: merged onto the skeleton layer with the same id.\n * Mirrors `sn_style::LayerOverride`.\n */\nexport interface LayerOverride {\n /** Hide the layer entirely (`layout.visibility = \"none\"`). */\n visible?: boolean;\n /** Paint properties merged over the skeleton's (per-key, override wins). */\n paint?: Record<string, unknown>;\n /** Layout properties merged over the skeleton's. */\n layout?: Record<string, unknown>;\n /** Replace the skeleton's filter (per-attribute styling hook). */\n filter?: unknown;\n minzoom?: number;\n maxzoom?: number;\n}\n\n/**\n * The optional visual-effects block, mirroring `sn_style::Effects`. Unlike\n * `extra`, this IS carried into the compiled style — as\n * `metadata[\"mapmap:effects\"]` — so any consumer of a compiled `style.json`\n * (hosted style URL, baked territory package) can honour it without the\n * theme document. Renderers that do not know the effects engine ignore the\n * metadata and render the style unchanged.\n */\nexport interface ThemeEffects {\n /** Route-line effect: `\"flow\"` (animated energy ribbon) or `\"none\"`. */\n route?: \"flow\" | \"none\";\n /**\n * Effect parameters, validated per effect. For `flow`: `color` (CSS\n * colour), `width` (px, 0.5-40), `speed` (cycles/s, 0-10).\n */\n params?: Record<string, unknown>;\n}\n\n/** The accepted `params` keys for the `flow` effect. */\nconst FLOW_PARAM_KEYS: readonly string[] = [\"color\", \"width\", \"speed\"];\n\n/**\n * Validate a theme's effects block, mirroring\n * `sn_style::theme::validate_effects` (same agent-readable messages).\n */\nfunction validateEffects(effects: ThemeEffects): void {\n const route = effects.route ?? \"none\";\n if (route !== \"flow\" && route !== \"none\") {\n throw new Error(\n `invalid effects block: unknown route effect ${JSON.stringify(route)}; ` +\n 'accepted: \"flow\", \"none\"',\n );\n }\n if (!effects.params) return;\n if (route === \"none\") {\n throw new Error(\n 'invalid effects block: \"params\" requires \"route\" to name an effect (e.g. \"flow\")',\n );\n }\n for (const [key, value] of Object.entries(effects.params)) {\n if (key === \"color\") {\n if (typeof value !== \"string\" || !isCssColour(value)) {\n throw new Error(\n `invalid effects block: params.color has invalid colour ` +\n `${JSON.stringify(value)}; use #rgb/#rrggbb/#rrggbbaa or ` +\n \"rgb()/rgba()/hsl()/hsla()\",\n );\n }\n } else if (key === \"width\") {\n if (typeof value !== \"number\" || value < 0.5 || value > 40) {\n throw new Error(\n \"invalid effects block: params.width must be a number between \" +\n `0.5 and 40 (pixels), got ${JSON.stringify(value)}`,\n );\n }\n } else if (key === \"speed\") {\n if (typeof value !== \"number\" || value < 0 || value > 10) {\n throw new Error(\n \"invalid effects block: params.speed must be a number between \" +\n `0 and 10 (cycles per second), got ${JSON.stringify(value)}`,\n );\n }\n } else {\n throw new Error(\n `invalid effects block: unknown params key ${JSON.stringify(key)}; ` +\n `accepted keys: ${FLOW_PARAM_KEYS.join(\", \")}`,\n );\n }\n }\n}\n\n/**\n * A MapMap Studio theme: the unit users and agents edit, store and publish.\n * Mirrors `sn_style::Theme` (all fields carry serde defaults, so everything\n * is optional here).\n */\nexport interface Theme {\n /** Human-readable theme name, e.g. `\"midnight-fleet\"`. */\n name?: string;\n /** Built-in palette to start from. Defaults to `\"light\"`. */\n base?: MapMapTheme;\n /** Palette overrides by slot name (see {@link PALETTE_SLOTS}). */\n palette?: Record<string, string>;\n /** Per-layer overrides by skeleton layer id. */\n layers?: Record<string, LayerOverride>;\n /**\n * Render buildings as 3D extrusions. Adds a `building-3d` fill-extrusion\n * layer (zoom 15+) driven by the tiles' `render_height` /\n * `render_min_height` attributes, and caps the flat `building` footprint\n * layer at that zoom so the two hand off cleanly (the extrusion rises\n * from flat as you zoom in). Web-safe; native navigation SDKs should\n * leave this off by default until MapLibre Native's fill-extrusion\n * memory use at street zooms is fixed (maplibre-native#4107). Mirrors\n * `Theme::buildings_3d`.\n */\n buildings_3d?: boolean;\n /**\n * Label fonts. Every fontstack must exist on the glyph server; until that\n * ships (P2), leave this at its default (`\"MapMap Sans Regular\"`).\n */\n fonts?: { regular?: string };\n /** Override the glyph endpoint (defaults to {@link DEFAULT_GLYPHS_URL}). */\n glyphs?: string;\n /** Optional sprite URL (icons/shields - P2, no default sprite exists). */\n sprite?: string;\n /**\n * Extra fully-formed MapLibre layers appended above the skeleton (below\n * labels). Each must reference the `territory` source and a known\n * source-layer.\n */\n extra_layers?: JsonObject[];\n /**\n * Optional visual effects (route ribbon etc.). Compiled into\n * `metadata[\"mapmap:effects\"]` on the style — see {@link ThemeEffects}.\n * Mirrors `Theme::effects`.\n */\n effects?: ThemeEffects;\n /**\n * Non-style extras carried by the THEME DOCUMENT, not the compiled\n * style. Studio stores its navigation design block here (`extra.nav`;\n * see `nav-design.ts`) and its POI category design (`extra.poi`; see\n * `poi-design.ts`). {@link buildStyle} ignores it entirely - the\n * compiled `style.json` is byte-identical with or without it. Mirrors\n * `Theme::extra` in the canonical Rust crate: the hosted styles API\n * stores the block verbatim (bounded at 256 KB serialised) and serves it\n * back from `GET /styles/{id}/theme`, so a Studio design survives\n * publishing - consume it via `createMap` with a theme document or\n * `navDesignFromThemeUrl` / `poiDesignFromThemeUrl` with the hosted\n * theme URL.\n */\n extra?: { nav?: unknown; poi?: unknown };\n}\n\nexport interface BuildStyleOptions {\n /**\n * Label language: an ISO 639 code selects `name:<code>` with a\n * local-name fallback; the literal `\"local\"` selects the local name\n * outright; omitted keeps the default (English-first). The tiles carry\n * the OSM `name:*` set, so switching involves no tile rebuild.\n */\n labelLanguage?: string;\n /**\n * Theme to build: a built-in name (`\"light\"` / `\"dark\"`) or a full\n * {@link Theme} document. Defaults to `\"light\"`.\n */\n theme?: MapMapTheme | Theme;\n /**\n * PMTiles URL for the territory tiles. Accepts either a `pmtiles://…` URL\n * or a plain `https://…` URL (the `pmtiles://` prefix is added for you).\n */\n territoryTilesUrl?: string;\n}\n\n/** Ensure a tiles URL carries the `pmtiles://` protocol prefix. */\nexport function toPmtilesUrl(url: string): string {\n return url.startsWith(\"pmtiles://\") ? url : `pmtiles://${url}`;\n}\n\n/**\n * Cheap CSS colour check: hex forms and the functional notations MapLibre\n * accepts. Deliberately permissive on the inside of `rgb()`/`hsl()`.\n * Mirrors `sn_style::theme::is_css_colour`.\n */\nfunction isCssColour(value: string): boolean {\n const v = value.trim();\n if (v.startsWith(\"#\")) {\n const hex = v.slice(1);\n return (\n [3, 4, 6, 8].includes(hex.length) && /^[0-9a-fA-F]+$/.test(hex)\n );\n }\n for (const prefix of [\"rgb(\", \"rgba(\", \"hsl(\", \"hsla(\"]) {\n if (v.startsWith(prefix) && v.endsWith(\")\")) return true;\n }\n return false;\n}\n\n/**\n * Resolve the effective palette for a theme: base defaults + overrides.\n * Fails on unknown slots or unparseable colours (agent self-correction).\n * Mirrors `sn_style::theme::resolve_palette`.\n */\nfunction resolvePalette(theme: Theme): Record<string, string> {\n const base = theme.base ?? \"light\";\n const palette: Record<string, string> = {};\n // Membership is checked against the slot list, not with `in` (which would\n // accept Object.prototype keys like \"toString\" that the Rust compiler\n // rejects as UnknownPaletteSlot).\n const knownSlots = new Set(PALETTE_SLOTS.map(([slot]) => slot));\n for (const [slot, light, dark] of PALETTE_SLOTS) {\n palette[slot] = base === \"dark\" ? dark : light;\n }\n for (const [slot, value] of Object.entries(theme.palette ?? {})) {\n if (!knownSlots.has(slot)) {\n const accepted = PALETTE_SLOTS.map(([s]) => s).join(\", \");\n throw new Error(\n `unknown palette slot ${JSON.stringify(slot)}; accepted slots: ${accepted}`,\n );\n }\n if (!isCssColour(value)) {\n throw new Error(\n `palette slot ${JSON.stringify(slot)} has invalid colour ` +\n `${JSON.stringify(value)}; use #rgb/#rrggbb/#rrggbbaa or ` +\n \"rgb()/rgba()/hsl()/hsla()\",\n );\n }\n palette[slot] = value;\n }\n return palette;\n}\n\n/**\n * Per-channel linear blend of two `#rrggbb` colours: `t` = 0 returns `a`,\n * `t` = 1 returns `b`. Mirrors `compile.rs`'s `mix()`.\n *\n * Used to DERIVE road-casing and building-outline colours from existing\n * palette slots rather than adding new ones — the 17-slot palette is a\n * published contract, and deriving means user overrides flow through\n * automatically. Blending against `textSecondary` (which flips with\n * light/dark themes) keeps the derived edges visible in both for free.\n *\n * Inputs that are not 6-digit hex are returned as-is (`a`), so a theme\n * carrying an exotic colour value degrades to no tint rather than NaN.\n *\n * Exported for tests; deliberately not re-exported from the package index.\n */\nexport function mixColour(a: string, b: string, t: number): string {\n const parse = (s: string): [number, number, number] | null =>\n /^#[0-9a-fA-F]{6}$/.test(s)\n ? [\n parseInt(s.slice(1, 3), 16),\n parseInt(s.slice(3, 5), 16),\n parseInt(s.slice(5, 7), 16),\n ]\n : null;\n const ca = parse(a);\n const cb = parse(b);\n if (!ca || !cb) return a;\n const k = Math.min(1, Math.max(0, t));\n const hex = (i: 0 | 1 | 2): string =>\n Math.min(255, Math.max(0, Math.round(ca[i] + (cb[i] - ca[i]) * k)))\n .toString(16)\n .padStart(2, \"0\");\n return `#${hex(0)}${hex(1)}${hex(2)}`;\n}\n\n/** Skeleton fill layer, mirroring `compile.rs`'s `fill()` helper. */\n\n/**\n * Per-class tint for the `landuse` fill. Mirrors `landuse_colour()` in\n * compile.rs.\n *\n * Landuse was one flat colour, so a hospital campus, a school field and a\n * retail park were visually the same object. The tints are DERIVED from\n * existing palette slots via `mixColour` rather than added as new slots: the\n * palette is a documented 17-slot contract, and a per-class slot explosion\n * would be a breaking change to every saved theme and preset.\n *\n * The `match` input is `[\"get\", \"class\"]` with a default branch, so classes\n * absent from this list (and features with no `class` at all, where `get`\n * yields null) fall through to the untinted slot colour rather than\n * disappearing. Kept deliberately subtle - these are background fills.\n */\nfunction landuseColour(p: (slot: string) => string): unknown[] {\n const base = p(\"landuse\");\n return [\n \"match\",\n [\"get\", \"class\"],\n // Civic/medical: leans towards the building tone.\n [\"hospital\"], mixColour(base, p(\"building\"), 0.55),\n // Education campuses read as semi-green grounds.\n [\"school\", \"university\", \"college\", \"kindergarten\", \"library\"],\n mixColour(base, p(\"park\"), 0.35),\n [\"cemetery\"], mixColour(base, p(\"park\"), 0.6),\n // Sports/play surfaces borrow the park green outright.\n [\"pitch\", \"playground\"], mixColour(base, p(\"park\"), 0.75),\n // Restricted land greys off.\n [\"military\"], mixColour(base, p(\"textSecondary\"), 0.3),\n [\"retail\", \"commercial\"], mixColour(base, p(\"building\"), 0.35),\n [\"residential\", \"suburb\", \"neighbourhood\"], mixColour(base, p(\"building\"), 0.18),\n [\"railway\"], mixColour(base, p(\"textSecondary\"), 0.2),\n base,\n ];\n}\n\n/**\n * Per-class tint for the `landcover` fill - see `landuseColour` for why these\n * are mixed from existing slots rather than given palette slots. Mirrors\n * `landcover_colour()` in compile.rs.\n */\nfunction landcoverColour(p: (slot: string) => string): unknown[] {\n const base = p(\"landcover\");\n return [\n \"match\",\n [\"get\", \"class\"],\n [\"wood\", \"forest\"], mixColour(base, p(\"park\"), 0.75),\n [\"grass\"], mixColour(base, p(\"park\"), 0.45),\n [\"wetland\"], mixColour(base, p(\"park\"), 0.3),\n [\"farmland\"], mixColour(base, p(\"landuse\"), 0.4),\n [\"sand\"], mixColour(base, p(\"building\"), 0.5),\n [\"rock\"], mixColour(base, p(\"textSecondary\"), 0.25),\n base,\n ];\n}\n\n/**\n * `[\"!in\", \"class\", ...]` excluding everything in the `transportation` layer\n * that is not a driveable road, for the layers (bridges, one-way arrows) that\n * address the road network as a whole rather than by rank. Mirrors\n * `not_a_road_filter()` in compile.rs.\n */\nfunction notARoadFilter(): unknown[] {\n return [\"!in\", \"class\", \"rail\", \"transit\", \"ferry\", \"path\", \"track\", \"pedestrian\", \"aerialway\"];\n}\n\n/**\n * Tunnels dim so they read as passing UNDER the surrounding network. Mirrors\n * `tunnel_opacity()` in compile.rs.\n *\n * `line-dasharray` would be the other conventional treatment but it takes no\n * data expression in MapLibre, so it cannot be driven off `brunnel` without\n * splitting every road layer in two. Opacity is the proportionate choice.\n *\n * `match` on a missing field is safe: `[\"get\", \"brunnel\"]` yields null for the\n * ~86% of features that carry no brunnel, and null takes the default.\n */\nfunction tunnelOpacity(): unknown[] {\n return [\"match\", [\"get\", \"brunnel\"], \"tunnel\", 0.55, 1.0];\n}\n\nfunction fill(\n id: string,\n sourceLayer: string,\n // Widened from `string` for the per-class `match` expressions that tint\n // landuse/landcover (see `landuseColour`).\n colour: string | unknown[],\n opacity: number,\n minzoom?: number,\n): JsonObject {\n const layer: JsonObject = {\n id,\n type: \"fill\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n paint: { \"fill-color\": colour, \"fill-opacity\": opacity },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Skeleton symbol layer, mirroring `compile.rs`'s `symbol()` helper. */\nfunction symbol(\n id: string,\n sourceLayer: string,\n textField: unknown,\n font: readonly string[],\n textSize: unknown,\n colour: string,\n halo: string,\n minzoom?: number,\n extraLayout?: JsonObject,\n): JsonObject {\n const layout: JsonObject = {\n \"text-field\": textField,\n \"text-font\": font,\n \"text-size\": textSize,\n ...extraLayout,\n };\n const layer: JsonObject = {\n id,\n type: \"symbol\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n layout,\n paint: {\n \"text-color\": colour,\n \"text-halo-color\": halo,\n \"text-halo-width\": 1.2,\n },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Apply a per-layer override, mirroring `compile.rs`'s `apply_override`. */\nfunction applyOverride(layer: JsonObject, layerOverride: LayerOverride): void {\n if (layerOverride.paint) mergeObject(layer, \"paint\", layerOverride.paint);\n if (layerOverride.layout) mergeObject(layer, \"layout\", layerOverride.layout);\n if (layerOverride.filter !== undefined) layer[\"filter\"] = layerOverride.filter;\n if (layerOverride.minzoom !== undefined) layer[\"minzoom\"] = layerOverride.minzoom;\n if (layerOverride.maxzoom !== undefined) layer[\"maxzoom\"] = layerOverride.maxzoom;\n if (layerOverride.visible === false) {\n const layout = (layer[\"layout\"] ??= {}) as JsonObject;\n layout[\"visibility\"] = \"none\";\n }\n}\n\nfunction mergeObject(\n layer: JsonObject,\n key: \"paint\" | \"layout\",\n overrides: Record<string, unknown>,\n): void {\n const target = (layer[key] ??= {}) as JsonObject;\n for (const [k, v] of Object.entries(overrides)) target[k] = v;\n}\n\n/** Validate one extra layer, mirroring `compile.rs`'s `validate_extra_layer`. */\nfunction validateExtraLayer(index: number, layer: unknown): JsonObject {\n const invalid = (reason: string): Error =>\n new Error(`extra layer ${index} is invalid: ${reason}`);\n if (typeof layer !== \"object\" || layer === null || Array.isArray(layer)) {\n throw invalid(\"must be an object\");\n }\n const obj = layer as JsonObject;\n const id = obj[\"id\"];\n if (typeof id !== \"string\") throw invalid('must have a string \"id\"');\n if (id.length === 0) throw invalid('\"id\" must be non-empty');\n if (obj[\"type\"] !== \"background\") {\n if (obj[\"source\"] !== \"territory\") {\n throw invalid('\"source\" must be \"territory\"');\n }\n const sourceLayer = obj[\"source-layer\"];\n if (typeof sourceLayer !== \"string\") {\n throw invalid('must have a string \"source-layer\"');\n }\n if (!SOURCE_LAYERS.includes(sourceLayer)) {\n throw invalid(\n `unknown source-layer ${JSON.stringify(sourceLayer)}; accepted: ` +\n SOURCE_LAYERS.join(\", \"),\n );\n }\n }\n return obj;\n}\n\n/**\n * Assemble a full MapLibre style for the MapMap tiles - a faithful port of\n * `sn_style::compile`, so a {@link Theme} compiles to the same style here\n * as it does in `sn-factory`/`sn-gateway`. Pure: returns a plain object,\n * touches no browser APIs, and is safe to snapshot in tests.\n *\n * Throws an `Error` with an agent-readable message (offending key + the\n * accepted values) on unknown palette slots, invalid colours, unknown layer\n * ids and invalid extra layers, mirroring `sn_style::StyleError`.\n */\n/**\n * The accepted top-level {@link Theme} keys (mirrors serde\n * `deny_unknown_fields`). `extra` is the one deliberate divergence from the\n * Rust crate: it carries Studio's nav design block in the theme FILE and is\n * ignored by compilation (the gateway still rejects it on `/styles`, which\n * is why Studio strips it on publish).\n */\nconst THEME_KEYS: readonly string[] = [\n \"name\",\n \"base\",\n \"palette\",\n \"layers\",\n \"fonts\",\n \"glyphs\",\n \"sprite\",\n \"extra_layers\",\n \"extra\",\n \"buildings_3d\",\n \"effects\",\n];\n\n/**\n * The `metadata` key a compiled style carries its effects block under.\n * Shared with `sn-style` (compile.rs) and read back by `MapMapMap` to\n * auto-enable the route effect for styles that request one.\n */\nexport const EFFECTS_METADATA_KEY = \"mapmap:effects\";\n\n/**\n * The effects block from a compiled style's `metadata`, if the style\n * carries a valid one (`{ route: \"flow\", params? }`). Lenient by design —\n * it reads FOREIGN styles (hosted URLs, baked packages), so anything\n * malformed returns `undefined` rather than throwing.\n */\nexport function effectsFromStyleMetadata(\n metadata: unknown,\n): { route: \"flow\"; params?: Record<string, unknown> } | undefined {\n if (typeof metadata !== \"object\" || metadata === null) return undefined;\n const block = (metadata as JsonObject)[EFFECTS_METADATA_KEY];\n if (typeof block !== \"object\" || block === null) return undefined;\n const { route, params } = block as JsonObject;\n if (route !== \"flow\") return undefined;\n return typeof params === \"object\" && params !== null\n ? { route, params: params as Record<string, unknown> }\n : { route };\n}\n\n/**\n * Zoom at which 3D building extrusions start (and the flat footprint layer\n * stops) when a theme sets `buildings_3d`. Mirrors\n * `compile.rs::BUILDINGS_3D_MINZOOM`. Exported for\n * `MapMapMap.setBuildings3d`, which performs the same handoff at runtime.\n */\nexport const BUILDINGS_3D_MINZOOM = 15;\n\n/**\n * The `building-3d` fill-extrusion layer a theme with `buildings_3d` gets:\n * heights from the tiles' `render_height`/`render_min_height` (5 m coalesce\n * fallback for tiles missing them), rising from flat over half a zoom so\n * the handoff from the footprint layer is seamless. Mirrors the layer\n * `compile.rs` emits, byte for byte. Shared by {@link buildStyle} and\n * `MapMapMap.setBuildings3d` so the two can never drift.\n */\nexport function buildings3dLayer(colour: unknown): JsonObject {\n return {\n id: \"building-3d\",\n type: \"fill-extrusion\",\n source: \"territory\",\n \"source-layer\": \"building\",\n minzoom: BUILDINGS_3D_MINZOOM,\n paint: {\n \"fill-extrusion-color\": colour,\n \"fill-extrusion-height\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_height\"], 5],\n ],\n \"fill-extrusion-base\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_min_height\"], 0],\n ],\n \"fill-extrusion-opacity\": 0.85,\n \"fill-extrusion-vertical-gradient\": true,\n },\n };\n}\n\n/** The `text-field` expression for the requested label language. */\nfunction nameFieldFor(labelLanguage?: string): unknown {\n if (labelLanguage === \"local\") return [\"get\", \"name\"];\n if (labelLanguage) return [\"coalesce\", [\"get\", `name:${labelLanguage}`], [\"get\", \"name\"]];\n return [\"coalesce\", [\"get\", \"name:en\"], [\"get\", \"name\"]];\n}\n\nexport function buildStyle(options: BuildStyleOptions = {}): StyleSpecification {\n const input = options.theme ?? \"light\";\n if (typeof input === \"object\") {\n // Mirror the Rust Theme's serde deny_unknown_fields: a typo'd key\n // (e.g. \"extraLayers\", \"pallete\") must fail loudly here too, not\n // silently render the default style.\n for (const key of Object.keys(input)) {\n if (!THEME_KEYS.includes(key)) {\n throw new Error(\n `unknown theme field ${JSON.stringify(key)}; accepted fields: ` +\n THEME_KEYS.join(\", \"),\n );\n }\n }\n }\n const theme: Theme =\n typeof input === \"string\" ? { name: input, base: input } : input;\n const palette = resolvePalette(theme);\n const p = (slot: string): string => palette[slot] as string;\n const font = [theme.fonts?.regular ?? \"MapMap Sans Regular\"] as const;\n const nameField = nameFieldFor(options.labelLanguage);\n const tilesUrl = toPmtilesUrl(\n options.territoryTilesUrl ?? DEFAULT_TERRITORY_TILES_URL,\n );\n\n // The skeleton: every OpenMapTiles source-layer styled, palette-driven.\n // Order is paint order (first = bottom). Mirrors compile.rs exactly.\n const layers: JsonObject[] = [\n {\n id: \"background\",\n type: \"background\",\n paint: { \"background-color\": p(\"background\") },\n },\n fill(\"landcover\", \"landcover\", landcoverColour(p), 0.6),\n fill(\"landuse\", \"landuse\", landuseColour(p), 0.45),\n fill(\"park\", \"park\", p(\"park\"), 0.7),\n fill(\"water\", \"water\", p(\"water\"), 1.0),\n {\n id: \"waterway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"waterway\",\n paint: {\n \"line-color\": p(\"waterway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.5, 16, 3],\n },\n },\n {\n id: \"aeroway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"aeroway\",\n minzoom: 10,\n filter: [\"in\", \"class\", \"runway\", \"taxiway\"],\n paint: {\n \"line-color\": p(\"aeroway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 10, 1, 16, 6],\n },\n },\n fill(\"building\", \"building\", p(\"building\"), 1.0, 13),\n // Building footprints sit at barely 1.2:1 against the background, so at\n // street zooms the fill alone reads as nothing. An outline restores the\n // block structure without touching the `building` slot default or the\n // fill opacity, which would alter every saved theme and preset. Starts\n // at BUILDINGS_3D_MINZOOM so it hands off to the extrusion at exactly\n // the zoom the flat fill does.\n {\n id: \"building-outline\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"building\",\n minzoom: BUILDINGS_3D_MINZOOM,\n paint: {\n \"line-color\": mixColour(p(\"building\"), p(\"textSecondary\"), 0.6),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 15, 0.3, 20, 1.6,\n ],\n },\n },\n {\n id: \"rail\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 8,\n filter: [\"in\", \"class\", \"rail\", \"transit\"],\n paint: {\n \"line-color\": p(\"rail\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 8, 0.4, 14, 1.6, 20, 6,\n ],\n },\n },\n // The `transportation` layer carries POLYGON features for pedestrian\n // plazas and footway areas (61 in a single Soho tile). Without a fill\n // they were only ever hairline-dashed as outlines, leaving town centres\n // empty.\n {\n id: \"pedestrian-areas\",\n type: \"fill\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 14,\n // A fill layer only ever draws polygonal geometry, so the class match\n // is the whole filter. An explicit [\"==\", [\"geometry-type\"], \"Polygon\"]\n // clause looks right but matches NOTHING here: MapLibre reports these\n // multi-ring plazas as \"MultiPolygon\" (verified live — the clause\n // rendered 0 of 73 features).\n filter: [\"match\", [\"get\", \"class\"], [\"path\", \"pedestrian\"], true, false],\n paint: {\n \"fill-color\": p(\"path\"),\n \"fill-opacity\": 0.7,\n },\n },\n {\n id: \"road-path\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"in\", \"class\", \"path\", \"track\", \"pedestrian\"],\n paint: {\n \"line-color\": p(\"path\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 13, 0.8, 16, 2.5, 18, 6, 20, 18,\n ],\n \"line-dasharray\": [3, 1.5],\n },\n },\n // Road casings. ALL casings are drawn beneath ALL road fills (rather\n // than casing/fill pairs) so that at junctions a minor road's casing\n // never paints over a major road's fill. Colours are derived, not new\n // palette slots — see `mixColour`.\n {\n id: \"road-minor-casing\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\n \"!in\",\n \"class\",\n \"motorway\",\n \"trunk\",\n \"primary\",\n \"rail\",\n \"transit\",\n \"path\",\n \"track\",\n \"pedestrian\",\n \"ferry\",\n ],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": mixColour(p(\"road\"), p(\"textSecondary\"), 0.45),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 12, 0.5, 14, 5, 16, 10, 17, 14, 18, 21, 19, 37, 20, 64,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n {\n id: \"road-major-casing\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 6,\n filter: [\"in\", \"class\", \"motorway\", \"trunk\", \"primary\"],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": mixColour(p(\"roadMajor\"), p(\"textSecondary\"), 0.45),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 6, 2, 14, 8, 16, 13, 17, 19, 18, 30, 19, 54, 20, 96,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n // Road widths ramp all the way to z20. They previously ended at z16, so\n // z17+ rendered frozen at z16 weights (4 px minor) against a 15-30 px\n // reference — the \"schematic lines\" bug.\n // Fills take round caps/joins like their casings: with the default butt\n // caps, consecutive segments split at junction nodes leave wedge gaps\n // the casing shows through — a pale notch exactly where roads join.\n {\n id: \"road-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\n \"!in\",\n \"class\",\n \"motorway\",\n \"trunk\",\n \"primary\",\n \"rail\",\n \"transit\",\n \"path\",\n \"track\",\n \"pedestrian\",\n \"ferry\",\n ],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": p(\"road\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 8, 0.5, 13, 1.5, 14, 3, 16, 7, 17, 10, 18, 16, 19, 29, 20, 52,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n {\n id: \"road-major\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\"in\", \"class\", \"motorway\", \"trunk\", \"primary\"],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": p(\"roadMajor\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 6, 1, 14, 5.5, 16, 10, 17, 15, 18, 24, 19, 44, 20, 80,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n // Bridges are REDRAWN on top of the whole flat road network (casing\n // then fill) so an overpass reads as crossing over what it spans\n // instead of as a flat junction. This is the proportionate treatment:\n // true multi-level ordering would need one layer pair per distinct\n // `layer` value, which is unbounded. The extra-wide casing supplies the\n // shadow edge that sells the crossing.\n {\n id: \"road-bridge-casing\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"all\", [\"==\", \"brunnel\", \"bridge\"], notARoadFilter()],\n layout: { \"line-cap\": \"butt\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": mixColour(p(\"road\"), p(\"textSecondary\"), 0.8),\n \"line-width\": [\"interpolate\", [\"exponential\", 1.2], [\"zoom\"], 13, 3, 16, 13, 17, 19, 18, 30, 19, 54, 20, 96],\n },\n },\n {\n id: \"road-bridge\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"all\", [\"==\", \"brunnel\", \"bridge\"], notARoadFilter()],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": [\n \"match\",\n [\"get\", \"class\"],\n [\"motorway\", \"trunk\", \"primary\"], p(\"roadMajor\"),\n p(\"road\"),\n ],\n \"line-width\": [\"interpolate\", [\"exponential\", 1.2], [\"zoom\"], 13, 1.5, 16, 8, 17, 15, 18, 24, 19, 44, 20, 80],\n },\n },\n {\n id: \"boundary-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n minzoom: 6,\n filter: [\"all\", [\">=\", \"admin_level\", 3], [\"<=\", \"admin_level\", 8]],\n paint: {\n \"line-color\": p(\"boundaryMinor\"),\n \"line-width\": 0.6,\n \"line-dasharray\": [2, 2],\n },\n },\n {\n id: \"boundary\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n filter: [\"<=\", \"admin_level\", 2],\n paint: {\n \"line-color\": p(\"boundary\"),\n \"line-width\": 1,\n \"line-dasharray\": [3, 2],\n },\n },\n ];\n\n // 3D buildings: a fill-extrusion layer above the road network (2D layers\n // drawn after an extrusion paint over its pitched volumes, so it must\n // come last in the base map), below extras and labels. The flat\n // footprint layer is capped at the extrusion minzoom. Mirrors compile.rs.\n if (theme.buildings_3d) {\n // Both the flat fill AND its outline hand off to the extrusion at the\n // same zoom, so the 2D block edges do not keep drawing on top of the\n // pitched volumes.\n for (const id of [\"building\", \"building-outline\"]) {\n const flat = layers.find((l) => l[\"id\"] === id) as JsonObject;\n flat[\"maxzoom\"] = BUILDINGS_3D_MINZOOM;\n }\n layers.push(buildings3dLayer(p(\"building\")));\n }\n\n // User/agent-supplied extra layers sit above the base map, below labels.\n (theme.extra_layers ?? []).forEach((extra, index) => {\n layers.push(structuredClone(validateExtraLayer(index, extra)));\n });\n\n layers.push(\n // One-way arrows, drawn as a TEXT symbol rather than a sprite icon. The\n // skeleton ships no sprite at all (`sprite` is an optional user-supplied\n // URL), so an `icon-image` arrow would render nothing for every default\n // style - a text glyph needs only the glyph server the labels already use.\n //\n // The font is PINNED rather than following `theme.fonts`: U+2192 is absent\n // from 5 of the bundled fontstacks (Barlow, Noto Serif, Nunito, Open\n // Sans, Rubik - verified by decoding their 8448-8703 glyph ranges), so a\n // themed font would silently drop every arrow. \"MapMap Sans Regular\" is\n // the default fontstack and carries it (verified the same way).\n //\n // `text-keep-upright` MUST be false: left at its `true` default MapLibre\n // flips glyphs on right-to-left line segments to keep them readable, which\n // would reverse the very thing the arrow encodes.\n {\n id: \"road-oneway\",\n type: \"symbol\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 16,\n // `oneway` is 1 (forward), -1 (reverse) or 0/absent. The string forms\n // are matched too: legacy `==` is strictly typed, and a tile build that\n // encodes the attribute as a string would otherwise match nothing.\n filter: [\n \"all\",\n [\n \"any\",\n [\"==\", \"oneway\", 1],\n [\"==\", \"oneway\", -1],\n [\"==\", \"oneway\", \"1\"],\n [\"==\", \"oneway\", \"-1\"],\n ],\n notARoadFilter(),\n ],\n layout: {\n \"symbol-placement\": \"line\",\n \"symbol-spacing\": 200,\n \"text-field\": \"\\u2192\",\n \"text-font\": [\"MapMap Sans Regular\"],\n \"text-size\": [\"interpolate\", [\"linear\"], [\"zoom\"], 16, 8, 20, 12],\n \"text-rotation-alignment\": \"map\",\n \"text-pitch-alignment\": \"map\",\n \"text-keep-upright\": false,\n // -1 means the arrow points against the digitisation direction.\n \"text-rotate\": [\n \"case\",\n [\"any\", [\"==\", [\"get\", \"oneway\"], -1], [\"==\", [\"get\", \"oneway\"], \"-1\"]],\n 180,\n 0,\n ],\n // Arrows are road furniture, not labels: they should not lose\n // collisions with names, nor push them out.\n \"text-allow-overlap\": true,\n \"text-ignore-placement\": true,\n },\n paint: {\n \"text-color\": mixColour(p(\"road\"), p(\"textSecondary\"), 0.55),\n \"text-halo-color\": p(\"textHalo\"),\n \"text-halo-width\": 1.0,\n },\n },\n symbol(\n \"housenumber\",\n \"housenumber\",\n [\"get\", \"housenumber\"],\n font,\n 10,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 17,\n ),\n symbol(\n \"road-labels\",\n \"transportation_name\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 12, 11, 16, 12.5, 20, 15],\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 12,\n {\n \"symbol-placement\": \"line\",\n // Street names must be able to REPEAT along a long road: at z18 the\n // map was drawing 80 POI labels to 11 road labels, reading as a pin\n // cloud rather than a street network. Spacing tightens as the same\n // street comes to fill more of the screen.\n \"symbol-spacing\": [\"interpolate\", [\"linear\"], [\"zoom\"], 12, 400, 16, 260, 18, 320, 20, 520],\n },\n ),\n symbol(\n \"water-name\",\n \"water_name\",\n nameField,\n font,\n 12,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n {\n // POI rebalancing. `poi.rank` is populated on 100% of features (1 = most\n // prominent), so it can do two jobs: a zoom-stepped ceiling admits only the\n // headline POIs at mid zooms and opens right up by z18, where the user has\n // asked for detail; and `symbol-sort-key` makes the survivors compete by\n // rank, so when labels do collide the landmark wins and the vape shop\n // loses. Lower sort key = placed first, and lower rank = more important, so\n // `rank` can be used directly. This rebalances rather than hides.\n ...symbol(\n \"poi-labels\",\n \"poi\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 14,\n {\n \"text-anchor\": \"top\",\n \"symbol-sort-key\": [\"coalesce\", [\"get\", \"rank\"], 99],\n },\n ),\n filter: [\n \"<=\",\n [\"coalesce\", [\"get\", \"rank\"], 99],\n [\"step\", [\"zoom\"], 6, 15, 10, 16, 15, 17, 22, 18, 40, 19, 120],\n ],\n },\n symbol(\n \"mountain-peak-labels\",\n \"mountain_peak\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n symbol(\n \"aerodrome-labels\",\n \"aerodrome_label\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 10,\n ),\n // Label hierarchy: settlements and regions wait until z4 so world\n // zooms aren't a flat democracy of states, cities and villages;\n // continent labels are dropped entirely as clutter.\n {\n ...symbol(\n \"place-labels\",\n \"place\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 4, 10.5, 12, 16],\n p(\"textPrimary\"),\n p(\"textHalo\"),\n 4,\n ),\n filter: [\"match\", [\"get\", \"class\"], [\"country\", \"continent\"], false, true],\n },\n // Countries: the most prominent text on the map at world zooms —\n // larger, letter-spaced, visible from z1, ceding to the regional\n // hierarchy from z10. Drawn last = wins label collisions.\n {\n ...symbol(\n \"country-labels\",\n \"place\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 1, 11, 3, 13.5, 6, 18],\n p(\"textPrimary\"),\n p(\"textHalo\"),\n 1,\n { \"text-letter-spacing\": 0.08, \"text-max-width\": 7 },\n ),\n filter: [\"==\", [\"get\", \"class\"], \"country\"],\n maxzoom: 10,\n },\n );\n\n // Reject duplicate layer ids (e.g. an extra layer reusing a skeleton id),\n // mirroring `validate_style` in sn-style's validate.rs — the Rust compiler\n // rejects these and MapLibre would error at style load.\n const seenIds = new Set<string>();\n for (const layer of layers) {\n const layerId = layer[\"id\"] as string;\n if (seenIds.has(layerId)) {\n throw new Error(`duplicate layer id ${JSON.stringify(layerId)}`);\n }\n seenIds.add(layerId);\n }\n\n // Apply per-layer overrides.\n const accepted = layers.map((l) => l[\"id\"] as string).join(\", \");\n for (const [id, layerOverride] of Object.entries(theme.layers ?? {})) {\n const layer = layers.find((l) => l[\"id\"] === id);\n if (!layer) {\n throw new Error(\n `unknown layer id ${JSON.stringify(id)}; accepted ids: ${accepted}`,\n );\n }\n applyOverride(layer, layerOverride);\n }\n\n const style: JsonObject = {\n version: 8,\n name: theme.name ? `MapMap ${theme.name}` : \"MapMap\",\n glyphs: theme.glyphs ?? DEFAULT_GLYPHS_URL,\n sources: {\n territory: {\n type: \"vector\",\n url: tilesUrl,\n // Legally required (ODbL + CC-BY) - enforced, not themable. There\n // is no theme field that can remove it.\n attribution: FULL_ATTRIBUTION,\n },\n },\n layers,\n };\n if (theme.sprite !== undefined) style[\"sprite\"] = theme.sprite;\n\n // Effects ride the COMPILED style (unlike `extra`, which is theme-only):\n // `metadata[\"mapmap:effects\"]` is the one channel a hosted style URL or a\n // baked territory package carries, so `MapMapMap` can auto-enable the\n // route ribbon from the style alone. Mirrors compile.rs.\n if (theme.effects) {\n validateEffects(theme.effects);\n if ((theme.effects.route ?? \"none\") !== \"none\") {\n const block: JsonObject = { route: theme.effects.route };\n if (theme.effects.params) block[\"params\"] = theme.effects.params;\n style[\"metadata\"] = { [EFFECTS_METADATA_KEY]: block };\n }\n }\n\n // The object above is structurally a MapLibre style; the cast avoids\n // hand-satisfying every discriminated-union member of StyleSpecification.\n return style as unknown as StyleSpecification;\n}\n","/**\n * MapMapMap - the branded MapLibre GL map.\n *\n * A thin wrapper over `maplibregl.Map`. MapLibre does all the rendering; this\n * class only wires in the MapMap default style, registers the pmtiles\n * protocol, and keeps the gateway `apiKey`/`baseUrl` handy so routing and ADR\n * helpers can reuse them.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n LayerSpecification,\n Map as MlMap,\n MapOptions,\n StyleSpecification,\n} from \"maplibre-gl\";\nimport { Protocol } from \"pmtiles\";\nimport { runMapDiagnostics } from \"./diagnostics.js\";\nimport {\n createRouteEffect,\n type RouteEffectLayer,\n type RouteEffectName,\n type RouteFlowOptions,\n} from \"./effects.js\";\nimport { LogoControl, type LogoOptions } from \"./logo.js\";\nimport { navDesignFromTheme, type NavDesign } from \"./nav-design.js\";\nimport { poiDesignFromTheme, type PoiDesign } from \"./poi-design.js\";\nimport {\n BUILDINGS_3D_MINZOOM,\n buildStyle,\n buildings3dLayer,\n effectsFromStyleMetadata,\n type MapMapTheme,\n type Theme,\n} from \"./style.js\";\nimport type { RouteGeometry } from \"./types.js\";\n\n// Tracked per maplibre-gl module instance, not with a single flag: bundlers\n// can duplicate maplibre-gl, and each copy needs its own registration.\nconst pmtilesRegistered = new WeakSet<object>();\n\n/**\n * Register the `pmtiles://` protocol on a MapLibre instance. Idempotent per\n * maplibre-gl instance, and safe to call before constructing any map.\n * Exposed for apps that build their own `maplibregl.Map` (possibly from\n * their own bundled maplibre-gl copy) but still want to read MapMap PMTiles.\n */\nexport function registerPmtilesProtocol(gl: typeof maplibregl = maplibregl): void {\n if (pmtilesRegistered.has(gl)) return;\n const protocol = new Protocol();\n gl.addProtocol(\"pmtiles\", protocol.tile);\n pmtilesRegistered.add(gl);\n}\n\nexport interface MapMapOptions {\n /**\n * The MapMap wordmark on the map (like the Google Maps / Mapbox marks).\n * Default on at bottom-right, above the attribution; `false` removes\n * it, or pass `{ position, href }` to customise.\n */\n logo?: boolean | LogoOptions;\n /** The container element or its id. */\n container: string | HTMLElement;\n /** Gateway API key (`snk_…`), used by routing and ADR helpers. */\n apiKey?: string;\n /** Gateway base URL for routing/ADR. Defaults to `https://api.mapmap.ai`. */\n baseUrl?: string;\n /**\n * Style to load. A theme name (`\"light\"` / `\"dark\"`), a MapMap Studio\n * `Theme` document, a full MapLibre `StyleSpecification`, or a style URL.\n * Defaults to `\"light\"`.\n */\n style?: MapMapTheme | Theme | StyleSpecification | string;\n /** Override the territory PMTiles URL used by the default styles. */\n territoryTilesUrl?: string;\n /** Initial centre as `[lng, lat]`. Defaults to the UK. */\n center?: [number, number];\n /** Initial zoom. Defaults to `5`. */\n zoom?: number;\n /**\n * Extra MapLibre `MapOptions` merged last (escape hatch for hash, bearing,\n * maxBounds, etc.). `container` and `style` here are ignored.\n */\n mapOptions?: Partial<Omit<MapOptions, \"container\" | \"style\">>;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.mapmap.ai\";\nconst DEFAULT_CENTER: [number, number] = [-1.5, 52.6];\nconst DEFAULT_ZOOM = 5;\nconst DEFAULT_EFFECT_LAYER_ID = \"mapmap-route-effect\";\n\n/** Options for {@link MapMapMap.setRouteEffect}. */\nexport interface SetRouteEffectOptions extends RouteFlowOptions {\n /**\n * The route line to attach the effect to. Optional: when omitted the\n * effect is ARMED and applies as soon as a `RouteLayer` draws a route\n * (RouteLayer feeds every drawn geometry to the map automatically).\n */\n geometry?: RouteGeometry;\n}\n\n/** The flow options carried by a style's `metadata[\"mapmap:effects\"].params`. */\nfunction flowOptionsFromParams(params: Record<string, unknown>): RouteFlowOptions {\n const options: RouteFlowOptions = {};\n if (typeof params[\"color\"] === \"string\") options.color = params[\"color\"];\n if (typeof params[\"width\"] === \"number\") options.width = params[\"width\"];\n if (typeof params[\"speed\"] === \"number\") options.speed = params[\"speed\"];\n return options;\n}\n\n/** The MapMap map: a branded, tiles-and-routing-ready MapLibre map. */\nexport class MapMapMap {\n /** The underlying MapLibre map. Use it for any native MapLibre call. */\n readonly map: MlMap;\n /** Gateway API key, if provided. */\n readonly apiKey: string | undefined;\n /** Gateway base URL (no trailing slash). */\n readonly baseUrl: string;\n /**\n * The Studio navigation design (`extra.nav`) parsed from the theme passed\n * as `style`, when it carried one. `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` pick this up as their default look; `undefined` means\n * the theme had no nav block (or `style` was not a theme document).\n */\n readonly navDesign: NavDesign | undefined;\n /**\n * The Studio POI category design (`extra.poi`) parsed from the theme\n * passed as `style`, when it carried one. Apply its label-text part with\n * `applyPoiDesign(map.map, map.poiDesign)`; `undefined` means the theme\n * had no poi block (or `style` was not a theme document).\n */\n readonly poiDesign: PoiDesign | undefined;\n\n // Route-effect state (see setRouteEffect / effects.ts). `explicit`\n // records an app-level decision, which always wins over a style's\n // metadata auto-enable.\n private effectName: RouteEffectName | null = null;\n private effectOptions: RouteFlowOptions = {};\n private effectGeometry: RouteGeometry | undefined;\n private effectExplicit = false;\n private effectLayer: RouteEffectLayer | undefined;\n\n constructor(options: MapMapOptions) {\n registerPmtilesProtocol();\n\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n const theme = themeOf(options.style);\n this.navDesign = navDesignFromTheme(theme);\n this.poiDesign = poiDesignFromTheme(theme);\n\n const style = resolveStyle(options.style, options.territoryTilesUrl);\n\n this.map = new maplibregl.Map({\n container: options.container,\n style,\n center: options.center ?? DEFAULT_CENTER,\n zoom: options.zoom ?? DEFAULT_ZOOM,\n attributionControl: { compact: false },\n ...options.mapOptions,\n });\n\n // The MapMap mark, Google/Mapbox-style. Default on (bottom-right,\n // above the attribution); `logo: false` removes it, `logo: {...}`\n // repositions it. Attribution is separate and never removable.\n if (options.logo !== false) {\n const logoOptions = options.logo === true ? {} : (options.logo ?? {});\n this.map.addControl(\n new LogoControl(logoOptions),\n logoOptions.position ?? \"bottom-right\",\n );\n }\n\n // Route effects: styles compiled with an `effects` block carry\n // `metadata[\"mapmap:effects\"]`; honour it on every style (re)load\n // unless the app has called setRouteEffect itself. Custom layers are\n // wiped by setStyle like all runtime layers, so this also re-installs\n // an active effect after a theme swap.\n this.map.on(\"style.load\", this.handleStyleLoadForEffects);\n\n // Self-diagnosing errors: one actionable console.error per issue per\n // page (0px container, duplicate maplibre-gl, WebGL, 401s). Fully\n // defensive - never throws, skips DOM checks server-side.\n runMapDiagnostics({\n container: options.container,\n map: this.map,\n maplibre: maplibregl,\n apiKey: this.apiKey,\n });\n }\n\n private readonly handleStyleLoadForEffects = (): void => {\n if (!this.effectExplicit) {\n const block = effectsFromStyleMetadata(this.styleMetadata());\n this.effectName = block?.route ?? null;\n this.effectOptions = block?.params ? flowOptionsFromParams(block.params) : {};\n }\n // The old layer object died with the old style; re-add a fresh one.\n // Deferred a microtask so layers other style.load handlers re-install\n // (RouteLayer's line) land first and the ribbon stays on top.\n this.effectLayer = undefined;\n queueMicrotask(() => this.applyRouteEffect());\n };\n\n /** The current style's `metadata`, if it can be read yet. */\n private styleMetadata(): unknown {\n try {\n return (\n this.map as { getStyle?: () => { metadata?: unknown } | undefined }\n ).getStyle?.()?.metadata;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Set (or clear) the visual effect on the active route line - the\n * effects-engine entry point (see `effects.ts`). The first effect is\n * `\"flow\"`: an animated energy ribbon flowing along the route, drawn in\n * a MapLibre custom layer with first-party GLSL.\n *\n * ```ts\n * const route = await routes.route(from, to);\n * map.setRouteEffect(\"flow\"); // uses the drawn route\n * map.setRouteEffect(\"flow\", { color: \"#ff7a1f\" }); // options\n * map.setRouteEffect(null); // back to the plain line\n * ```\n *\n * Geometry: pass `{ geometry }` explicitly, or omit it and the effect\n * attaches to whatever route a `RouteLayer` on this map draws (current\n * and future - RouteLayer reports every drawn line via\n * {@link setRouteEffectGeometry}).\n *\n * Styles whose theme carried an `effects` block auto-enable their effect\n * from the compiled style's metadata; calling this method (with any\n * value, including `null`) overrides the style's wish for the lifetime\n * of this map.\n *\n * Accessibility/resilience (see effects.ts): honours\n * `prefers-reduced-motion` (static gradient, no animation) and falls\n * back to the plain route line with a single console warning if WebGL\n * setup fails.\n */\n setRouteEffect(\n effect: RouteEffectName | null,\n options: SetRouteEffectOptions = {},\n ): void {\n this.effectExplicit = true;\n const { geometry, ...flowOptions } = options;\n this.effectName = effect;\n this.effectOptions = flowOptions;\n if (geometry) this.effectGeometry = geometry;\n // Options are baked into the layer at creation; rebuild it.\n this.removeEffectLayer();\n this.applyRouteEffect();\n }\n\n /**\n * Attach the active route effect to a route line (or detach it with\n * `null`). `RouteLayer` calls this on every `draw()`/`clear()`, so apps\n * normally never do - pass `geometry` to {@link setRouteEffect} for\n * routes drawn outside a RouteLayer.\n */\n setRouteEffectGeometry(geometry: RouteGeometry | null): void {\n this.effectGeometry = geometry ?? undefined;\n if (\n geometry &&\n this.effectLayer &&\n this.map.getLayer(this.effectLayerId())\n ) {\n this.effectLayer.setGeometry(geometry);\n return;\n }\n this.applyRouteEffect();\n }\n\n private effectLayerId(): string {\n return this.effectOptions.id ?? DEFAULT_EFFECT_LAYER_ID;\n }\n\n private removeEffectLayer(): void {\n const id = this.effectLayerId();\n if (this.map.getLayer(id)) this.map.removeLayer(id);\n this.effectLayer = undefined;\n }\n\n /** Reconcile the effect state with the map: install, update or remove. */\n private applyRouteEffect(): void {\n const id = this.effectLayerId();\n if (this.effectName === null || this.effectGeometry === undefined) {\n this.removeEffectLayer();\n return;\n }\n if (!this.map.isStyleLoaded()) {\n this.map.once(\"load\", () => this.applyRouteEffect());\n return;\n }\n if (this.effectLayer && this.map.getLayer(id)) {\n this.effectLayer.setGeometry(this.effectGeometry);\n return;\n }\n if (this.map.getLayer(id)) this.map.removeLayer(id);\n this.effectLayer = createRouteEffect(this.effectName, this.effectGeometry, {\n ...this.effectOptions,\n id,\n });\n this.map.addLayer(this.effectLayer);\n }\n\n /**\n * Toggle 3D building extrusions at runtime — the live equivalent of\n * compiling the style with `buildings_3d: true` (see `Theme`): adds or\n * removes the `building-3d` fill-extrusion layer and hands the flat\n * `building` footprint layer off at zoom 15. The extrusion takes its\n * colour from the current `building` fill, so it follows the theme.\n * Idempotent; safe to call before the style has loaded (it applies on\n * load). Requires the MapMap skeleton's `building` layer — on a custom\n * style without one this throws rather than guessing.\n *\n * Mobile note: leave 3D off in native navigation views for now\n * (maplibre-native#4107 — fill-extrusion memory at street zooms).\n */\n setBuildings3d(enabled: boolean): void {\n if (!this.map.isStyleLoaded()) {\n this.map.once(\"load\", () => this.setBuildings3d(enabled));\n return;\n }\n if (enabled === (this.map.getLayer(\"building-3d\") !== undefined)) return;\n const building = this.map.getLayer(\"building\");\n if (!building) {\n throw new Error(\n 'setBuildings3d needs the MapMap skeleton \"building\" layer; ' +\n \"the current style does not have one\",\n );\n }\n const minzoom = building.minzoom ?? 13;\n if (enabled) {\n const colour =\n this.map.getPaintProperty(\"building\", \"fill-color\") ?? \"#e0d6c4\";\n this.map.addLayer(\n buildings3dLayer(colour) as unknown as LayerSpecification,\n buildings3dBeforeId(this.map),\n );\n this.map.setLayerZoomRange(\"building\", minzoom, BUILDINGS_3D_MINZOOM);\n } else {\n this.map.removeLayer(\"building-3d\");\n // 24 is the style-spec default maxzoom, i.e. \"uncapped\".\n this.map.setLayerZoomRange(\"building\", minzoom, 24);\n }\n }\n\n /** Resolves once the style and first tiles are loaded. */\n whenReady(): Promise<void> {\n return new Promise((resolve) => {\n if (this.map.loaded()) {\n resolve();\n return;\n }\n this.map.once(\"load\", () => resolve());\n });\n }\n\n /** Remove the map and release its WebGL context. */\n destroy(): void {\n this.map.remove();\n }\n}\n\n/** Functional alias for {@link MapMapMap}, mirroring the Mapbox `new Map` feel. */\nexport function createMap(options: MapMapOptions): MapMapMap {\n return new MapMapMap(options);\n}\n\n/**\n * Where the runtime `building-3d` layer goes: the same place the compiler\n * puts it — directly above the base map (after `boundary`), below extras\n * and labels. On a custom style without the skeleton's `boundary` layer,\n * fall back to just below the first symbol layer; `undefined` (append on\n * top) only if there are no symbol layers either.\n */\nfunction buildings3dBeforeId(map: MlMap): string | undefined {\n const layers = map.getStyle().layers ?? [];\n const boundary = layers.findIndex((l) => l.id === \"boundary\");\n if (boundary >= 0) return layers[boundary + 1]?.id;\n return layers.find((l) => l.type === \"symbol\")?.id;\n}\n\n/**\n * The MapMap Studio Theme document behind a `style` option, if that is what\n * it is. An object without a `version` field is a Theme; a full MapLibre\n * StyleSpecification always carries `version: 8`.\n */\nfunction themeOf(style: MapMapOptions[\"style\"]): Theme | undefined {\n if (typeof style === \"object\" && style !== null && !(\"version\" in style)) {\n return style as Theme;\n }\n return undefined;\n}\n\nfunction resolveStyle(\n style: MapMapOptions[\"style\"],\n territoryTilesUrl: string | undefined,\n): StyleSpecification | string {\n if (style === undefined || style === \"light\" || style === \"dark\") {\n return buildStyle({\n theme: style ?? \"light\",\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n const theme = themeOf(style);\n if (theme) {\n return buildStyle({\n theme,\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n return style as StyleSpecification | string;\n}\n","/**\n * OSRM request assembly and response parsing - pure, browser-free logic.\n *\n * The MapMap gateway exposes `GET /route/v1/{profile}/{coordinates}` speaking\n * the OSRM HTTP API v1, with truck vendor extensions (`height`, `width`,\n * `length`, `weight`, `hazmat`, `tunnel_code`). We always request\n * `geometries=geojson` so the route line arrives as a GeoJSON LineString we\n * can hand straight to a MapLibre source.\n */\nimport { formatCoords } from \"./coords.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteGeometry,\n RouteProfile,\n TruckParams,\n} from \"./types.js\";\n\n/** Guidance-related query options. */\nexport interface GuidanceQuery {\n voice?: boolean;\n banner?: boolean;\n language?: string;\n}\n\n/** Build the OSRM query string (without the leading `?`) for a request. */\nexport function buildRouteQuery(truck?: TruckParams, guidance?: GuidanceQuery): string {\n const params = new URLSearchParams({\n geometries: \"geojson\",\n overview: \"full\",\n steps: \"true\",\n });\n if (guidance?.voice) params.set(\"voice_instructions\", \"true\");\n if (guidance?.banner) params.set(\"banner_instructions\", \"true\");\n if (guidance?.language) params.set(\"language\", guidance.language);\n if (truck) {\n if (truck.heightM != null) params.set(\"height\", String(truck.heightM));\n if (truck.widthM != null) params.set(\"width\", String(truck.widthM));\n if (truck.lengthM != null) params.set(\"length\", String(truck.lengthM));\n if (truck.weightT != null) params.set(\"weight\", String(truck.weightT));\n if (truck.hazmat != null) params.set(\"hazmat\", String(truck.hazmat));\n // URLSearchParams encodes the slash in codes like \"B/D\" for us.\n if (truck.tunnelCode != null) params.set(\"tunnel_code\", truck.tunnelCode);\n }\n return params.toString();\n}\n\n/**\n * Build the full OSRM route URL. `baseUrl` is the gateway origin (trailing\n * slashes are trimmed); `points` is the ordered coordinate path.\n */\nexport function buildRouteUrl(\n baseUrl: string,\n profile: RouteProfile,\n points: LngLatLike[],\n truck?: TruckParams,\n guidance?: GuidanceQuery,\n): string {\n const origin = baseUrl.replace(/\\/+$/, \"\");\n const coords = formatCoords(points);\n const query = buildRouteQuery(truck, guidance);\n return `${origin}/route/v1/${encodeURIComponent(profile)}/${coords}?${query}`;\n}\n\n/**\n * Parse an OSRM route response into a {@link ParsedRoute}. Throws with the\n * OSRM `code`/`message` when the response is not `Ok` or carries no route.\n */\nexport function parseOsrmRoute(body: unknown): ParsedRoute {\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"OSRM response was not an object\");\n }\n const obj = body as Record<string, unknown>;\n const code = obj[\"code\"];\n if (code !== \"Ok\") {\n const message = typeof obj[\"message\"] === \"string\" ? obj[\"message\"] : \"\";\n throw new Error(\n `OSRM routing failed: ${String(code)}${message ? ` - ${message}` : \"\"}`,\n );\n }\n\n const routes = obj[\"routes\"];\n if (!Array.isArray(routes) || routes.length === 0) {\n throw new Error(\"OSRM response contained no routes\");\n }\n const route = routes[0] as Record<string, unknown>;\n\n const geometry = parseGeometry(route[\"geometry\"]);\n const distanceM = numberOr(route[\"distance\"], 0);\n const durationS = numberOr(route[\"duration\"], 0);\n\n return { distanceM, durationS, geometry, raw: route };\n}\n\nfunction parseGeometry(geometry: unknown): RouteGeometry {\n if (\n typeof geometry !== \"object\" ||\n geometry === null ||\n (geometry as { type?: unknown }).type !== \"LineString\"\n ) {\n throw new Error(\n \"route geometry was not GeoJSON - request geometries=geojson\",\n );\n }\n const coordinates = (geometry as { coordinates?: unknown }).coordinates;\n if (!Array.isArray(coordinates)) {\n throw new Error(\"route geometry had no coordinates\");\n }\n const positions: [number, number][] = coordinates.map((pos, i) => {\n if (\n !Array.isArray(pos) ||\n typeof pos[0] !== \"number\" ||\n typeof pos[1] !== \"number\"\n ) {\n throw new Error(`route geometry position ${i} is not [lng, lat]`);\n }\n return [pos[0], pos[1]];\n });\n return { type: \"LineString\", coordinates: positions };\n}\n\nfunction numberOr(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}\n","/**\n * RouteLayer - fetch an OSRM route from the MapMap gateway and draw it.\n *\n * The route request/parse logic lives in the pure `osrm` module; this class\n * owns the network call and the MapLibre source/layers (a signal-blue line\n * with a darker casing, matching the brand).\n */\nimport type {\n GeoJSONSource,\n LineLayerSpecification,\n Map as MlMap,\n} from \"maplibre-gl\";\nimport { buildRouteUrl, parseOsrmRoute } from \"./osrm.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteOptions,\n} from \"./types.js\";\nimport { MapMapMap } from \"./map.js\";\nimport type { NavAlertsDesign, NavRouteDesign } from \"./nav-design.js\";\n\n/** MapMap brand signal blue (see website `--signal`). */\nexport const SIGNAL_BLUE = \"#3a86ff\";\nconst CASING_COLOR = \"#1f438a\";\n/** Built-in average-speed corridor tint, used without an alerts design. */\nconst CORRIDOR_COLOR = \"#e05c6c\";\nconst CORRIDOR_OPACITY = 0.55;\n\nexport interface RouteLayerOptions {\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-route\"`. */\n id?: string;\n /**\n * Studio route design (`extra.nav` `route` block). Defaults to the map's\n * `navDesign.route` when given a `MapMapMap` whose theme carried one;\n * without a design the layer keeps its built-in signal-blue look.\n */\n design?: NavRouteDesign;\n /**\n * Studio safety-alert design (`extra.nav` `alerts` block), used for the\n * average-speed corridor highlight drawn by\n * {@link RouteLayer.setAlertCorridors}. Defaults to the map's\n * `navDesign.alerts` when given a `MapMapMap` whose theme carried one.\n */\n alertsDesign?: NavAlertsDesign;\n /**\n * Colour of the already-travelled part of the line once\n * {@link RouteLayer.setProgress} is used (the Google-style \"vanishing\n * route line\"). Defaults to a dimmed grey.\n */\n progressColor?: string;\n}\n\n/** Default colour of the travelled route segment. */\nconst PROGRESS_COLOR = \"#b0b0b0\";\n\n/**\n * The manoeuvre-arrow bitmap: a white upward arrow with a dark outline,\n * generated as raw RGBA pixels so no canvas 2D context is needed (works in\n * workers and test environments alike). Rotated per-manoeuvre via\n * `icon-rotate`.\n */\nfunction arrowImage(): { width: number; height: number; data: Uint8Array } {\n const size = 24;\n const data = new Uint8Array(size * size * 4);\n const head = 13; // rows 2..head form the triangular head\n const put = (x: number, y: number, edge: boolean): void => {\n const i = (y * size + x) * 4;\n const v = edge ? 31 : 255; // dark outline, white fill\n data[i] = v;\n data[i + 1] = v;\n data[i + 2] = edge ? 58 : 255;\n data[i + 3] = 255;\n };\n for (let y = 2; y < head; y++) {\n // Head: width grows with y; edge pixels darken to outline the shape.\n const half = Math.round(((y - 2) / (head - 3)) * 9);\n for (let x = 11 - half; x <= 12 + half; x++) {\n put(x, y, x === 11 - half || x === 12 + half || y === 2);\n }\n }\n for (let y = head; y < 22; y++) {\n // Shaft: constant width 6, outlined.\n for (let x = 9; x <= 14; x++) {\n put(x, y, x === 9 || x === 14 || y === 21);\n }\n }\n return { width: size, height: size, data };\n}\n\n/** Draws MapMap routes on a MapLibre map. */\nexport class RouteLayer {\n private readonly map: MlMap;\n /** The owning MapMapMap, when built from one - fed each drawn route so\n * an armed route effect (`setRouteEffect`) attaches automatically. */\n private readonly owner: MapMapMap | undefined;\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly casingLayerId: string;\n private readonly lineLayerId: string;\n private readonly maneuverSourceId: string;\n private readonly maneuverLayerId: string;\n private readonly arrowImageId: string;\n private readonly corridorSourceId: string;\n private readonly corridorLayerId: string;\n private readonly design: NavRouteDesign | undefined;\n private alertsDesign: NavAlertsDesign | undefined;\n private readonly progressColor: string;\n private lastRoute: ParsedRoute | undefined;\n private progress = 0;\n private maneuver: { lngLat: [number, number]; bearingDeg: number } | undefined;\n private corridors: [number, number][][] = [];\n\n constructor(map: MapMapMap | MlMap, options: RouteLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.owner = map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n this.design = options.design ?? map.navDesign?.route;\n this.alertsDesign = options.alertsDesign ?? map.navDesign?.alerts;\n } else {\n this.map = map;\n if (!options.baseUrl) {\n throw new Error(\"RouteLayer needs a baseUrl when given a raw MapLibre map\");\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.design = options.design;\n this.alertsDesign = options.alertsDesign;\n }\n const id = options.id ?? \"mapmap-route\";\n this.sourceId = `${id}-src`;\n this.casingLayerId = `${id}-casing`;\n this.lineLayerId = `${id}-line`;\n this.maneuverSourceId = `${id}-maneuver-src`;\n this.maneuverLayerId = `${id}-maneuver`;\n this.arrowImageId = `${id}-arrow`;\n this.corridorSourceId = `${id}-corridor-src`;\n this.corridorLayerId = `${id}-corridor`;\n this.progressColor = options.progressColor ?? PROGRESS_COLOR;\n // MapLibre wipes runtime sources/layers on every setStyle (e.g. a\n // light/dark theme swap), so re-install the route after each style\n // load — the same pattern the playground uses. This also completes a\n // draw() that arrived before the initial style finished loading.\n this.map.on(\"style.load\", this.handleStyleLoad);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.lastRoute) this.install(this.lastRoute);\n else this.installManeuver();\n this.installCorridors();\n };\n\n /**\n * Route from `from` to `to` (with optional intermediate `via` points passed\n * through `options` is not supported here - pass a coordinate list to\n * {@link routePath} for that), draw the line, and return the parsed route.\n */\n async route(\n from: LngLatLike,\n to: LngLatLike,\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n return this.routePath([from, to], options);\n }\n\n /** Route through an ordered list of coordinates and draw the result. */\n async routePath(\n points: LngLatLike[],\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n const url = buildRouteUrl(\n this.baseUrl,\n options.profile ?? \"driving\",\n points,\n options.truck,\n { voice: options.voice, banner: options.banner, language: options.language },\n );\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(url, { headers });\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n const obj =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n // Only OSRM-shaped error bodies (with a \"code\") belong to the routing\n // engine; anything else (e.g. the gateway's RFC 9457 problem+json for\n // 401/429) is reported with its status and title/detail instead of\n // being misattributed as an OSRM failure.\n if (typeof obj?.[\"code\"] !== \"string\") {\n const context = [obj?.[\"title\"], obj?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `route request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n }\n const parsed = parseOsrmRoute(body);\n this.draw(parsed);\n return parsed;\n }\n\n /** The most recently drawn route, if any. */\n get current(): ParsedRoute | undefined {\n return this.lastRoute;\n }\n\n /**\n * Draw (or update) a parsed route's line on the map. Safe to call before\n * the style has loaded: the route is stored and installed on the next\n * `style.load` instead of throwing MapLibre's \"Style is not done loading\".\n */\n draw(route: ParsedRoute): void {\n this.lastRoute = route;\n if (this.map.isStyleLoaded()) this.install(route);\n // else: installed by handleStyleLoad.\n // Attach any armed route effect (map.setRouteEffect) to this line -\n // after install, so the effect's custom layer lands above the line.\n this.owner?.setRouteEffectGeometry(route.geometry);\n }\n\n /** Add-or-update the source and layers for a route on the current style. */\n private install(route: ParsedRoute): void {\n const data = {\n type: \"Feature\" as const,\n properties: {},\n geometry: route.geometry,\n };\n\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n // lineMetrics powers the progress gradient (line-progress requires it).\n this.map.addSource(this.sourceId, { type: \"geojson\", data, lineMetrics: true });\n }\n\n if (this.map.getLayer(this.casingLayerId) && this.map.getLayer(this.lineLayerId)) {\n this.applyProgress();\n this.installManeuver();\n return;\n }\n\n // With a Studio design the paints follow the Studio preview exactly\n // (constant width, casing = width + 4, shared opacity — see\n // syncNavOverlay in the Studio client); without one they keep the\n // built-in zoom-interpolated signal-blue look, unchanged.\n const casing: LineLayerSpecification = {\n id: this.casingLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.casingColor,\n \"line-width\": this.design.width + 4,\n \"line-opacity\": this.design.opacity,\n }\n : {\n \"line-color\": CASING_COLOR,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 6, 16, 12],\n },\n };\n const line: LineLayerSpecification = {\n id: this.lineLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.color,\n \"line-width\": this.design.width,\n \"line-opacity\": this.design.opacity,\n }\n : {\n \"line-color\": SIGNAL_BLUE,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 3, 16, 8],\n },\n };\n\n if (!this.map.getLayer(this.casingLayerId)) this.map.addLayer(casing);\n if (!this.map.getLayer(this.lineLayerId)) this.map.addLayer(line);\n this.applyProgress();\n this.installManeuver();\n }\n\n /**\n * Sets how much of the route has been travelled, as a fraction in `[0, 1]`\n * of the line's length. The travelled part dims to `progressColor` (the\n * \"vanishing route line\"); `0` restores the untinted line. The value is\n * remembered across {@link draw} calls and style swaps. Pair with the\n * guidance module's distance-remaining to derive the fraction.\n */\n setProgress(fraction: number): void {\n this.progress = Math.min(1, Math.max(0, fraction));\n if (this.map.getLayer(this.lineLayerId)) this.applyProgress();\n }\n\n /** Applies the current progress fraction to the line layer's gradient. */\n private applyProgress(): void {\n const routeColor = this.design?.color ?? SIGNAL_BLUE;\n // A `step` on line-progress: travelled colour up to the fraction, the\n // route colour beyond it. line-progress only evaluates >= 0, so at 0 the\n // gradient is removed instead (also keeps non-progress usage identical\n // to the pre-progress behaviour).\n const gradient =\n this.progress > 0\n ? [\"step\", [\"line-progress\"], this.progressColor, this.progress, routeColor]\n : undefined;\n this.map.setPaintProperty(this.lineLayerId, \"line-gradient\", gradient);\n }\n\n /**\n * Shows (or moves) the upcoming-manoeuvre arrow: a small map-aligned\n * arrow at `lngLat` rotated to `bearingDeg` (clockwise from north).\n * Survives style swaps until {@link clearManeuver}.\n */\n setManeuver(lngLat: [number, number], bearingDeg: number): void {\n this.maneuver = { lngLat, bearingDeg };\n if (this.map.isStyleLoaded()) this.installManeuver();\n }\n\n /** Hides the manoeuvre arrow. */\n clearManeuver(): void {\n this.maneuver = undefined;\n if (this.map.getLayer(this.maneuverLayerId)) this.map.removeLayer(this.maneuverLayerId);\n if (this.map.getSource(this.maneuverSourceId)) this.map.removeSource(this.maneuverSourceId);\n }\n\n /** Add-or-update the manoeuvre arrow source/layer for the current style. */\n private installManeuver(): void {\n if (!this.maneuver) return;\n const data = {\n type: \"Feature\" as const,\n properties: { bearing: this.maneuver.bearingDeg },\n geometry: { type: \"Point\" as const, coordinates: this.maneuver.lngLat },\n };\n const source = this.map.getSource(this.maneuverSourceId) as GeoJSONSource | undefined;\n if (source) {\n source.setData(data);\n } else {\n this.map.addSource(this.maneuverSourceId, { type: \"geojson\", data });\n }\n // setStyle also wipes runtime images, so re-add alongside the layer.\n if (!this.map.hasImage(this.arrowImageId)) {\n this.map.addImage(this.arrowImageId, arrowImage());\n }\n if (!this.map.getLayer(this.maneuverLayerId)) {\n this.map.addLayer({\n id: this.maneuverLayerId,\n type: \"symbol\",\n source: this.maneuverSourceId,\n layout: {\n \"icon-image\": this.arrowImageId,\n \"icon-rotate\": [\"get\", \"bearing\"],\n \"icon-rotation-alignment\": \"map\",\n \"icon-allow-overlap\": true,\n \"icon-ignore-placement\": true,\n \"icon-size\": [\"interpolate\", [\"linear\"], [\"zoom\"], 12, 0.7, 18, 1.4],\n },\n });\n } else {\n this.map.setLayoutProperty(this.maneuverLayerId, \"icon-rotate\", [\"get\", \"bearing\"]);\n }\n }\n\n /**\n * Highlights average-speed enforcement corridors on the route line.\n *\n * A corridor is a stretch of the route between an entry and an exit\n * camera, so it is a property of the LINE, not a point alert: drawing it\n * as a tinted overlay above the route is what makes \"you are inside a\n * section check right now\" readable at a glance, and it is the only part\n * of the alert design that persists rather than firing once.\n *\n * Pass the corridor geometries (arrays of `[lng, lat]` along the route)\n * and, optionally, a Studio alerts design for the colour and opacity;\n * without one the layer uses the design carried by the owning map, then\n * a built-in tint. An empty array clears the highlight. Survives style\n * swaps like the route itself.\n */\n setAlertCorridors(\n corridors: readonly (readonly [number, number])[][],\n design?: NavAlertsDesign,\n ): void {\n if (design) this.alertsDesign = design;\n this.corridors = corridors.map((line) => line.map((p) => [p[0], p[1]] as [number, number]));\n if (this.corridors.length === 0) {\n this.clearAlertCorridors();\n return;\n }\n if (this.map.isStyleLoaded()) this.installCorridors();\n }\n\n /** Removes the corridor highlight (the route line itself is untouched). */\n clearAlertCorridors(): void {\n this.corridors = [];\n if (this.map.getLayer(this.corridorLayerId)) this.map.removeLayer(this.corridorLayerId);\n if (this.map.getSource(this.corridorSourceId)) this.map.removeSource(this.corridorSourceId);\n }\n\n /** Add-or-update the corridor source/layer for the current style. */\n private installCorridors(): void {\n if (this.corridors.length === 0) return;\n const data = {\n type: \"FeatureCollection\" as const,\n features: this.corridors.map((coordinates) => ({\n type: \"Feature\" as const,\n properties: {},\n geometry: { type: \"LineString\" as const, coordinates },\n })),\n };\n const source = this.map.getSource(this.corridorSourceId) as GeoJSONSource | undefined;\n if (source) {\n source.setData(data);\n } else {\n this.map.addSource(this.corridorSourceId, { type: \"geojson\", data });\n }\n const design = this.alertsDesign;\n const color = design?.corridorColor ?? CORRIDOR_COLOR;\n const opacity = design?.corridorOpacity ?? CORRIDOR_OPACITY;\n // Slightly wider than the route line so the tint reads as a highlight\n // around it rather than as a second, competing route.\n const width = (this.design?.width ?? 4.5) + 3;\n if (!this.map.getLayer(this.corridorLayerId)) {\n this.map.addLayer({\n id: this.corridorLayerId,\n type: \"line\",\n source: this.corridorSourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": color,\n \"line-width\": width,\n \"line-opacity\": opacity,\n },\n });\n } else {\n this.map.setPaintProperty(this.corridorLayerId, \"line-color\", color);\n this.map.setPaintProperty(this.corridorLayerId, \"line-opacity\", opacity);\n this.map.setPaintProperty(this.corridorLayerId, \"line-width\", width);\n }\n }\n\n /** Remove the route's layers and source from the map. */\n clear(): void {\n this.clearManeuver();\n this.clearAlertCorridors();\n for (const layerId of [this.lineLayerId, this.casingLayerId]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n this.lastRoute = undefined;\n // The route is gone; take any route effect with it.\n this.owner?.setRouteEffectGeometry(null);\n this.progress = 0;\n }\n\n /**\n * Remove the route and detach the layer's `style.load` listener. Call\n * when disposing of the layer (the map itself is left untouched).\n */\n destroy(): void {\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.clear();\n }\n}\n","/**\n * WCAG relative-luminance contrast, and the legibility gate for the\n * safety-alert chip.\n *\n * WHY THIS IS A SAFETY CHECK, NOT A TASTE CHECK: NHTSA's visual-manual\n * driver-distraction guidelines are built around single glances of under\n * two seconds away from the road. An alert chip whose text does not\n * resolve inside one such glance either costs the driver a second glance\n * or is not read at all, so a low-contrast colour pair is a defect in the\n * alert, not a stylistic preference. Studio therefore warns on a failing\n * pair rather than silently accepting it.\n *\n * The threshold is WCAG 2.x AA for large text (3:1) raised to the\n * body-text floor (4.5:1) - a chip is glanced at, not read at leisure, and\n * the guidance surface already renders at banner sizes.\n *\n * DELIBERATELY NOT the Rust `sn_style::contrast` helper (nor the\n * `check_style_contrast` MCP tool): the web SDK does not link Rust, and\n * Studio needs this in the browser as the customer drags a colour picker.\n * Same formula (WCAG 2.x `(L1 + 0.05) / (L2 + 0.05)` over sRGB\n * relative luminance), independently implemented and unit-tested.\n *\n * LOCKSTEP: mirrors the contrast helpers in `website/lib/studio-nav.ts`.\n */\n\nimport type { NavAlertsDesign } from \"./nav-design.js\";\n\n/** Minimum acceptable contrast ratio for alert-chip text on its background. */\nexport const ALERT_CONTRAST_MIN = 4.5;\n\n/**\n * Parses a CSS hex colour (`#rgb`, `#rrggbb`, `#rgba`, `#rrggbbaa`) into\n * 0-255 sRGB channels. Alpha is accepted and ignored - the chip composites\n * over an opaque background, so its alpha does not describe what the\n * driver sees. Returns `undefined` for any other notation (named colours,\n * `rgb()`, gradients): unparseable means \"cannot judge\", never \"fails\".\n */\nexport function parseHexColor(value: unknown): [number, number, number] | undefined {\n if (typeof value !== \"string\") return undefined;\n const hex = value.trim().replace(/^#/, \"\");\n if (!/^[0-9a-f]+$/i.test(hex)) return undefined;\n // #rgb shorthand: each digit doubles (`#f0a` -> `#ff00aa`).\n const expanded =\n hex.length === 3 || hex.length === 4\n ? hex\n .slice(0, 3)\n .split(\"\")\n .map((c) => c + c)\n .join(\"\")\n : hex.length === 6 || hex.length === 8\n ? hex.slice(0, 6)\n : undefined;\n if (expanded === undefined) return undefined;\n return [\n parseInt(expanded.slice(0, 2), 16),\n parseInt(expanded.slice(2, 4), 16),\n parseInt(expanded.slice(4, 6), 16),\n ];\n}\n\n/** WCAG 2.x relative luminance of an sRGB triple (channels 0-255). */\nexport function relativeLuminance(rgb: readonly [number, number, number]): number {\n const [r, g, b] = rgb.map((channel) => {\n const c = channel / 255;\n return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * WCAG 2.x contrast ratio between two hex colours, from 1 (identical) to\n * 21 (black on white). Order-independent. Returns `undefined` when either\n * colour cannot be parsed, so callers can distinguish \"not judgeable\" from\n * \"fails\".\n */\nexport function contrastRatio(a: unknown, b: unknown): number | undefined {\n const rgbA = parseHexColor(a);\n const rgbB = parseHexColor(b);\n if (!rgbA || !rgbB) return undefined;\n const lumA = relativeLuminance(rgbA);\n const lumB = relativeLuminance(rgbB);\n const lighter = Math.max(lumA, lumB);\n const darker = Math.min(lumA, lumB);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/** A chip colour pair that falls below {@link ALERT_CONTRAST_MIN}. */\nexport interface AlertContrastIssue {\n /** Which chip state the pair belongs to. */\n state: \"calm\" | \"escalated\";\n /** The text colour of the failing pair. */\n textColor: string;\n /** The background colour of the failing pair. */\n background: string;\n /** The measured ratio, rounded to 2 dp. */\n ratio: number;\n /** The floor it failed to clear. */\n minimum: number;\n}\n\n/**\n * Every chip colour pair in `design` that fails the contrast floor, in\n * state order. An empty array means both states are legible (or, for\n * colours this module cannot parse, not judgeable - those are skipped\n * rather than reported as failures).\n *\n * Advisory by design: the parser stays lenient and never rejects a theme\n * on contrast. Studio surfaces these as warnings next to the pickers so a\n * designer sees the problem while choosing, which is the only moment the\n * warning can actually change the outcome.\n */\nexport function alertContrastIssues(design: NavAlertsDesign): AlertContrastIssue[] {\n const pairs: readonly (readonly [\"calm\" | \"escalated\", string, string])[] = [\n [\"calm\", design.textColor, design.background],\n [\"escalated\", design.escalatedTextColor, design.escalatedBackground],\n ];\n const issues: AlertContrastIssue[] = [];\n for (const [state, textColor, background] of pairs) {\n const ratio = contrastRatio(textColor, background);\n if (ratio === undefined || ratio >= ALERT_CONTRAST_MIN) continue;\n issues.push({\n state,\n textColor,\n background,\n ratio: Math.round(ratio * 100) / 100,\n minimum: ALERT_CONTRAST_MIN,\n });\n }\n return issues;\n}\n","/**\n * PositionPuck - the current-position marker, styled by a Studio design.\n *\n * A MapLibre `Marker`-based puck: a coloured dot with an optional heading\n * arrow, or a custom image (`https:`/`data:` URI, data payloads capped at\n * 64 KB - the same cap Studio enforces on upload) that replaces both and\n * falls back to the built-in dot if it fails to load. The marker survives\n * `setStyle` on its own (markers are DOM overlays, not style layers), so\n * no `style.load` re-install is needed.\n *\n * LOCKSTEP: the element structure and styling mirror `createPuckElement` /\n * `stylePuckElement` in the Studio client\n * (`website/app/studio/StudioClient.tsx`), so a theme's puck renders here\n * exactly as Studio previews it.\n *\n * Like `MapMapMap` (see map.ts), this module imports the SDK's bundled\n * maplibre-gl for the `Marker` constructor - a purely structural typing\n * (the `LogoControl` pattern) is not possible because a Marker must be\n * constructed, not just duck-typed.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type { Map as MlMap, Marker } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { defaultNavDesign, type NavPuckDesign } from \"./nav-design.js\";\n\n/** Maximum accepted `data:` puck-image payload (matches Studio's upload cap). */\nexport const MAX_PUCK_IMAGE_BYTES = 64 * 1024;\n\n/**\n * Approximate decoded byte size of a `data:` URI payload (base64 payloads\n * decode to 3/4 of their character count; other payloads are counted as-is,\n * an upper bound for percent-encoded text).\n */\nfunction dataUriBytes(uri: string): number {\n const comma = uri.indexOf(\",\");\n const payload = comma === -1 ? \"\" : uri.slice(comma + 1);\n const meta = comma === -1 ? uri : uri.slice(0, comma);\n return /;base64$/i.test(meta) || /;base64;/i.test(meta)\n ? Math.floor((payload.length * 3) / 4)\n : payload.length;\n}\n\n/** The design's image URL, or `undefined` when unusable (built-in puck). */\nfunction effectiveImageUrl(design: NavPuckDesign): string | undefined {\n const url = design.imageUrl?.trim();\n if (!url) return undefined;\n if (/^data:/i.test(url) && dataUriBytes(url) > MAX_PUCK_IMAGE_BYTES) {\n return undefined;\n }\n return url;\n}\n\n/**\n * The signed shortest-arc rotation from `fromDeg` to `toDeg`, in degrees.\n * Always in `(-180, 180]`, so a heading tween never spins the long way\n * round the compass (350° -> 10° is +20°, not -340°).\n */\nexport function shortestArcDeg(fromDeg: number, toDeg: number): number {\n const raw = (((toDeg - fromDeg) % 360) + 360) % 360;\n return raw > 180 ? raw - 360 : raw;\n}\n\n/** Options for {@link PositionPuck}. */\nexport interface PositionPuckOptions {\n /**\n * Animate between fixes instead of snapping (default `true`). Position\n * lerps linearly and heading tweens along the shortest arc, over a\n * duration adapted to the observed fix interval (like the\n * `NavigationCamera` glide, so puck and camera arrive together). Falls\n * back to instant placement where `requestAnimationFrame` is missing.\n */\n interpolate?: boolean;\n /** Test seam: clock override, defaults to `Date.now`. */\n now?: () => number;\n /** Test seam: frame scheduler override, defaults to rAF. */\n requestFrame?: (callback: () => void) => number;\n /** Test seam: frame canceller override, defaults to cancelAnimationFrame. */\n cancelFrame?: (handle: number) => void;\n}\n\n/** Longest tween between fixes, ms (also the camera's default glide). */\nconst MAX_TWEEN_MS = 900;\n/** Shortest tween worth animating, ms; below this the move is instant. */\nconst MIN_TWEEN_MS = 100;\n\n/** A current-position puck marker for MapMap maps. */\nexport class PositionPuck {\n /** The puck's root DOM element (the Marker element). */\n readonly element: HTMLElement;\n private readonly map: MlMap;\n private readonly marker: Marker;\n private readonly design: NavPuckDesign;\n private added = false;\n private readonly interpolate: boolean;\n private readonly now: () => number;\n private readonly requestFrame?: (callback: () => void) => number;\n private readonly cancelFrame?: (handle: number) => void;\n private frameHandle: number | undefined;\n /** The position/heading currently rendered on the marker. */\n private rendered: { lat: number; lon: number; heading: number } | undefined;\n private lastFixAt: number | undefined;\n\n /**\n * Creates the puck (not yet on the map - it appears on the first\n * {@link setLocation}). The design defaults to the map's\n * `navDesign.puck` when given a `MapMapMap` whose theme carried an\n * `extra.nav` block, then to the built-in blue puck.\n */\n constructor(map: MapMapMap | MlMap, design?: NavPuckDesign, options?: PositionPuckOptions) {\n this.map = map instanceof MapMapMap ? map.map : map;\n this.design =\n design ??\n (map instanceof MapMapMap ? map.navDesign?.puck : undefined) ??\n defaultNavDesign().puck;\n this.element = createPuckElement();\n stylePuckElement(this.element, this.design);\n this.interpolate = options?.interpolate ?? true;\n this.now = options?.now ?? Date.now;\n const g = globalThis as {\n requestAnimationFrame?: (cb: FrameRequestCallback) => number;\n cancelAnimationFrame?: (handle: number) => void;\n };\n this.requestFrame =\n options?.requestFrame ??\n (g.requestAnimationFrame ? (cb) => g.requestAnimationFrame!(() => cb()) : undefined);\n this.cancelFrame =\n options?.cancelFrame ?? (g.cancelAnimationFrame ? (h) => g.cancelAnimationFrame!(h) : undefined);\n // Map-aligned rotation/pitch: the puck lies flat on the map and its\n // heading rotates with the camera bearing, as in the Studio preview.\n this.marker = new maplibregl.Marker({\n element: this.element,\n rotationAlignment: \"map\",\n pitchAlignment: \"map\",\n });\n }\n\n /**\n * Moves the puck (adding it to the map on the first call). `headingDeg`\n * rotates the whole element - arrow or custom image - clockwise from\n * north; omit it to keep the previous heading.\n *\n * With interpolation on (the default) every call after the first glides\n * from the currently rendered position - a fix arriving mid-tween\n * retargets smoothly rather than jumping.\n */\n setLocation(location: { lat: number; lon: number }, headingDeg?: number): void {\n const first = !this.added;\n const nowMs = this.now();\n const interval = this.lastFixAt === undefined ? MAX_TWEEN_MS : nowMs - this.lastFixAt;\n this.lastFixAt = nowMs;\n this.cancelTween();\n const from = this.rendered;\n const target = {\n lat: location.lat,\n lon: location.lon,\n heading: headingDeg ?? from?.heading ?? 0,\n };\n const duration = Math.min(MAX_TWEEN_MS, interval);\n if (first || !this.interpolate || !this.requestFrame || !from || duration < MIN_TWEEN_MS) {\n this.render(target);\n } else {\n this.tween(from, target, nowMs, duration);\n }\n if (first) {\n this.marker.addTo(this.map);\n this.added = true;\n }\n }\n\n /** Removes the puck from the map (cancelling any tween). `setLocation` re-adds it. */\n remove(): void {\n this.cancelTween();\n this.marker.remove();\n this.added = false;\n }\n\n /** Applies a position/heading to the marker immediately. */\n private render(state: { lat: number; lon: number; heading: number }): void {\n this.marker.setLngLat([state.lon, state.lat]);\n this.marker.setRotation(state.heading);\n this.rendered = state;\n }\n\n /** Runs a linear position lerp + shortest-arc heading tween via rAF. */\n private tween(\n from: { lat: number; lon: number; heading: number },\n to: { lat: number; lon: number; heading: number },\n startedAt: number,\n duration: number,\n ): void {\n const headingDelta = shortestArcDeg(from.heading, to.heading);\n const step = (): void => {\n const t = Math.min(1, (this.now() - startedAt) / duration);\n this.render({\n lat: from.lat + (to.lat - from.lat) * t,\n lon: from.lon + (to.lon - from.lon) * t,\n heading: from.heading + headingDelta * t,\n });\n if (t < 1) {\n this.frameHandle = this.requestFrame!(step);\n } else {\n this.frameHandle = undefined;\n // Land exactly on the target heading (mod-360 of the tween end).\n this.render(to);\n }\n };\n this.frameHandle = this.requestFrame!(step);\n }\n\n /** Cancels an in-flight tween, leaving the marker where it rendered last. */\n private cancelTween(): void {\n if (this.frameHandle !== undefined) {\n this.cancelFrame?.(this.frameHandle);\n this.frameHandle = undefined;\n }\n }\n}\n\n/**\n * The puck element: a dot plus an optional heading-arrow triangle, and a\n * (hidden by default) custom-image slot that replaces both when the design\n * carries an `imageUrl`. LOCKSTEP with Studio's `createPuckElement`.\n */\nfunction createPuckElement(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"PositionPuck requires a DOM environment\");\n const el = doc.createElement(\"div\");\n el.className = \"mapmap-puck\";\n el.style.position = \"relative\";\n const arrow = doc.createElement(\"div\");\n arrow.dataset[\"part\"] = \"arrow\";\n const dot = doc.createElement(\"div\");\n dot.dataset[\"part\"] = \"dot\";\n const img = doc.createElement(\"img\");\n img.dataset[\"part\"] = \"image\";\n img.alt = \"\";\n img.draggable = false;\n img.style.display = \"none\";\n el.append(arrow, dot, img);\n return el;\n}\n\n/**\n * Applies a puck design to the element. LOCKSTEP with Studio's\n * `stylePuckElement`: same sizes, colours, shadows and image fallback (a\n * URL that fails to load is remembered on the element and the built-in\n * puck shows instead).\n */\nfunction stylePuckElement(el: HTMLElement, puck: NavPuckDesign): void {\n const dot = el.querySelector<HTMLElement>(\"[data-part='dot']\");\n const arrow = el.querySelector<HTMLElement>(\"[data-part='arrow']\");\n const img = el.querySelector<HTMLImageElement>(\"[data-part='image']\");\n if (!dot || !arrow || !img) return;\n const s = puck.size;\n el.style.width = `${s}px`;\n el.style.height = `${s}px`;\n const url = effectiveImageUrl(puck) ?? \"\";\n if (url !== \"\" && el.dataset[\"imageFailed\"] !== url) {\n if (img.getAttribute(\"src\") !== url) {\n img.onerror = () => {\n el.dataset[\"imageFailed\"] = url;\n img.removeAttribute(\"src\");\n stylePuckElement(el, puck);\n };\n img.src = url;\n }\n img.style.cssText =\n `display:block;position:absolute;inset:0;width:${s}px;height:${s}px;` +\n \"object-fit:contain;filter:drop-shadow(0 1px 4px rgba(0,0,0,0.5))\";\n dot.style.cssText = \"display:none\";\n arrow.style.cssText = \"display:none\";\n return;\n }\n img.onerror = null;\n if (img.getAttribute(\"src\") !== null) img.removeAttribute(\"src\");\n img.style.cssText = \"display:none\";\n dot.style.cssText =\n `position:absolute;inset:0;border-radius:50%;background:${puck.color};` +\n \"border:2px solid #ffffff;box-shadow:0 1px 6px rgba(0,0,0,0.45)\";\n arrow.style.cssText = puck.headingArrow\n ? `position:absolute;left:50%;top:${(-s * 0.55).toFixed(1)}px;transform:translateX(-50%);` +\n `width:0;height:0;border-left:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-right:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-bottom:${(s * 0.6).toFixed(1)}px solid ${puck.color}`\n : \"display:none\";\n}\n","/**\n * Auto day/night theme switching from sun position.\n *\n * A dependency-free solar calculator (the standard sunrise equation, as\n * published at https://en.wikipedia.org/wiki/Sunrise_equation, itself a\n * restatement of the NOAA solar calculation details,\n * https://gml.noaa.gov/grad/solcalc/calcdetails.html) plus a small\n * scheduler that flips between light and dark at sunrise/sunset. Nothing\n * here touches a map: pair {@link ThemeScheduler} with\n * `MapMapMap.setStyle(\"light\" | \"dark\")` (or any other callback) in the\n * app. Territory packages already ship paired light/dark styles, so the\n * switch works offline too.\n */\n\n/** Sun-times result: either both events, or a polar day/night marker. */\nexport type SunTimes = { sunrise: Date; sunset: Date } | \"polarDay\" | \"polarNight\";\n\nconst DEG = Math.PI / 180;\n/** Milliseconds per day. */\nconst DAY_MS = 86_400_000;\n/** Julian date of the Unix epoch. */\nconst JULIAN_EPOCH = 2_440_587.5;\n/** Julian date of the J2000 epoch. */\nconst J2000 = 2_451_545;\n\n/** Converts a Julian date to a JS `Date`. */\nfunction fromJulian(julian: number): Date {\n return new Date((julian - JULIAN_EPOCH) * DAY_MS);\n}\n\n/**\n * Sunrise and sunset (standard -0.833° horizon: refraction + solar disc)\n * for the civil day containing `date` (UTC) at `lat`/`lng`, or a polar\n * marker when the sun never crosses the horizon that day.\n */\nexport function sunTimes(date: Date, lat: number, lng: number): SunTimes {\n // Days since J2000, rounded to the nearest civil day at the longitude.\n const julianDay = Math.ceil(date.getTime() / DAY_MS + JULIAN_EPOCH - J2000 - 0.0009 + lng / 360);\n const meanSolarTime = julianDay + 0.0009 - lng / 360;\n const meanAnomalyDeg = (357.5291 + 0.98560028 * meanSolarTime) % 360;\n const m = meanAnomalyDeg * DEG;\n const centreDeg = 1.9148 * Math.sin(m) + 0.02 * Math.sin(2 * m) + 0.0003 * Math.sin(3 * m);\n const eclipticLngDeg = (meanAnomalyDeg + centreDeg + 180 + 102.9372) % 360;\n const l = eclipticLngDeg * DEG;\n const transit = J2000 + meanSolarTime + 0.0053 * Math.sin(m) - 0.0069 * Math.sin(2 * l);\n const sinDeclination = Math.sin(l) * Math.sin(23.4397 * DEG);\n const cosDeclination = Math.cos(Math.asin(sinDeclination));\n const cosHourAngle =\n (Math.sin(-0.833 * DEG) - Math.sin(lat * DEG) * sinDeclination) /\n (Math.cos(lat * DEG) * cosDeclination);\n if (cosHourAngle < -1) return \"polarDay\";\n if (cosHourAngle > 1) return \"polarNight\";\n const hourAngleDeg = Math.acos(cosHourAngle) / DEG;\n return {\n sunrise: fromJulian(transit - hourAngleDeg / 360),\n sunset: fromJulian(transit + hourAngleDeg / 360),\n };\n}\n\n/** The theme the sun dictates at `date` for `lat`/`lng`. */\nexport function resolveTheme(date: Date, lat: number, lng: number): \"light\" | \"dark\" {\n const times = sunTimes(date, lat, lng);\n if (times === \"polarDay\") return \"light\";\n if (times === \"polarNight\") return \"dark\";\n return date >= times.sunrise && date < times.sunset ? \"light\" : \"dark\";\n}\n\n/** Options for {@link ThemeScheduler}. */\nexport interface ThemeSchedulerOptions {\n /** Latitude used for the solar calculation. */\n lat: number;\n /** Longitude used for the solar calculation. */\n lng: number;\n /** Called (immediately on construction, then at each sunrise) for light. */\n onLight: () => void;\n /** Called (immediately on construction, then at each sunset) for dark. */\n onDark: () => void;\n /** Test seam: clock override, defaults to `Date.now`. */\n now?: () => number;\n /** Test seam: timer override, defaults to `setTimeout`. */\n setTimeoutFn?: (callback: () => void, ms: number) => ReturnType<typeof setTimeout>;\n /** Test seam: timer canceller, defaults to `clearTimeout`. */\n clearTimeoutFn?: (handle: ReturnType<typeof setTimeout>) => void;\n}\n\n/** Re-check interval under polar day/night, where no flip is scheduled. */\nconst POLAR_RECHECK_MS = 6 * 3_600_000;\n/** Margin added past a boundary so the re-evaluation lands beyond it. */\nconst BOUNDARY_MARGIN_MS = 1_000;\n\n/**\n * Applies the sun-appropriate theme now and at every subsequent\n * sunrise/sunset until {@link dispose}. No OSS map SDK ships this\n * out of the box; pair with the OS dark-mode signal in the app if the\n * user's system preference should win instead.\n */\nexport class ThemeScheduler {\n private lat: number;\n private lng: number;\n private readonly onLight: () => void;\n private readonly onDark: () => void;\n private readonly now: () => number;\n private readonly setTimeoutFn: (cb: () => void, ms: number) => ReturnType<typeof setTimeout>;\n private readonly clearTimeoutFn: (handle: ReturnType<typeof setTimeout>) => void;\n private handle: ReturnType<typeof setTimeout> | undefined;\n private applied: \"light\" | \"dark\" | undefined;\n private disposed = false;\n\n constructor(options: ThemeSchedulerOptions) {\n this.lat = options.lat;\n this.lng = options.lng;\n this.onLight = options.onLight;\n this.onDark = options.onDark;\n this.now = options.now ?? Date.now;\n this.setTimeoutFn = options.setTimeoutFn ?? ((cb, ms) => setTimeout(cb, ms));\n this.clearTimeoutFn = options.clearTimeoutFn ?? ((h) => clearTimeout(h));\n this.evaluate();\n }\n\n /** The theme most recently applied, if any. */\n get current(): \"light\" | \"dark\" | undefined {\n return this.applied;\n }\n\n /** Moves the observer (e.g. a new GPS fix region) and re-evaluates. */\n setPosition(lat: number, lng: number): void {\n this.lat = lat;\n this.lng = lng;\n this.evaluate();\n }\n\n /** Stops all future flips. */\n dispose(): void {\n this.disposed = true;\n if (this.handle !== undefined) this.clearTimeoutFn(this.handle);\n this.handle = undefined;\n }\n\n /** Applies the theme for now and arms the timer for the next boundary. */\n private evaluate(): void {\n if (this.disposed) return;\n if (this.handle !== undefined) {\n this.clearTimeoutFn(this.handle);\n this.handle = undefined;\n }\n const nowDate = new Date(this.now());\n const theme = resolveTheme(nowDate, this.lat, this.lng);\n if (theme !== this.applied) {\n this.applied = theme;\n (theme === \"light\" ? this.onLight : this.onDark)();\n }\n const delay = this.nextBoundaryDelay(nowDate);\n this.handle = this.setTimeoutFn(() => this.evaluate(), delay);\n }\n\n /** Milliseconds until the next sunrise/sunset (or the polar re-check). */\n private nextBoundaryDelay(nowDate: Date): number {\n const nowMs = nowDate.getTime();\n // Today's events, then tomorrow's: the next boundary is the earliest\n // event strictly in the future.\n for (const dayOffset of [0, 1]) {\n const times = sunTimes(new Date(nowMs + dayOffset * DAY_MS), this.lat, this.lng);\n if (times === \"polarDay\" || times === \"polarNight\") continue;\n for (const event of [times.sunrise, times.sunset]) {\n const delta = event.getTime() - nowMs;\n if (delta > 0) return delta + BOUNDARY_MARGIN_MS;\n }\n }\n return POLAR_RECHECK_MS;\n }\n}\n","/**\n * Runtime label-language switching.\n *\n * MapMap tiles carry OpenMapTiles multilingual `name:*` fields\n * (https://openmaptiles.org/schema/), so a map can switch label language\n * without new tiles: rewrite each symbol layer's `text-field` to prefer\n * `name:{language}`. `setMapLanguage(map, \"de\")` does exactly that for\n * every layer whose text-field reads name fields (other text — road refs,\n * house numbers — is left untouched). Pass `null` to restore the compiled\n * style's default (`name:en` first).\n *\n * Server-side, themes can bake a language in with `theme.language`; this\n * helper is the client-side equivalent for user-facing toggles. For\n * right-to-left scripts (Arabic, Hebrew) also install MapLibre's RTL text\n * plugin in the app (`maplibregl.setRTLTextPlugin(...)`) — the SDK does\n * not fetch remote scripts on your behalf.\n */\nimport type { Map as MlMap } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\n\n/** ISO 639 primary subtag plus optional region/script subtag, e.g. `pt-BR`. */\nconst LANGUAGE_TAG = /^[a-z]{2,3}(-[A-Za-z0-9]{2,4})?$/;\n\n/**\n * The `text-field` expression for labels in `language` — the requested\n * language first, the Latin transliteration second, the local name last.\n * `null` yields the compiled default (`name:en`, then `name`).\n */\nexport function languageTextField(language: string | null): unknown {\n if (language === null) {\n return [\"coalesce\", [\"get\", \"name:en\"], [\"get\", \"name\"]];\n }\n return [\n \"coalesce\",\n [\"get\", `name:${language}`],\n [\"get\", \"name:latin\"],\n [\"get\", \"name\"],\n ];\n}\n\n/**\n * True when a layer's `text-field` reads `name`/`name:*` properties —\n * i.e. it is a place/POI/road-name label whose language can switch.\n * Fields reading other properties (`ref` shields, house numbers) are not.\n */\nexport function isNameTextField(textField: unknown): boolean {\n if (typeof textField === \"string\") {\n // Token syntax: \"{name}\", \"{name:en} ({name:latin})\", …\n return /\\{name(?::[A-Za-z0-9-]+)?\\}/.test(textField);\n }\n if (Array.isArray(textField)) {\n if (\n textField.length === 2 &&\n textField[0] === \"get\" &&\n typeof textField[1] === \"string\"\n ) {\n return textField[1] === \"name\" || textField[1].startsWith(\"name:\");\n }\n return textField.some((part) => isNameTextField(part));\n }\n return false;\n}\n\n/**\n * Switches every name-label layer of the map's current style to\n * `language` (`null` restores the style's default). Returns the ids of\n * the layers it rewrote. Throws on a malformed language tag. Reapply\n * after `setStyle` — a style swap resets label languages.\n */\nexport function setMapLanguage(\n map: MapMapMap | MlMap,\n language: string | null,\n): string[] {\n if (language !== null && !LANGUAGE_TAG.test(language)) {\n throw new Error(\n `invalid language tag ${JSON.stringify(language)}; use e.g. \"de\", \"pt-BR\", \"zh-Hans\"`,\n );\n }\n const ml = map instanceof MapMapMap ? map.map : map;\n const layers = ml.getStyle()?.layers ?? [];\n const changed: string[] = [];\n for (const layer of layers) {\n if (layer.type !== \"symbol\") continue;\n const textField = (layer.layout as Record<string, unknown> | undefined)?.[\n \"text-field\"\n ];\n if (textField === undefined || !isNameTextField(textField)) continue;\n ml.setLayoutProperty(layer.id, \"text-field\", languageTextField(language));\n changed.push(layer.id);\n }\n return changed;\n}\n","/**\n * Probe batch upload - the browser side of opt-in aggregate collection.\n *\n * The wasm nav core (`@mapmap/core` `GuidanceSession`) accumulates aggregates\n * on-device and hands back the exact body to POST via `finishProbeJson()`;\n * this helper delivers it to the gateway's `POST /v1/probe`, with the same\n * status handling and retry policy as the mobile SDKs. Aggregates only - the\n * core is architecturally incapable of emitting a trajectory.\n *\n * Consent is the caller's responsibility: only upload for a key whose operator\n * has set `probe_opt_in`, and - in a browser - only with the user's opt-in\n * (ePrivacy/PECR) consent. See `docs/PROBE-SDK-INTEGRATION.md`.\n *\n * @example\n * ```ts\n * const body = session.finishProbeJson(arrived, Date.now());\n * if (body) void uploadProbeBatch(\"https://api.mapmap.ai\", apiKey, body);\n * ```\n */\n\n/** The outcome of an upload attempt. */\nexport type ProbeUploadOutcome =\n | \"accepted\" // 202 - stored\n | \"refused\" // 403 - key not opted in; not retried\n | \"notEnabled\" // 501 - server collection off (SN_PROBE_DIR unset); not retried\n | \"rejected\" // 400/other 4xx - malformed; not retried\n | \"gaveUp\"; // network error or 5xx after exhausting retries\n\n/** Options for {@link uploadProbeBatch}. All optional. */\nexport interface UploadProbeOptions {\n /** Injectable fetch (defaults to the global). */\n fetch?: typeof fetch;\n /** Total attempts including the first (default 4). */\n maxAttempts?: number;\n /** Attempt number → delay before the next try, ms (default `attempt*1000`). */\n backoffMs?: (attempt: number) => number;\n /** Injectable delay, for deterministic tests (default `setTimeout`). */\n sleep?: (ms: number) => Promise<void>;\n /** Abort signal forwarded to fetch. */\n signal?: AbortSignal;\n}\n\n/** The `/v1/probe` endpoint for a gateway origin (trailing slashes trimmed). */\nexport function buildProbeUrl(baseUrl: string): string {\n return `${baseUrl.replace(/\\/+$/, \"\")}/v1/probe`;\n}\n\n/**\n * POST one probe body to `{baseUrl}/v1/probe` with a bearer key. Transient\n * failures (network or `5xx`) are retried with bounded backoff; permanent ones\n * (`400`/`403`/`501`) are not. Resolves with the terminal outcome and never\n * rejects, so a fire-and-forget `void uploadProbeBatch(...)` is safe.\n *\n * @param body the string returned by `GuidanceSession.finishProbeJson()`.\n */\nexport async function uploadProbeBatch(\n baseUrl: string,\n apiKey: string,\n body: string,\n options: UploadProbeOptions = {},\n): Promise<ProbeUploadOutcome> {\n const doFetch = options.fetch ?? globalThis.fetch;\n const maxAttempts = options.maxAttempts ?? 4;\n const backoffMs = options.backoffMs ?? ((attempt) => attempt * 1000);\n const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n const url = buildProbeUrl(baseUrl);\n\n for (let attempt = 1; ; attempt++) {\n let outcome: ProbeUploadOutcome;\n try {\n const response = await doFetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body,\n signal: options.signal,\n });\n outcome = classifyStatus(response.status);\n } catch {\n outcome = \"gaveUp\";\n }\n\n if (outcome === \"gaveUp\" && attempt < maxAttempts) {\n await sleep(backoffMs(attempt));\n continue;\n }\n return outcome;\n }\n}\n\nfunction classifyStatus(status: number): ProbeUploadOutcome {\n if (status === 202) return \"accepted\";\n if (status === 403) return \"refused\";\n if (status === 501) return \"notEnabled\";\n if (status >= 500 && status <= 599) return \"gaveUp\";\n return \"rejected\";\n}\n","/**\n * PlacesLayer - drop your own places (store locations, depots, POIs) onto a\n * MapMap map: the store-finder use case.\n *\n * A GeoJSON source plus MapLibre layers, following the RouteLayer pattern:\n * native clustering (`cluster: true` on the source) with count badges,\n * click-to-expand clusters, a typed `onPlaceClick` callback and an optional\n * built-in popup, plus pure `nearest()` (haversine) and gateway-backed\n * `nearestByDriveTime()` (`POST /matrix`) helpers for \"which branch is\n * closest?\".\n *\n * Like RouteLayer, the layer survives `setStyle` (light/dark theme swaps):\n * places are re-installed on every `style.load`.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n CircleLayerSpecification,\n ExpressionSpecification,\n GeoJSONSource,\n MapLayerMouseEvent,\n Map as MlMap,\n Popup,\n SymbolLayerSpecification,\n} from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { SIGNAL_BLUE } from \"./route.js\";\n\n/** Mean Earth radius in metres (IUGG), as used by turf and PostGIS. */\nconst EARTH_RADIUS_M = 6371008.8;\n/** Font stack for cluster-count badges; ships with the MapMap default styles. */\nconst CLUSTER_TEXT_FONT = \"MapMap Sans Regular\";\n\n/** One place to show on the map - a store, depot, branch, POI. */\nexport interface Place {\n /** Stable unique id, e.g. your store number. */\n id: string;\n /** Display name. */\n name: string;\n /** Latitude, degrees. */\n lat: number;\n /** Longitude, degrees. */\n lon: number;\n /**\n * Arbitrary extra data (opening hours, phone, …). Every key is copied\n * verbatim onto the top level of the GeoJSON feature's `properties`,\n * alongside the reserved `id`, `name` and `__mapmapIndex` keys (which win\n * on collision) - so scalar values are directly addressable from a\n * data-driven `color` expression, e.g. `[\"get\", \"category\"]`. MapLibre\n * JSON-stringifies nested objects/arrays at render time, so keep anything\n * you want to style on as a top-level string/number/boolean. The whole\n * object also comes back on the place handed to `onPlaceClick` / `popup`.\n */\n properties?: Record<string, unknown>;\n}\n\n/** A GeoJSON Point feature, as accepted in a {@link PlacesFeatureCollection}. */\nexport interface PlacePointFeature {\n type: \"Feature\";\n id?: string | number;\n geometry: { type: \"Point\"; coordinates: number[] };\n properties?: Record<string, unknown> | null;\n}\n\n/**\n * A plain GeoJSON FeatureCollection of Points, accepted anywhere a `Place[]`\n * is (structurally compatible with `@types/geojson`'s\n * `FeatureCollection<Point>`). See {@link placesFromGeoJSON} for how ids and\n * names are derived.\n */\nexport interface PlacesFeatureCollection {\n type: \"FeatureCollection\";\n features: PlacePointFeature[];\n}\n\n/** Either input shape for {@link PlacesLayer} / `setPlaces`. */\nexport type PlacesInput = Place[] | PlacesFeatureCollection;\n\n/** A place with its straight-line distance attached (see `nearest`). */\nexport type PlaceWithDistance = Place & {\n /** Straight-line (haversine) distance from the origin, metres. */\n distanceM: number;\n};\n\n/** A place with gateway drive time attached (see `nearestByDriveTime`). */\nexport type PlaceWithDriveTime = Place & {\n /** Drive time from the origin, seconds. */\n durationS: number;\n /** Driven distance from the origin, metres (`null` when not returned). */\n distanceM: number | null;\n};\n\n/** A custom pin image for unclustered places. */\nexport interface PlacesIcon {\n /** Image URL (any format `Map#loadImage` accepts, e.g. PNG). */\n url: string;\n /** MapLibre `icon-size` scale factor. Defaults to `1`. */\n size?: number;\n}\n\n/** Options for {@link PlacesLayer.nearestByDriveTime}. */\nexport interface NearestByDriveTimeOptions {\n /** How many places to return. Defaults to `1`. */\n n?: number;\n /**\n * Gateway costing model, e.g. `\"auto\"` (default) or `\"truck\"` (Premium\n * price class - see `POST /matrix` in the API docs).\n */\n costing?: string;\n /**\n * Valhalla-style costing options forwarded verbatim, e.g.\n * `{ truck: { height: 4.0 } }`.\n */\n costingOptions?: Record<string, unknown>;\n}\n\nexport interface PlacesLayerOptions {\n /** Initial places. Also settable later via {@link PlacesLayer.setPlaces}. */\n places?: PlacesInput;\n /** Cluster nearby places into count badges. Defaults to `true`. */\n cluster?: boolean;\n /** Cluster radius in pixels. Defaults to MapLibre's `50`. */\n clusterRadius?: number;\n /** Max zoom to cluster at. Defaults to MapLibre's `14`. */\n clusterMaxZoom?: number;\n /**\n * Pin colour: a CSS colour string, or a MapLibre expression evaluated\n * against each feature's `properties` for per-category pins, e.g.\n * `[\"match\", [\"get\", \"category\"], \"food\", \"#e63946\", \"#3a86ff\"]` (see\n * {@link Place.properties} for what an expression can `get`). Defaults to\n * MapMap signal blue (`#3a86ff`). Only styles the default circle pins -\n * ignored with a custom `icon`. A cluster mixes categories, so an\n * expression never applies to clusters: they use `clusterColor`.\n */\n color?: string | ExpressionSpecification;\n /**\n * Cluster circle colour. Defaults to `color` when that is a plain string,\n * else to MapMap signal blue (a cluster mixes categories, so a\n * data-driven `color` expression cannot apply to it).\n */\n clusterColor?: string;\n /**\n * Custom pin image for unclustered places (a symbol layer instead of the\n * default circle). If the image fails to load, the circle look is used.\n */\n icon?: PlacesIcon;\n /**\n * Fit the map to the places the first time they are set. Defaults to\n * `false` (the map view is left alone).\n */\n fitBounds?: boolean;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-places\"`. */\n id?: string;\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Called when an individual (unclustered) place is clicked. */\n onPlaceClick?: (place: Place, lngLat: { lng: number; lat: number }) => void;\n /**\n * Built-in popup: return HTML (a string is set with `setHTML`, an element\n * with `setDOMContent`) and a `maplibregl.Popup` opens at the place on\n * click. Omit for no popup.\n */\n popup?: (place: Place) => string | HTMLElement;\n}\n\n/** The generated MapLibre source/layer ids (see {@link PlacesLayer.ids}). */\nexport interface PlacesLayerIds {\n /** The GeoJSON source id. */\n source: string;\n /** The unclustered-points layer id (circle, or symbol with `icon`). */\n points: string;\n /** The cluster circles layer id (only installed with `cluster: true`). */\n clusters: string;\n /** The cluster count badge layer id (only installed with `cluster: true`). */\n clusterCounts: string;\n}\n\n/** Options for {@link PlacesLayer.select}. */\nexport interface PlacesSelectOptions {\n /** Open the layer's configured `popup` at the place. Defaults to `true`. */\n popup?: boolean;\n /** Ease the camera to the place. Defaults to `true`. */\n flyTo?: boolean;\n /** Zoom for the camera move (with `flyTo`). Keeps the current zoom if omitted. */\n zoom?: number;\n}\n\n/**\n * Normalise a GeoJSON FeatureCollection of Points to `Place[]`. The id comes\n * from `feature.id`, then `properties.id`, then the feature index; the name\n * from `properties.name` (else `\"\"`). Non-Point features are skipped.\n */\nexport function placesFromGeoJSON(\n collection: PlacesFeatureCollection,\n): Place[] {\n const places: Place[] = [];\n collection.features.forEach((feature, index) => {\n if (feature.geometry?.type !== \"Point\") return;\n const [lon, lat] = feature.geometry.coordinates;\n if (typeof lon !== \"number\" || typeof lat !== \"number\") {\n throw new Error(`place feature ${index} has no [lon, lat] coordinates`);\n }\n const props = feature.properties ?? {};\n const rawId = feature.id ?? props[\"id\"];\n const place: Place = {\n id:\n typeof rawId === \"string\" || typeof rawId === \"number\"\n ? String(rawId)\n : String(index),\n name: typeof props[\"name\"] === \"string\" ? props[\"name\"] : \"\",\n lat,\n lon,\n };\n if (feature.properties) place.properties = feature.properties;\n places.push(place);\n });\n return places;\n}\n\n/** Straight-line (haversine) distance between two points, metres. */\nexport function haversineDistanceM(\n a: { lat: number; lon: number },\n b: { lat: number; lon: number },\n): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b.lat - a.lat);\n const dLon = rad(b.lon - a.lon);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/** The GeoJSON built for the source; one Point feature per place. */\ninterface PlacesSourceData {\n type: \"FeatureCollection\";\n features: {\n type: \"Feature\";\n geometry: { type: \"Point\"; coordinates: [number, number] };\n properties: Record<string, unknown>;\n }[];\n}\n\n/** Draws customer places on a MapLibre map, with clustering and popups. */\nexport class PlacesLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string | undefined;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly clustersLayerId: string;\n private readonly clusterCountLayerId: string;\n private readonly pointsLayerId: string;\n private readonly iconImageId: string;\n private readonly cluster: boolean;\n private readonly clusterRadius: number | undefined;\n private readonly clusterMaxZoom: number | undefined;\n private readonly color: string | ExpressionSpecification;\n private readonly clusterColor: string;\n private readonly icon: PlacesIcon | undefined;\n private readonly wantFitBounds: boolean;\n private readonly onPlaceClick:\n | ((place: Place, lngLat: { lng: number; lat: number }) => void)\n | undefined;\n private readonly popupFn:\n | ((place: Place) => string | HTMLElement)\n | undefined;\n private places: Place[] = [];\n private data: PlacesSourceData | undefined;\n private popup: Popup | undefined;\n private fitted = false;\n private destroyed = false;\n\n constructor(map: MapMapMap | MlMap, options: PlacesLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n } else {\n this.map = map;\n this.baseUrl = options.baseUrl?.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n const id = options.id ?? \"mapmap-places\";\n this.sourceId = `${id}-src`;\n this.clustersLayerId = `${id}-clusters`;\n this.clusterCountLayerId = `${id}-cluster-count`;\n this.pointsLayerId = `${id}-points`;\n this.iconImageId = `${id}-icon`;\n this.cluster = options.cluster ?? true;\n this.clusterRadius = options.clusterRadius;\n this.clusterMaxZoom = options.clusterMaxZoom;\n this.color = options.color ?? SIGNAL_BLUE;\n this.clusterColor =\n options.clusterColor ??\n (typeof this.color === \"string\" ? this.color : SIGNAL_BLUE);\n this.icon = options.icon;\n this.wantFitBounds = options.fitBounds ?? false;\n this.onPlaceClick = options.onPlaceClick;\n this.popupFn = options.popup;\n\n // Same lifecycle as RouteLayer: runtime sources/layers are wiped on\n // every setStyle (theme swap), so re-install on each style.load - which\n // also completes a setPlaces that arrived before the style had loaded.\n this.map.on(\"style.load\", this.handleStyleLoad);\n // Delegated layer events survive layer re-installation (they are bound\n // to the layer id, not the layer object), so bind them once here.\n this.map.on(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.on(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.on(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.on(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n\n if (options.places) this.setPlaces(options.places);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.data) this.install(this.data);\n };\n\n private readonly handleMouseEnter = (): void => {\n this.map.getCanvas().style.cursor = \"pointer\";\n };\n\n private readonly handleMouseLeave = (): void => {\n this.map.getCanvas().style.cursor = \"\";\n };\n\n private readonly handlePlaceClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const index: unknown = feature.properties?.[\"__mapmapIndex\"];\n if (typeof index !== \"number\") return;\n const place = this.places[index];\n if (!place) return;\n this.onPlaceClick?.(place, { lng: e.lngLat.lng, lat: e.lngLat.lat });\n if (this.popupFn) this.openPopup(place);\n };\n\n private readonly handleClusterClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const clusterId: unknown = feature.properties?.[\"cluster_id\"];\n if (typeof clusterId !== \"number\") return;\n const source = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (!source) return;\n const geometry = feature.geometry;\n if (geometry.type !== \"Point\") return;\n const [lng, lat] = geometry.coordinates;\n if (typeof lng !== \"number\" || typeof lat !== \"number\") return;\n void source\n .getClusterExpansionZoom(clusterId)\n .then((zoom) => {\n if (!this.destroyed) this.map.easeTo({ center: [lng, lat], zoom });\n })\n .catch(() => {\n /* cluster no longer in the source (data changed mid-flight) */\n });\n };\n\n /**\n * Replace the layer's places - a `Place[]` or a GeoJSON FeatureCollection\n * of Points. Never silently drops an update: once the source exists the\n * data is applied immediately, even while `isStyleLoaded()` is transiently\n * `false` mid-render (search-as-you-type just works); calls made before\n * the source has first been installed are stashed - the latest one wins -\n * and installed on the next `style.load`. With `fitBounds: true` the\n * first non-empty set also fits the map view.\n */\n setPlaces(places: PlacesInput): void {\n this.places = Array.isArray(places) ? places : placesFromGeoJSON(places);\n this.data = {\n type: \"FeatureCollection\",\n features: this.places.map((place, index) => ({\n type: \"Feature\",\n geometry: { type: \"Point\", coordinates: [place.lon, place.lat] },\n properties: {\n ...place.properties,\n id: place.id,\n name: place.name,\n __mapmapIndex: index,\n },\n })),\n };\n if (this.wantFitBounds && !this.fitted && this.places.length > 0) {\n this.fitted = true;\n this.map.fitBounds(boundsOf(this.places), { padding: 48, maxZoom: 15 });\n }\n const source = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (source) {\n // setData on an existing source is safe even while isStyleLoaded()\n // is transiently false (tiles/cluster work in flight) - never drop\n // an update once the source is installed.\n source.setData(this.data);\n } else if (this.map.isStyleLoaded()) {\n this.install(this.data);\n }\n // else: kept in this.data (latest call wins) until handleStyleLoad.\n }\n\n /** The layer's current places (normalised to `Place[]`). */\n get current(): Place[] {\n return this.places;\n }\n\n /**\n * The generated MapLibre source/layer ids - public API for escape-hatch\n * styling (`map.setPaintProperty`, `queryRenderedFeatures`, …) beyond the\n * layer's options. Stable for the layer's lifetime, derived from the `id`\n * option (default `\"mapmap-places\"`). The cluster ids are only installed\n * on the map with `cluster: true` (the default), and `points` is a circle\n * layer by default or a symbol layer once a custom `icon` has loaded.\n */\n get ids(): PlacesLayerIds {\n return {\n source: this.sourceId,\n points: this.pointsLayerId,\n clusters: this.clustersLayerId,\n clusterCounts: this.clusterCountLayerId,\n };\n }\n\n /**\n * Programmatically select a place by id - list-to-map sync for a store\n * finder's results list. Opens the layer's configured `popup` at the\n * place (`popup: false` to skip, no-op without a `popup` option) and\n * eases the camera to it (`flyTo: false` to skip; `zoom` to also zoom).\n * Returns the selected place, or `undefined` for an unknown id (in which\n * case nothing happens). Does NOT invoke `onPlaceClick` - a programmatic\n * selection is not a user click.\n */\n select(id: string, options: PlacesSelectOptions = {}): Place | undefined {\n const place = this.places.find((p) => p.id === id);\n if (!place) return undefined;\n if (options.flyTo ?? true) {\n this.map.easeTo({\n center: [place.lon, place.lat],\n ...(options.zoom !== undefined ? { zoom: options.zoom } : {}),\n });\n }\n if (options.popup ?? true) this.openPopup(place);\n return place;\n }\n\n /** Close the popup opened by {@link select} or a place click, if any. */\n deselect(): void {\n this.popup?.remove();\n this.popup = undefined;\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by straight-line\n * (haversine) distance, each with `distanceM` attached. Pure and instant -\n * no network. For road-network answers use {@link nearestByDriveTime}.\n */\n nearest(origin: { lat: number; lon: number }, n = 1): PlaceWithDistance[] {\n return this.places\n .map((place) => ({ ...place, distanceM: haversineDistanceM(origin, place) }))\n .sort((a, b) => a.distanceM - b.distanceM)\n .slice(0, Math.max(0, n));\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by drive time, via the\n * gateway's `POST /matrix` (one source, all places as targets). Resolves\n * to places sorted by `durationS` ascending, with the driven `distanceM`\n * attached; unreachable places (`null` duration) are dropped. Needs the\n * gateway `baseUrl`/`apiKey` - picked up from a `MapMapMap` automatically,\n * or pass them as layer options.\n */\n async nearestByDriveTime(\n origin: { lat: number; lon: number },\n options: NearestByDriveTimeOptions = {},\n ): Promise<PlaceWithDriveTime[]> {\n if (!this.baseUrl) {\n throw new Error(\n \"PlacesLayer needs a baseUrl (or a MapMapMap) for nearestByDriveTime\",\n );\n }\n if (this.places.length === 0) return [];\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n const body: Record<string, unknown> = {\n sources: [{ lat: origin.lat, lon: origin.lon }],\n targets: this.places.map((p) => ({ lat: p.lat, lon: p.lon })),\n costing: options.costing ?? \"auto\",\n };\n if (options.costingOptions) body[\"costing_options\"] = options.costingOptions;\n\n const response = await fetch(`${this.baseUrl}/matrix`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n const payload: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `matrix request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n const { durations, distances } = matrixRows(payload);\n\n const reachable: PlaceWithDriveTime[] = [];\n this.places.forEach((place, index) => {\n const durationS = durations[index];\n if (typeof durationS !== \"number\") return; // null = unreachable\n const distanceM = distances?.[index];\n reachable.push({\n ...place,\n durationS,\n distanceM: typeof distanceM === \"number\" ? distanceM : null,\n });\n });\n reachable.sort((a, b) => a.durationS - b.durationS);\n return reachable.slice(0, Math.max(0, options.n ?? 1));\n }\n\n /** Add-or-update the source and layers on the current style. */\n private install(data: PlacesSourceData): void {\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n this.map.addSource(this.sourceId, {\n type: \"geojson\",\n data,\n cluster: this.cluster,\n ...(this.cluster && this.clusterRadius !== undefined\n ? { clusterRadius: this.clusterRadius }\n : {}),\n ...(this.cluster && this.clusterMaxZoom !== undefined\n ? { clusterMaxZoom: this.clusterMaxZoom }\n : {}),\n });\n }\n\n if (this.cluster) this.installClusterLayers();\n this.installPointsLayer();\n }\n\n /** Cluster circles (sized by count) and the count badge on top. */\n private installClusterLayers(): void {\n if (!this.map.getLayer(this.clustersLayerId)) {\n const clusters: CircleLayerSpecification = {\n id: this.clustersLayerId,\n type: \"circle\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n paint: {\n \"circle-color\": this.clusterColor,\n \"circle-opacity\": 0.9,\n \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 16, 25, 20, 100, 26],\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(clusters);\n }\n if (!this.map.getLayer(this.clusterCountLayerId)) {\n const count: SymbolLayerSpecification = {\n id: this.clusterCountLayerId,\n type: \"symbol\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n layout: {\n \"text-field\": [\"get\", \"point_count_abbreviated\"],\n \"text-font\": [CLUSTER_TEXT_FONT],\n \"text-size\": 12,\n },\n paint: { \"text-color\": \"#ffffff\" },\n };\n this.map.addLayer(count);\n }\n }\n\n /**\n * The unclustered-places layer: a circle pin by default, or a symbol\n * layer once the custom `icon` image has loaded (falling back to the\n * circle look if it fails, like PositionPuck's image fallback).\n */\n private installPointsLayer(): void {\n if (this.map.getLayer(this.pointsLayerId)) return;\n if (!this.icon) {\n this.addCirclePointsLayer();\n return;\n }\n if (this.map.hasImage(this.iconImageId)) {\n this.addIconPointsLayer();\n return;\n }\n void this.map\n .loadImage(this.icon.url)\n .then((image) => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n if (!this.map.hasImage(this.iconImageId)) {\n this.map.addImage(this.iconImageId, image.data);\n }\n this.addIconPointsLayer();\n })\n .catch(() => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n this.addCirclePointsLayer();\n });\n }\n\n private addCirclePointsLayer(): void {\n const points: CircleLayerSpecification = {\n id: this.pointsLayerId,\n type: \"circle\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n paint: {\n \"circle-color\": this.color,\n \"circle-radius\": 7,\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(points);\n }\n\n private addIconPointsLayer(): void {\n const points: SymbolLayerSpecification = {\n id: this.pointsLayerId,\n type: \"symbol\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n layout: {\n \"icon-image\": this.iconImageId,\n \"icon-size\": this.icon?.size ?? 1,\n \"icon-allow-overlap\": true,\n },\n };\n this.map.addLayer(points);\n }\n\n /** Open the built-in popup for a place, replacing any previous one. */\n private openPopup(place: Place): void {\n if (!this.popupFn) return;\n const content = this.popupFn(place);\n const popup = new maplibregl.Popup({ offset: 12 }).setLngLat([\n place.lon,\n place.lat,\n ]);\n if (typeof content === \"string\") popup.setHTML(content);\n else popup.setDOMContent(content);\n this.popup?.remove();\n this.popup = popup.addTo(this.map);\n }\n\n /** Remove the places' layers, source, image and popup from the map. */\n clear(): void {\n this.popup?.remove();\n this.popup = undefined;\n for (const layerId of [\n this.pointsLayerId,\n this.clusterCountLayerId,\n this.clustersLayerId,\n ]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n if (this.map.hasImage(this.iconImageId)) {\n this.map.removeImage(this.iconImageId);\n }\n this.places = [];\n this.data = undefined;\n }\n\n /**\n * Remove the places and detach every listener (style.load, clicks,\n * hovers). Call when disposing of the layer (the map is left untouched).\n */\n destroy(): void {\n this.destroyed = true;\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.map.off(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.off(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.off(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.off(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n this.clear();\n }\n}\n\n/** Bounding box of a non-empty place list, as MapLibre `fitBounds` corners. */\nfunction boundsOf(\n places: Place[],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const { lon, lat } of places) {\n if (lon < minLng) minLng = lon;\n if (lat < minLat) minLat = lat;\n if (lon > maxLng) maxLng = lon;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n/**\n * Pull the origin's rows out of a `POST /matrix` response\n * (`{\"durations\": [[…]], \"distances\": [[…]]}`, row-major, one row here\n * because we send a single source). Throws on anything else.\n */\nfunction matrixRows(payload: unknown): {\n durations: (number | null)[];\n distances: (number | null)[] | undefined;\n} {\n if (typeof payload !== \"object\" || payload === null) {\n throw new Error(\"matrix returned a non-object response\");\n }\n const obj = payload as Record<string, unknown>;\n const durations = firstRow(obj[\"durations\"]);\n if (!durations) {\n throw new Error(\"matrix response has no durations row\");\n }\n return { durations, distances: firstRow(obj[\"distances\"]) };\n}\n\n/** The first row of a row-major `(number | null)[][]`, if that is the shape. */\nfunction firstRow(value: unknown): (number | null)[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const row: unknown = value[0];\n if (!Array.isArray(row)) return undefined;\n return row.map((cell: unknown) =>\n typeof cell === \"number\" && Number.isFinite(cell) ? cell : null,\n );\n}\n","/**\n * NavigationCamera - the turnkey chase-cam for turn-by-turn navigation.\n *\n * Packages the Google-Maps-style follow camera on top of MapLibre's native\n * camera: per-fix `easeTo` with linear easing (continuous glide, no\n * rubber-banding), course-up bearing, a tilted pitch preset, and a\n * screen-offset that anchors the puck low-centre so the camera looks ahead.\n * User gestures (drag, rotate, pitch, zoom) switch the camera to `\"free\"`\n * mode; it auto-recentres after a configurable idle period. An `overview()`\n * mode fits the whole route top-down, and `resume()` returns to the chase\n * cam at the last known fix.\n *\n * Like `RouteLayer`, the class holds only a structural handle on the map\n * (`easeTo`, `fitBounds`, `stop`, events, container) so it is unit-testable\n * against a fake without a WebGL context.\n *\n * Globe projection note: {@link NavigationCamera.isSupported} returns\n * `false` when the map runs the globe (or vertical-perspective) projection.\n * At navigation zooms globe renders much like mercator, but the pixel-offset\n * anchor maths and the top-down overview framing assume a mercator camera;\n * switch the map to mercator (`map.setProjection({ type: \"mercator\" })`)\n * before navigating, or accept an unanchored follow.\n */\nimport type { Map as MlMap } from \"maplibre-gl\";\nimport { unwrapLngs } from \"./coords.js\";\nimport { MapMapMap } from \"./map.js\";\nimport type { PositionPuck } from \"./puck.js\";\nimport type { ParsedRoute, RouteGeometry } from \"./types.js\";\n\n/** A GPS fix to follow. */\nexport interface CameraFix {\n lat: number;\n lon: number;\n}\n\n/** The camera's current behaviour. */\nexport type NavigationCameraMode = \"follow\" | \"overview\" | \"free\";\n\nexport interface NavigationCameraOptions {\n /**\n * Camera tilt in degrees, clamped to 0-85. Default `60` - MapLibre's\n * non-experimental ceiling; values above 60 may show rendering artefacts\n * and flatten DOM-marker pucks. When the requested pitch exceeds the\n * map's `maxPitch`, the limit is raised to match.\n *\n * Precedence: this option > the Studio design's `camera.pitch` (when the\n * map is a `MapMapMap` whose theme carried `extra.nav.camera`) > the\n * built-in default.\n */\n pitch?: number;\n /**\n * Follow-mode zoom. Default `17`. Same precedence as `pitch`: option >\n * Studio design `camera.zoom` > built-in default.\n */\n zoom?: number;\n /**\n * Where the fix (and puck) sits vertically on screen, as a fraction of\n * the container height from the top, clamped to 0-1. Default `0.72` -\n * the puck rides low so the camera looks up the road ahead.\n */\n anchorY?: number;\n /**\n * Ease duration per {@link NavigationCamera.follow} call, milliseconds.\n * Default `900`, and always capped by the observed fix interval so a\n * fast fix cadence never queues up lagging animations.\n */\n easeMs?: number;\n /**\n * Idle time after the last user gesture before the camera recentres\n * itself back to follow mode, milliseconds. Default `6000`; `0` disables\n * auto-recentre (the app must call {@link NavigationCamera.resume}).\n */\n autoRecentreMs?: number;\n}\n\n/** The map-interaction events that hand the camera to the user. */\nconst INTERACTION_EVENTS = [\n \"dragstart\",\n \"rotatestart\",\n \"pitchstart\",\n \"zoomstart\",\n] as const;\n\nconst DEFAULT_PITCH = 60;\nconst DEFAULT_ZOOM = 17;\nconst DEFAULT_ANCHOR_Y = 0.72;\nconst DEFAULT_EASE_MS = 900;\nconst DEFAULT_AUTO_RECENTRE_MS = 6000;\n/** Screen padding around the route in overview mode, pixels. */\nconst OVERVIEW_PADDING_PX = 48;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Anything with a `PositionPuck`-shaped `setLocation` can be co-driven. */\ntype CoDrivenPuck = Pick<PositionPuck, \"setLocation\">;\n\n/** A follow-mode chase camera for MapMap maps. */\nexport class NavigationCamera {\n private readonly m: MlMap;\n private readonly pitch: number;\n private readonly zoom: number;\n private readonly anchorY: number;\n private readonly easeMs: number;\n private readonly autoRecentreMs: number;\n\n private currentMode: NavigationCameraMode = \"follow\";\n private puck: CoDrivenPuck | undefined;\n private lastFix: CameraFix | undefined;\n private lastCourse: number | undefined;\n private lastFixAt: number | undefined;\n private lastRoute: RouteGeometry | undefined;\n private recentreTimer: ReturnType<typeof setTimeout> | undefined;\n private destroyed = false;\n\n // Bound once so `off` in destroy() removes exactly what `on` added.\n private readonly onInteraction = (ev?: { originalEvent?: unknown }): void => {\n // Camera-driven moves (our own easeTo/fitBounds) fire the same events\n // without an `originalEvent`; only real user gestures carry one.\n if (!ev?.originalEvent || this.destroyed) return;\n this.currentMode = \"free\";\n this.m.stop();\n this.scheduleRecentre();\n };\n\n /**\n * `false` when the map runs the globe (or vertical-perspective)\n * projection, whose camera geometry breaks the low-anchor offset maths\n * and top-down overview framing. Switch to mercator for navigation.\n */\n static isSupported(map: MapMapMap | MlMap): boolean {\n const m = map instanceof MapMapMap ? map.map : map;\n const projection = (\n m as { getProjection?: () => unknown }\n ).getProjection?.();\n return !usesGlobe(projection);\n }\n\n constructor(map: MapMapMap | MlMap, options: NavigationCameraOptions = {}) {\n this.m = map instanceof MapMapMap ? map.map : map;\n // A MapMapMap built from a Studio theme may carry `extra.nav.camera`;\n // its pitch/zoom become the option defaults. Precedence: explicit\n // option > design > built-in default.\n const design = map instanceof MapMapMap ? map.navDesign?.camera : undefined;\n this.pitch = clamp(options.pitch ?? design?.pitch ?? DEFAULT_PITCH, 0, 85);\n this.zoom = options.zoom ?? design?.zoom ?? DEFAULT_ZOOM;\n this.anchorY = clamp(options.anchorY ?? DEFAULT_ANCHOR_Y, 0, 1);\n this.easeMs = Math.max(0, options.easeMs ?? DEFAULT_EASE_MS);\n this.autoRecentreMs = Math.max(\n 0,\n options.autoRecentreMs ?? DEFAULT_AUTO_RECENTRE_MS,\n );\n\n // A pitch preset above the map's ceiling would be silently clamped by\n // MapLibre; raise the ceiling to honour the preset (never lower it).\n if (this.pitch > this.m.getMaxPitch()) this.m.setMaxPitch(this.pitch);\n\n for (const event of INTERACTION_EVENTS) {\n this.m.on(event, this.onInteraction);\n }\n }\n\n /** The camera's current behaviour: `\"follow\"`, `\"overview\"` or `\"free\"`. */\n get mode(): NavigationCameraMode {\n return this.currentMode;\n }\n\n /**\n * Co-drive a {@link PositionPuck}: every {@link follow} call also\n * `setLocation`s the puck, so camera and puck never diverge.\n */\n attachPuck(puck: CoDrivenPuck): void {\n this.puck = puck;\n }\n\n /**\n * Glide the camera to a fix, course-up when `courseDeg` is given\n * (bearing is left unchanged when it is `undefined`). Each call eases\n * with linear timing over `easeMs` capped by the observed fix interval,\n * and interrupts the previous ease (no queue buildup). The fix and an\n * attached puck are always updated, but the camera only moves in\n * `\"follow\"` mode - `\"free\"` and `\"overview\"` record the fix for\n * {@link resume}.\n */\n follow(fix: CameraFix, courseDeg?: number): void {\n const now = Date.now();\n const interval =\n this.lastFixAt === undefined\n ? this.easeMs\n : Math.max(0, now - this.lastFixAt);\n this.lastFixAt = now;\n this.lastFix = fix;\n if (courseDeg !== undefined) this.lastCourse = courseDeg;\n this.puck?.setLocation(fix, courseDeg);\n if (this.currentMode !== \"follow\") return;\n this.easeToFix(fix, courseDeg, Math.min(this.easeMs, interval));\n }\n\n /**\n * Fit the route top-down (pitch 0, north-up). Pass the route geometry on\n * the first call; later calls reuse the last geometry given. A no-op\n * when no geometry has ever been provided.\n */\n overview(routeGeometry?: RouteGeometry): void {\n if (routeGeometry) this.lastRoute = routeGeometry;\n const route = this.lastRoute;\n if (!route || route.coordinates.length === 0) return;\n this.clearRecentreTimer();\n this.currentMode = \"overview\";\n this.m.fitBounds(boundsOf(route.coordinates), {\n padding: OVERVIEW_PADDING_PX,\n pitch: 0,\n bearing: 0,\n duration: this.easeMs,\n essential: true,\n });\n }\n\n /**\n * Return to follow mode, gliding back to the last fix (with its last\n * known course) when one has been recorded.\n */\n resume(): void {\n this.clearRecentreTimer();\n this.currentMode = \"follow\";\n if (this.lastFix) {\n this.easeToFix(this.lastFix, this.lastCourse, this.easeMs);\n }\n }\n\n /** Remove the map listeners and cancel any pending auto-recentre. */\n destroy(): void {\n this.destroyed = true;\n this.clearRecentreTimer();\n for (const event of INTERACTION_EVENTS) {\n this.m.off(event, this.onInteraction);\n }\n }\n\n private easeToFix(\n fix: CameraFix,\n courseDeg: number | undefined,\n duration: number,\n ): void {\n this.m.easeTo({\n center: [fix.lon, fix.lat],\n ...(courseDeg !== undefined ? { bearing: courseDeg } : {}),\n pitch: this.pitch,\n zoom: this.zoom,\n offset: [0, this.anchorOffsetY()],\n duration,\n easing: (t: number) => t,\n // Interrupt semantics: `essential` easings run even under\n // prefers-reduced-motion, and each new easeTo cancels the previous\n // one, so a fast fix cadence glides instead of queueing.\n essential: true,\n });\n }\n\n /**\n * The pixel offset that renders the followed fix at `anchorY` of the\n * container height: `(anchorY - 0.5) * height` (0.5 is the natural\n * centre; positive y moves the puck down the screen).\n */\n private anchorOffsetY(): number {\n const height = this.m.getContainer().clientHeight;\n return (this.anchorY - 0.5) * height;\n }\n\n private scheduleRecentre(): void {\n this.clearRecentreTimer();\n if (this.autoRecentreMs === 0) return;\n this.recentreTimer = setTimeout(() => {\n this.recentreTimer = undefined;\n if (this.currentMode === \"free\") this.resume();\n }, this.autoRecentreMs);\n }\n\n private clearRecentreTimer(): void {\n if (this.recentreTimer !== undefined) {\n clearTimeout(this.recentreTimer);\n this.recentreTimer = undefined;\n }\n }\n}\n\n/** South-west / north-east bounds of a coordinate list. */\nfunction boundsOf(\n coordinates: [number, number][],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const [lng, lat] of coordinates) {\n if (lng < minLng) minLng = lng;\n if (lng > maxLng) maxLng = lng;\n if (lat < minLat) minLat = lat;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n// ---------------------------------------------------------------------------\n// camera.flythrough() - cinematic route replay + scrollytelling binder.\n// ---------------------------------------------------------------------------\n\n/** Mean Earth radius in metres (IUGG), matching places.ts. */\nconst FLYTHROUGH_EARTH_RADIUS_M = 6371008.8;\n\n/** Straight-line (haversine) distance between two `[lng, lat]`s, metres. */\nfunction flythroughDistanceM(a: [number, number], b: [number, number]): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b[1] - a[1]);\n const dLon = rad(b[0] - a[0]);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a[1])) * Math.cos(rad(b[1])) * Math.sin(dLon / 2) ** 2;\n return 2 * FLYTHROUGH_EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/**\n * Initial great-circle bearing from `a` to `b`, degrees clockwise from\n * north, normalised to `[0, 360)`.\n */\nexport function bearingBetween(\n a: [number, number],\n b: [number, number],\n): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLon = rad(b[0] - a[0]);\n const latA = rad(a[1]);\n const latB = rad(b[1]);\n const y = Math.sin(dLon) * Math.cos(latB);\n const x =\n Math.cos(latA) * Math.sin(latB) -\n Math.sin(latA) * Math.cos(latB) * Math.cos(dLon);\n const deg = (Math.atan2(y, x) * 180) / Math.PI;\n return (deg + 360) % 360;\n}\n\n/**\n * The signed shortest-arc rotation from bearing `from` to bearing `to`,\n * in `(-180, 180]` degrees - the slerp-style delta the flythrough eases\n * along so the chase cam never spins the long way round.\n */\nexport function shortestArcDelta(from: number, to: number): number {\n const delta = (((to - from) % 360) + 540) % 360 - 180;\n return delta === -180 ? 180 : delta;\n}\n\n/** A camera pose along a flythrough: where to look from, and which way. */\nexport interface FlythroughPose {\n /** Camera target on the route, `[lng, lat]`. */\n center: [number, number];\n /** Chase-cam bearing: towards a point `lookAheadM` up the road. */\n bearing: number;\n}\n\n/**\n * Precomputed arc-length sampler over a route line: maps progress\n * `t` (0-1 of total route distance) to a {@link FlythroughPose}. Pure -\n * shared by {@link flythroughPose} (tests) and the controller (per frame,\n * without recomputing cumulative distances).\n */\nclass PoseSampler {\n private readonly points: [number, number][];\n private readonly cumulative: number[];\n readonly totalM: number;\n\n constructor(coordinates: [number, number][]) {\n // Unwrap longitudes onto a continuous range first, so a route that\n // crosses the antimeridian interpolates across the real gap instead\n // of sweeping the camera around the world.\n const unwrapped = unwrapLngs(coordinates);\n // Consecutive duplicates carry no direction; drop them once here.\n this.points = unwrapped.filter(\n (p, i) =>\n i === 0 ||\n p[0] !== unwrapped[i - 1]![0] ||\n p[1] !== unwrapped[i - 1]![1],\n );\n if (this.points.length < 2) {\n throw new Error(\n \"flythrough needs a route with at least two distinct coordinates\",\n );\n }\n this.cumulative = [0];\n for (let i = 1; i < this.points.length; i++) {\n this.cumulative.push(\n this.cumulative[i - 1]! +\n flythroughDistanceM(this.points[i - 1]!, this.points[i]!),\n );\n }\n this.totalM = this.cumulative[this.cumulative.length - 1]!;\n }\n\n /** The interpolated point `distanceM` along the route (clamped). */\n pointAt(distanceM: number): [number, number] {\n const d = Math.min(this.totalM, Math.max(0, distanceM));\n // Linear scan is fine: callers advance monotonically and routes are\n // a few thousand points at most.\n let i = 1;\n while (i < this.cumulative.length - 1 && this.cumulative[i]! < d) i++;\n const before = this.cumulative[i - 1]!;\n const span = this.cumulative[i]! - before;\n const f = span > 0 ? (d - before) / span : 0;\n const a = this.points[i - 1]!;\n const b = this.points[i]!;\n return [a[0] + (b[0] - a[0]) * f, a[1] + (b[1] - a[1]) * f];\n }\n\n /** The pose at progress `t` (clamped 0-1), chasing `lookAheadM` ahead. */\n poseAt(t: number, lookAheadM: number): FlythroughPose {\n const d = Math.min(1, Math.max(0, t)) * this.totalM;\n const center = this.pointAt(d);\n let target = this.pointAt(d + Math.max(1, lookAheadM));\n if (target[0] === center[0] && target[1] === center[1]) {\n // At (or past) the end the look-ahead collapses onto the centre;\n // hold the final segment's direction instead of a degenerate\n // zero-length bearing.\n const last = this.points[this.points.length - 1]!;\n const prev = this.points[this.points.length - 2]!;\n return { center, bearing: bearingBetween(prev, last) };\n }\n return { center, bearing: bearingBetween(center, target) };\n }\n}\n\n/**\n * The camera pose at progress `t` (0-1) along a route: the interpolated\n * point that fraction of the total distance along the line, with a\n * chase-cam bearing towards the point `lookAheadM` further on. Pure -\n * exported for tests and for apps that drive the camera themselves.\n */\nexport function flythroughPose(\n coordinates: [number, number][],\n t: number,\n lookAheadM = 200,\n): FlythroughPose {\n return new PoseSampler(coordinates).poseAt(t, lookAheadM);\n}\n\nexport interface FlythroughOptions {\n /**\n * Camera tilt in degrees, clamped 0-85. Default `60` (the cinematic\n * chase look; see {@link NavigationCameraOptions.pitch} for caveats\n * above 60).\n */\n pitch?: number;\n /** Camera zoom held through the replay. Default `16`. */\n zoom?: number;\n /**\n * Total replay duration in milliseconds. Default `20000`. Ignored when\n * `speedMps` is given.\n */\n durationMs?: number;\n /**\n * Replay ground speed in metres/second along the route - the duration\n * becomes `routeLength / speedMps`. Wins over `durationMs`.\n */\n speedMps?: number;\n /**\n * How far up the road the chase cam looks to derive its bearing,\n * metres. Default `200`; larger = calmer bearing on wiggly roads.\n */\n lookAheadM?: number;\n /**\n * Bearing smoothing rate per second (the fraction of the remaining\n * shortest-arc turn closed each second). Default `3`; higher = snappier.\n */\n bearingEase?: number;\n}\n\n/** The handle a {@link flythrough} returns. */\nexport interface FlythroughController {\n /** Start (or resume) the replay. Restarts from 0 when it had finished. */\n play(): void;\n /** Freeze the replay where it is. */\n pause(): void;\n /** Pause and rewind to the start (the camera jumps to the start pose). */\n stop(): void;\n /** Scrub to progress `t` (0-1, clamped) and apply the pose immediately. */\n seek(t: number): void;\n /** Playback-rate multiplier (`1` = real duration, `2` = double). */\n speed: number;\n /** Current progress, 0-1. */\n readonly progress: number;\n /** Whether the replay is currently advancing. */\n readonly playing: boolean;\n /** Subscribe to progress updates; returns the unsubscribe function. */\n onProgress(listener: (t: number) => void): () => void;\n /** Pause and detach everything. The controller is dead afterwards. */\n destroy(): void;\n}\n\n/** One animation frame, with a cancel handle; setTimeout fallback in Node. */\nfunction scheduleFrame(cb: (timestampMs: number) => void): () => void {\n if (typeof requestAnimationFrame === \"function\") {\n const handle = requestAnimationFrame(cb);\n return () => cancelAnimationFrame(handle);\n }\n const handle = setTimeout(() => cb(Date.now()), 16);\n return () => clearTimeout(handle);\n}\n\n/**\n * Cinematic route replay: fly the camera along a route line with a\n * chase-cam bearing (eased along the shortest arc, so junctions glide\n * instead of spinning), at a configurable pitch/zoom/speed. Returns a\n * transport-style controller; nothing moves until `play()` or `seek()`.\n *\n * ```ts\n * const route = await routes.route(from, to);\n * const replay = flythrough(map, route, { pitch: 60, durationMs: 15000 });\n * replay.onProgress((t) => scrubber.value = String(t));\n * replay.play();\n * ```\n *\n * Drives the camera with `jumpTo` once per animation frame (the standard\n * MapLibre scrub pattern). Runs under any projection; on globe the ride is\n * unanchored but valid. Accepts a `ParsedRoute` (from `RouteLayer`) or a\n * bare GeoJSON LineString geometry.\n */\nexport function flythrough(\n map: MapMapMap | MlMap,\n route: RouteGeometry | ParsedRoute,\n options: FlythroughOptions = {},\n): FlythroughController {\n const m = map instanceof MapMapMap ? map.map : map;\n const geometry = \"geometry\" in route ? route.geometry : route;\n const sampler = new PoseSampler(geometry.coordinates);\n const pitch = clamp(options.pitch ?? 60, 0, 85);\n const zoom = options.zoom ?? 16;\n const lookAheadM = options.lookAheadM ?? 200;\n const bearingEase = Math.max(0, options.bearingEase ?? 3);\n const durationMs =\n options.speedMps !== undefined && options.speedMps > 0\n ? (sampler.totalM / options.speedMps) * 1000\n : Math.max(1, options.durationMs ?? 20_000);\n\n let t = 0;\n let rate = 1;\n let playing = false;\n let destroyed = false;\n let bearing: number | undefined;\n let lastFrameTs: number | undefined;\n let cancelFrame: (() => void) | undefined;\n const listeners = new Set<(t: number) => void>();\n\n const applyPose = (dtS: number): void => {\n const pose = sampler.poseAt(t, lookAheadM);\n // Ease the bearing along the shortest arc: close a time-scaled\n // fraction of the remaining turn each frame (frame-rate independent).\n bearing =\n bearing === undefined\n ? pose.bearing\n : bearing +\n shortestArcDelta(bearing, pose.bearing) *\n Math.min(1, bearingEase * dtS);\n m.jumpTo({ center: pose.center, bearing, pitch, zoom });\n for (const listener of listeners) listener(t);\n };\n\n const frame = (timestampMs: number): void => {\n if (!playing || destroyed) return;\n const dtS =\n lastFrameTs === undefined ? 0 : Math.max(0, timestampMs - lastFrameTs) / 1000;\n lastFrameTs = timestampMs;\n t = Math.min(1, t + (dtS * 1000 * rate) / durationMs);\n applyPose(dtS || 1 / 60);\n if (t >= 1) {\n playing = false;\n return;\n }\n cancelFrame = scheduleFrame(frame);\n };\n\n const pause = (): void => {\n playing = false;\n cancelFrame?.();\n cancelFrame = undefined;\n lastFrameTs = undefined;\n };\n\n return {\n play(): void {\n if (destroyed || playing) return;\n if (t >= 1) t = 0; // replay from the top once finished\n playing = true;\n lastFrameTs = undefined;\n cancelFrame = scheduleFrame(frame);\n },\n pause,\n stop(): void {\n if (destroyed) return;\n pause();\n t = 0;\n bearing = undefined; // next pose snaps rather than unwinding the arc\n applyPose(1 / 60);\n },\n seek(to: number): void {\n if (destroyed) return;\n t = Math.min(1, Math.max(0, to));\n bearing = undefined; // a scrub snaps on-heading rather than easing there\n applyPose(1 / 60);\n },\n get speed(): number {\n return rate;\n },\n set speed(value: number) {\n if (Number.isFinite(value) && value > 0) rate = value;\n },\n get progress(): number {\n return t;\n },\n get playing(): boolean {\n return playing;\n },\n onProgress(listener: (progress: number) => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n destroy(): void {\n destroyed = true;\n pause();\n listeners.clear();\n },\n };\n}\n\n/** Anything scrollable the binder accepts: an element or the window. */\ntype ScrollTarget = Pick<\n HTMLElement,\n \"addEventListener\" | \"removeEventListener\"\n> &\n Partial<\n Pick<HTMLElement, \"scrollTop\" | \"scrollHeight\" | \"clientHeight\"> &\n Pick<Window, \"scrollY\" | \"innerHeight\" | \"document\">\n >;\n\n/**\n * Scrollytelling: bind a flythrough to a scroll position, so scrolling a\n * story column scrubs the camera along the route. The binder pauses the\n * controller (scroll owns the timeline) and seeks it to the scrolled\n * fraction - immediately on bind, then on every scroll. Returns the\n * unbind function.\n *\n * ```ts\n * const replay = flythrough(map, route);\n * const unbind = bindFlythroughToScroll(replay, document.querySelector(\"#story\")!);\n * ```\n */\nexport function bindFlythroughToScroll(\n controller: FlythroughController,\n target: HTMLElement | Window = window,\n): () => void {\n const t = target as ScrollTarget;\n const fraction = (): number => {\n if (typeof t.scrollTop === \"number\") {\n // An element: how far through its own scrollable height.\n const max = (t.scrollHeight ?? 0) - (t.clientHeight ?? 0);\n return max > 0 ? t.scrollTop / max : 0;\n }\n // The window: how far through the document.\n const doc = t.document?.documentElement;\n const max = (doc?.scrollHeight ?? 0) - (t.innerHeight ?? 0);\n return max > 0 ? (t.scrollY ?? 0) / max : 0;\n };\n const onScroll = (): void => {\n controller.pause();\n controller.seek(Math.min(1, Math.max(0, fraction())));\n };\n t.addEventListener(\"scroll\", onScroll, { passive: true });\n onScroll();\n return () => t.removeEventListener(\"scroll\", onScroll);\n}\n\n/**\n * Whether a `getProjection()` result names the globe. MapLibre v5 returns\n * `{ type }` where `type` is `\"globe\"`, `\"mercator\"`,\n * `\"vertical-perspective\"` or a style expression that can evaluate to any\n * of them; any mention of globe/vertical-perspective counts as globe.\n */\nfunction usesGlobe(projection: unknown): boolean {\n if (projection === null || projection === undefined) return false;\n if (typeof projection === \"string\") {\n return projection === \"globe\" || projection === \"vertical-perspective\";\n }\n if (Array.isArray(projection)) return projection.some(usesGlobe);\n if (typeof projection === \"object\") {\n return Object.values(projection).some(usesGlobe);\n }\n return false;\n}\n","/**\n * IsochroneLayer - walkability rings (reachability contours) on a MapMap\n * map, backed by the gateway's live `POST /isochrone` endpoint (Valhalla\n * isochrone; see docs/API.md).\n *\n * One call - `showReachability({ origin, mode: \"walk\", minutes: [5, 10, 15] })` -\n * renders concentric reachability rings: graduated-opacity fills (nearest\n * ring strongest), contour outlines, and \"N min\" labels along each\n * contour. The estate-agent / store-catchment / \"how walkable is this\n * flat?\" view in one line.\n *\n * Follows the RouteLayer pattern: gateway base URL/key picked up from a\n * `MapMapMap` automatically, layers survive `setStyle` theme swaps via\n * re-installation on `style.load`, and `clear()`/`destroy()` tidy up.\n */\nimport type {\n DataDrivenPropertyValueSpecification,\n FillLayerSpecification,\n GeoJSONSource,\n LineLayerSpecification,\n Map as MlMap,\n SymbolLayerSpecification,\n} from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { SIGNAL_BLUE } from \"./route.js\";\nimport { toLngLat } from \"./coords.js\";\nimport type { LngLatLike } from \"./types.js\";\n\n/**\n * Travel mode for the rings. The friendly names map onto gateway costings\n * (`walk` → `pedestrian`, `cycle` → `bicycle`, `drive` → `auto`); any\n * other string is passed through as a raw Valhalla costing (e.g.\n * `\"truck\"`, `\"motor_scooter\"`).\n */\nexport type ReachabilityMode =\n | \"walk\"\n | \"cycle\"\n | \"drive\"\n | \"truck\"\n | (string & {});\n\nconst MODE_TO_COSTING: Record<string, string> = {\n walk: \"pedestrian\",\n cycle: \"bicycle\",\n drive: \"auto\",\n};\n\nexport interface ShowReachabilityOptions {\n /** Where the rings radiate from. */\n origin: LngLatLike;\n /** Travel mode. Defaults to `\"walk\"` - these are walkability rings. */\n mode?: ReachabilityMode;\n /** Ring contours in minutes, e.g. `[5, 10, 15]`. At least one. */\n minutes: number[];\n /** Ring colour. Defaults to MapMap signal blue. */\n color?: string;\n /**\n * Valhalla-style costing options forwarded verbatim, e.g.\n * `{ pedestrian: { use_lit: 1.0 } }`.\n */\n costingOptions?: Record<string, unknown>;\n}\n\nexport interface IsochroneLayerOptions {\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-isochrone\"`. */\n id?: string;\n}\n\n/** The GeoJSON FeatureCollection the gateway returns, passed through. */\nexport interface IsochroneFeatureCollection {\n type: \"FeatureCollection\";\n features: {\n type: \"Feature\";\n geometry: { type: string; coordinates: unknown };\n properties?: Record<string, unknown> | null;\n }[];\n}\n\n/** Renders reachability rings from the gateway's `POST /isochrone`. */\nexport class IsochroneLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly fillLayerId: string;\n private readonly lineLayerId: string;\n private readonly labelLayerId: string;\n private lastData: IsochroneFeatureCollection | undefined;\n private lastMinutes: number[] = [];\n private lastColor: string = SIGNAL_BLUE;\n\n constructor(map: MapMapMap | MlMap, options: IsochroneLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n } else {\n this.map = map;\n if (!options.baseUrl) {\n throw new Error(\n \"IsochroneLayer needs a baseUrl when given a raw MapLibre map\",\n );\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n const id = options.id ?? \"mapmap-isochrone\";\n this.sourceId = `${id}-src`;\n this.fillLayerId = `${id}-fill`;\n this.lineLayerId = `${id}-line`;\n this.labelLayerId = `${id}-label`;\n // RouteLayer lifecycle: runtime sources/layers are wiped on every\n // setStyle (theme swap), so re-install on each style.load - which also\n // completes a show() that arrived before the style finished loading.\n this.map.on(\"style.load\", this.handleStyleLoad);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.lastData) this.install(this.lastData);\n };\n\n /**\n * Fetch and render reachability rings. Returns the GeoJSON\n * FeatureCollection the gateway produced (each feature carries a\n * `contour` property in minutes), for callers who also want the raw\n * shapes. Replaces any rings already shown by this layer.\n */\n async showReachability(\n options: ShowReachabilityOptions,\n ): Promise<IsochroneFeatureCollection> {\n if (options.minutes.length === 0) {\n throw new Error(\n \"showReachability needs at least one contour in minutes, e.g. { minutes: [5, 10, 15] }\",\n );\n }\n const [lon, lat] = toLngLat(options.origin);\n const mode = options.mode ?? \"walk\";\n const body: Record<string, unknown> = {\n locations: [{ lat, lon }],\n costing: MODE_TO_COSTING[mode] ?? mode,\n // Largest first so smaller (nearer) rings paint on top.\n contours: [...options.minutes]\n .sort((a, b) => b - a)\n .map((time) => ({ time })),\n polygons: true,\n };\n if (options.costingOptions) body[\"costing_options\"] = options.costingOptions;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(`${this.baseUrl}/isochrone`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n const payload: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `isochrone request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n if (\n typeof payload !== \"object\" ||\n payload === null ||\n (payload as Record<string, unknown>)[\"type\"] !== \"FeatureCollection\"\n ) {\n throw new Error(\"isochrone returned no FeatureCollection\");\n }\n const collection = payload as IsochroneFeatureCollection;\n this.lastMinutes = [...options.minutes].sort((a, b) => a - b);\n this.lastColor = options.color ?? SIGNAL_BLUE;\n this.draw(collection);\n return collection;\n }\n\n /** The most recently drawn rings, if any. */\n get current(): IsochroneFeatureCollection | undefined {\n return this.lastData;\n }\n\n /** Draw (or update) a ring collection. Safe before the style has loaded. */\n private draw(collection: IsochroneFeatureCollection): void {\n this.lastData = collection;\n if (!this.map.isStyleLoaded()) return; // installed by handleStyleLoad\n this.install(collection);\n }\n\n /** Add-or-update the source and ring layers on the current style. */\n private install(collection: IsochroneFeatureCollection): void {\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(collection as never);\n } else {\n this.map.addSource(this.sourceId, {\n type: \"geojson\",\n data: collection as never,\n });\n }\n if (this.map.getLayer(this.fillLayerId)) {\n // Re-shown with a different colour/contours: refresh the paints.\n this.map.setPaintProperty(\n this.fillLayerId,\n \"fill-color\",\n this.lastColor,\n );\n this.map.setPaintProperty(\n this.fillLayerId,\n \"fill-opacity\",\n this.fillOpacity(),\n );\n this.map.setPaintProperty(this.lineLayerId, \"line-color\", this.lastColor);\n this.map.setPaintProperty(this.labelLayerId, \"text-color\", this.lastColor);\n return;\n }\n\n // Valhalla polygons are full disks (not donuts), so translucent fills\n // naturally stack: near the origin every ring overlaps and the tint\n // reads strongest, fading towards the outermost contour. The graduated\n // per-ring opacity reinforces that.\n const fill: FillLayerSpecification = {\n id: this.fillLayerId,\n type: \"fill\",\n source: this.sourceId,\n paint: {\n \"fill-color\": this.lastColor,\n \"fill-opacity\": this.fillOpacity(),\n },\n };\n const line: LineLayerSpecification = {\n id: this.lineLayerId,\n type: \"line\",\n source: this.sourceId,\n paint: {\n \"line-color\": this.lastColor,\n \"line-width\": 1.5,\n \"line-opacity\": 0.8,\n },\n };\n const label: SymbolLayerSpecification = {\n id: this.labelLayerId,\n type: \"symbol\",\n source: this.sourceId,\n layout: {\n \"symbol-placement\": \"line\",\n \"text-field\": [\n \"concat\",\n [\"to-string\", [\"get\", \"contour\"]],\n \" min\",\n ],\n // Ships with the MapMap default styles (see places.ts).\n \"text-font\": [\"Noto Sans Regular\"],\n \"text-size\": 11,\n },\n paint: {\n \"text-color\": this.lastColor,\n \"text-halo-color\": \"#ffffff\",\n \"text-halo-width\": 1.2,\n },\n };\n this.map.addLayer(fill);\n this.map.addLayer(line);\n this.map.addLayer(label);\n }\n\n /**\n * Graduated fill opacity: the nearest contour (fewest minutes) is the\n * most opaque, the farthest the faintest, interpolated on each\n * feature's `contour` property. With one contour it is a constant.\n */\n private fillOpacity(): DataDrivenPropertyValueSpecification<number> {\n const min = this.lastMinutes[0] ?? 0;\n const max = this.lastMinutes[this.lastMinutes.length - 1] ?? 0;\n if (this.lastMinutes.length < 2 || min === max) return 0.18;\n return [\n \"interpolate\",\n [\"linear\"],\n [\"get\", \"contour\"],\n min,\n 0.28,\n max,\n 0.08,\n ] as unknown as DataDrivenPropertyValueSpecification<number>;\n }\n\n /** Remove the rings' layers and source from the map. */\n clear(): void {\n for (const layerId of [\n this.labelLayerId,\n this.lineLayerId,\n this.fillLayerId,\n ]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n this.lastData = undefined;\n }\n\n /** Remove the rings and detach the layer's `style.load` listener. */\n destroy(): void {\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.clear();\n }\n}\n","/**\n * AdrCheck - optional helper for the gateway's `POST /adr/check` endpoint.\n *\n * The ADR 8.6.4 tunnel compliance engine, exposed directly. No MapLibre\n * dependency; just a typed fetch wrapper.\n */\nimport type { AdrCheckRequest, AdrCheckResult } from \"./types.js\";\n\n/**\n * Builds the exact wire body the gateway deserialises\n * (`sn-gateway` `routes/adr.rs` → `sn_adr::AdrVehicleProfile`):\n * `{\"adr\": {\"dimensions\": {…}, \"tunnel_code\"?, \"hazmat\"}, \"tunnel_category\"}`.\n * Unset dimensions default to the EU 96/53/EC artic maximums, mirroring\n * `TruckDimensions::default()`. Exported for contract tests.\n */\nexport function buildAdrCheckBody(request: AdrCheckRequest): Record<string, unknown> {\n const dims = request.dimensions ?? {};\n const adr: Record<string, unknown> = {\n dimensions: {\n height_m: dims.heightM ?? 4.0,\n width_m: dims.widthM ?? 2.55,\n length_m: dims.lengthM ?? 16.5,\n gross_weight_t: dims.grossWeightT ?? 40.0,\n axle_load_t: dims.axleLoadT ?? null,\n axle_count: dims.axleCount ?? null,\n },\n hazmat: request.hazmat,\n };\n // Omitted entirely when unknown: the gateway reads a missing tunnel_code\n // as \"dangerous goods of unknown code\" (conservative code-B fallback).\n if (request.tunnelCode !== undefined) adr[\"tunnel_code\"] = request.tunnelCode;\n return { adr, tunnel_category: request.tunnelCategory };\n}\n\nexport interface AdrCheckOptions {\n /** Gateway base URL, e.g. `https://api.mapmap.ai`. */\n baseUrl: string;\n /** Gateway API key (`snk_…`). */\n apiKey?: string;\n}\n\n/** Calls `POST /adr/check` and returns the parsed compliance decision. */\nexport class AdrCheck {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n\n constructor(options: AdrCheckOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n async check(request: AdrCheckRequest): Promise<AdrCheckResult> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(`${this.baseUrl}/adr/check`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(buildAdrCheckBody(request)),\n });\n\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `ADR check failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"ADR check returned a non-object response\");\n }\n const obj = body as Record<string, unknown>;\n const result: AdrCheckResult = {\n status: typeof obj[\"status\"] === \"string\" ? obj[\"status\"] : \"unknown\",\n raw: obj,\n };\n if (typeof obj[\"reason\"] === \"string\") result.reason = obj[\"reason\"];\n return result;\n }\n}\n","/**\n * Turn-by-turn guidance helpers: voice + banner instructions and lanes.\n *\n * The gateway's OSRM endpoint returns Mapbox-shaped `voiceInstructions`\n * (plain + SSML announcements with distance triggers) and\n * `bannerInstructions` (primary line with a maneuver glyph, lane\n * sub-banners) on each step when requested with\n * `voice: true` / `banner: true` route options. This module extracts them\n * from a parsed route, renders a banner as a DOM element, and speaks\n * announcements through the browser's `SpeechSynthesis`.\n *\n * Everything except {@link GuidanceBanner} and {@link speak} is pure and\n * covered by unit tests.\n */\n\nimport {\n NAV_CAMERA_KINDS,\n navAlertLeadDistanceM,\n navAlertSoundUrl,\n navCameraKind,\n type NavAlertsDesign,\n type NavAlertAudioMode,\n type NavBannerDesign,\n type NavCameraKind,\n} from \"./nav-design.js\";\nimport { directionIcons, iconNameForStep } from \"./direction-icons.js\";\nimport type { ParsedRoute } from \"./types.js\";\n\n/** A spoken instruction with its trigger distance before the maneuver. */\nexport interface VoiceInstruction {\n /** Metres before the end of the step at which to announce. */\n distanceAlongGeometry: number;\n /** Plain text for speech synthesis. */\n announcement: string;\n /** SSML form, preferred by engines that support it. */\n ssmlAnnouncement?: string;\n}\n\n/** One lane entry of a banner lane diagram. */\nexport interface LaneIndication {\n /** Turn directions this lane allows (OSRM indication strings). */\n directions: string[];\n /**\n * Whether the lane can be used for the maneuver. `undefined` means\n * unknown, not unusable — banner components omit the flag for\n * non-recommended lanes (see {@link bannerLanes}).\n */\n valid?: boolean;\n /** Whether guidance recommends this lane. */\n active?: boolean;\n}\n\n/** A typed fragment of banner content. */\nexport interface BannerComponent {\n type: string;\n text: string;\n directions?: string[];\n active?: boolean;\n}\n\n/** One banner line. */\nexport interface BannerContent {\n text: string;\n type?: string;\n modifier?: string;\n components?: BannerComponent[];\n}\n\n/** The visual banner shown while travelling a step. */\nexport interface BannerInstruction {\n distanceAlongGeometry: number;\n primary: BannerContent;\n secondary?: BannerContent;\n sub?: BannerContent;\n}\n\n/** Guidance data for one step of the route. */\nexport interface StepGuidance {\n /** Step index within the flattened route. */\n stepIndex: number;\n /** Step length in metres. */\n distanceM: number;\n /**\n * Written instruction for the step's upcoming maneuver. Taken from\n * `maneuver.instruction` when a server emits it (Mapbox-style); the\n * MapMap gateway does not, so it falls back to the step's final voice\n * announcement (the pre-transition instruction) and then to the banner\n * primary text. Undefined only when the step carries no guidance at all.\n */\n instruction?: string;\n /** Spoken announcements, ordered by descending trigger distance. */\n voice: VoiceInstruction[];\n /** Visual banners for the upcoming maneuver. */\n banners: BannerInstruction[];\n /**\n * OSRM travel mode of the step (`driving`, `ferry`, …) where the server\n * emits it. Pass the guidance entry as {@link GuidanceBanner.update}'s\n * second argument so ferry legs render the ferry icon.\n */\n mode?: string;\n /**\n * `left`/`right` where the server emits it (the MapMap gateway sets it on\n * u-turn steps), so u-turn icons point the correct way in left-hand-traffic\n * regions.\n */\n drivingSide?: string;\n}\n\n/**\n * Extracts per-step guidance from a parsed route (requires the route to\n * have been requested with `steps: true` and voice/banner enabled).\n * Steps without instructions yield empty arrays, never holes.\n */\nexport function extractGuidance(route: ParsedRoute): StepGuidance[] {\n const legs = (route.raw[\"legs\"] as Record<string, unknown>[] | undefined) ?? [];\n const out: StepGuidance[] = [];\n let index = 0;\n for (const leg of legs) {\n const steps = (leg[\"steps\"] as Record<string, unknown>[] | undefined) ?? [];\n for (const step of steps) {\n const voice = (step[\"voiceInstructions\"] as VoiceInstruction[] | undefined) ?? [];\n const banners = (step[\"bannerInstructions\"] as BannerInstruction[] | undefined) ?? [];\n const guidance: StepGuidance = {\n stepIndex: index,\n distanceM: Number(step[\"distance\"] ?? 0),\n instruction: stepInstruction(step, voice, banners),\n voice,\n banners,\n };\n if (typeof step[\"mode\"] === \"string\") guidance.mode = step[\"mode\"];\n if (typeof step[\"driving_side\"] === \"string\") {\n guidance.drivingSide = step[\"driving_side\"];\n }\n out.push(guidance);\n index += 1;\n }\n }\n return out;\n}\n\n/**\n * The written instruction for a step. The gateway's OSRM translation\n * (`sn-valhalla` `osrm.rs`) emits no `maneuver.instruction`; the written\n * text lives in the voice announcements (the last one is the pre-transition\n * instruction, e.g. \"Turn right onto High Street\") and in the banner\n * primary text. Prefer `maneuver.instruction` when a server does emit it.\n */\nfunction stepInstruction(\n step: Record<string, unknown>,\n voice: VoiceInstruction[],\n banners: BannerInstruction[],\n): string | undefined {\n const maneuver = step[\"maneuver\"] as Record<string, unknown> | undefined;\n const fromManeuver = maneuver?.[\"instruction\"];\n if (typeof fromManeuver === \"string\" && fromManeuver.length > 0) {\n return fromManeuver;\n }\n const lastVoice = voice[voice.length - 1];\n if (\n typeof lastVoice?.announcement === \"string\" &&\n lastVoice.announcement.length > 0\n ) {\n return lastVoice.announcement;\n }\n const bannerText = banners[0]?.primary?.text;\n if (typeof bannerText === \"string\" && bannerText.length > 0) {\n return bannerText;\n }\n return undefined;\n}\n\n/** Named XML entities the gateway's `xml_escape` (and standard SSML) emit. */\nconst XML_ENTITIES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \""\": '\"',\n \"'\": \"'\",\n};\n\n/**\n * Strips SSML tags down to speakable plain text. Entities are decoded in a\n * single pass (never re-scanning already-decoded output), so text whose\n * literal content looks like an entity — e.g. `&lt;`, the gateway's\n * escape of a literal `<` — round-trips correctly. Decodes the five\n * named XML entities plus decimal numeric references (`'`).\n */\nexport function ssmlToText(ssml: string): string {\n return ssml\n .replace(/<[^>]+>/g, \"\")\n .replace(/&(?:amp|lt|gt|quot|apos);|&#(\\d+);/g, (entity, decimal: string | undefined) =>\n decimal !== undefined\n ? String.fromCodePoint(Number(decimal))\n : (XML_ENTITIES[entity] ?? entity),\n )\n .trim();\n}\n\n/**\n * Lane entries of a banner's sub line, if it carries a lane diagram.\n *\n * Banner lane components only carry `active` (the recommended lane) — the\n * gateway drops the per-lane `valid` flag from banners, keeping it in the\n * raw route's `intersections[].lanes`. An active lane is by definition\n * usable, so `valid` is `true` for active lanes and *unknown* (undefined,\n * never `false`) for the rest: a non-recommended lane may still be legal.\n * Read `route.raw` `legs[].steps[].intersections[].lanes` for the full\n * `valid` set.\n */\nexport function bannerLanes(banner: BannerInstruction): LaneIndication[] {\n const components = banner.sub?.components ?? [];\n return components\n .filter((c) => c.type === \"lane\")\n .map((c) => {\n const lane: LaneIndication = { directions: c.directions ?? [] };\n if (c.active !== undefined) lane.active = c.active;\n if (c.active === true) lane.valid = true;\n return lane;\n });\n}\n\n/**\n * Unicode arrow for a lane/maneuver direction (OSRM indication strings).\n * A text-only fallback; sprite-based lane icons ship with the map assets.\n */\nexport function directionArrow(direction: string): string {\n switch (direction) {\n case \"left\":\n return \"←\";\n case \"right\":\n return \"→\";\n case \"straight\":\n case \"none\":\n return \"↑\";\n case \"slight left\":\n return \"↖\";\n case \"slight right\":\n return \"↗\";\n case \"sharp left\":\n return \"↙\";\n case \"sharp right\":\n return \"↘\";\n case \"uturn\":\n return \"↶\";\n case \"merge to left\":\n return \"⬅\";\n case \"merge to right\":\n return \"➡\";\n default:\n return \"•\";\n }\n}\n\n/** Options for {@link speak}. */\nexport interface SpeakOptions {\n /** BCP 47 language for the utterance, e.g. `en-GB`. */\n lang?: string;\n /** Speech rate (0.1–10, default 1). */\n rate?: number;\n}\n\n/**\n * Speaks a voice instruction through the browser's `SpeechSynthesis`.\n * Prefers the SSML body's text (browsers do not accept raw SSML). Returns\n * false when speech synthesis is unavailable (e.g. non-browser contexts).\n * De-duplication is the caller's responsibility: speak each instruction\n * once as its trigger distance is crossed.\n */\nexport function speak(instruction: VoiceInstruction, options: SpeakOptions = {}): boolean {\n const synth = (globalThis as { speechSynthesis?: SpeechSynthesis }).speechSynthesis;\n const Utterance = (\n globalThis as {\n SpeechSynthesisUtterance?: typeof SpeechSynthesisUtterance;\n }\n ).SpeechSynthesisUtterance;\n if (!synth || !Utterance) return false;\n const text = instruction.ssmlAnnouncement\n ? ssmlToText(instruction.ssmlAnnouncement)\n : instruction.announcement;\n const utterance = new Utterance(text);\n if (options.lang) utterance.lang = options.lang;\n if (options.rate) utterance.rate = options.rate;\n synth.speak(utterance);\n return true;\n}\n\n/**\n * A minimal DOM banner: primary text with a maneuver icon from the platform\n * direction set (the same `direction-icons` glyphs the MapMap apps use —\n * ferry, roundabouts, forks, ramps and all), plus an optional lane row.\n * Style with the `mapmap-banner` / `mapmap-banner-lanes` /\n * `mapmap-banner-icon` classes, pass a Studio design (`extra.nav` `banner`\n * block, e.g. `map.navDesign?.banner`) to match a Studio theme, or read\n * {@link StepGuidance} yourself for fully custom UI. The icon's secondary\n * shapes retheme via the `--mm-icon-secondary` CSS custom property.\n */\nexport class GuidanceBanner {\n /** The banner root element; attach it wherever your UI needs it. */\n readonly element: HTMLElement;\n private readonly design: NavBannerDesign | undefined;\n\n constructor(container?: HTMLElement, design?: NavBannerDesign) {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"GuidanceBanner requires a DOM environment\");\n this.design = design;\n this.element = doc.createElement(\"div\");\n this.element.className = \"mapmap-banner\";\n // With a design, the derived metrics follow the Studio preview exactly\n // (gap = padding × 1.2, horizontal padding = padding × 1.4, arrow at\n // fontSize × 1.4, height set = min-height with contents vertically\n // centred, unset = auto). Without one the built-in look is unchanged.\n this.element.style.cssText = design\n ? \"display:none;align-items:center;box-sizing:border-box;\" +\n `gap:${Math.round((design.padding ?? 10) * 1.2)}px;` +\n `padding:${design.padding ?? 10}px ${Math.round((design.padding ?? 10) * 1.4)}px;` +\n `background:${design.background};color:${design.textColor};` +\n `border-radius:${design.cornerRadius ?? 10}px;` +\n `max-width:${design.maxWidth ?? 340}px;` +\n (design.height !== undefined ? `min-height:${design.height}px;` : \"\") +\n `font:600 ${design.fontSize}px/1.3 system-ui,sans-serif`\n : \"display:none;gap:12px;align-items:center;padding:10px 14px;\" +\n \"background:#101418;color:#fff;border-radius:10px;\" +\n \"font:600 16px/1.3 system-ui,sans-serif\";\n container?.appendChild(this.element);\n }\n\n /**\n * Renders a banner instruction (or hides the element with `null`).\n *\n * `step` is optional icon context — pass the step's {@link StepGuidance}\n * (or any `{ mode, drivingSide }`) so ferry legs render the ferry glyph\n * and u-turns point the correct way in left-hand-traffic regions.\n */\n update(\n banner: BannerInstruction | null,\n step?: Pick<StepGuidance, \"mode\" | \"drivingSide\">,\n ): void {\n if (!banner) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n const doc = this.element.ownerDocument;\n this.element.style.display = \"flex\";\n\n // Manoeuvre glyph from the platform direction set. Safe innerHTML: the\n // markup is generated build-time constants keyed by a typed name —\n // never request or user input.\n const iconSize = this.design ? Math.round(this.design.fontSize * 1.4) : 22;\n const icon = doc.createElement(\"span\");\n icon.className = \"mapmap-banner-icon\";\n icon.setAttribute(\"aria-hidden\", \"true\");\n icon.style.cssText = `flex:none;display:inline-flex;width:${iconSize}px;height:${iconSize}px`;\n icon.innerHTML =\n directionIcons[\n iconNameForStep({\n maneuver: { type: banner.primary.type, modifier: banner.primary.modifier },\n mode: step?.mode,\n driving_side: step?.drivingSide,\n })\n ];\n // The generated SVGs carry fixed 20px width/height attributes; scale\n // them to the span so the design's font size drives the glyph size.\n const svg = icon.firstElementChild;\n if (svg) {\n svg.setAttribute(\"width\", \"100%\");\n svg.setAttribute(\"height\", \"100%\");\n }\n\n const text = doc.createElement(\"span\");\n text.textContent = banner.primary.text;\n\n const children: HTMLElement[] = [icon, text];\n\n const lanes = this.design?.showLanes === false ? [] : bannerLanes(banner);\n if (lanes.length > 0) {\n const laneRow = doc.createElement(\"span\");\n laneRow.className = \"mapmap-banner-lanes\";\n if (this.design) {\n // Studio preview semantics: letter-spacing scales with the padding\n // token, and each lane dims unless guidance recommends it.\n const spacing = Math.max(2, Math.round((this.design.padding ?? 10) * 0.4));\n laneRow.style.cssText = `margin-left:auto;letter-spacing:${spacing}px;white-space:nowrap`;\n for (const lane of lanes) {\n const glyph = doc.createElement(\"span\");\n glyph.textContent = directionArrow(lane.directions[0] ?? \"none\");\n glyph.style.opacity = lane.active ? \"0.95\" : \"0.35\";\n laneRow.appendChild(glyph);\n }\n } else {\n laneRow.style.cssText = \"margin-left:auto;letter-spacing:4px\";\n laneRow.textContent = lanes\n .map((lane) => directionArrow(lane.directions[0] ?? \"none\"))\n .join(\"\");\n laneRow.style.opacity = \"0.9\";\n }\n children.push(laneRow);\n }\n\n this.element.replaceChildren(...children);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Safety-camera alerts\n// ---------------------------------------------------------------------------\n\n/**\n * One camera alert to present. `kind` is normalised through\n * {@link navCameraKind}, so a raw gateway value (`\"redlight\"`) is accepted.\n *\n * JURISDICTION: whether a camera reaches you at all is decided server-side\n * before the response leaves the gateway. Nothing in this module can widen\n * that; it styles what the policy already permitted.\n */\nexport interface CameraAlert {\n /** Camera regime; wire values are normalised. */\n kind: NavCameraKind | string;\n /** Enforced limit in km/h, when known. */\n limitKph?: number;\n /** Metres to the camera, when known. */\n distanceM?: number;\n}\n\n/**\n * What a host should actually do with an alert, given the design and\n * whether the driver is currently over the limit.\n *\n * The rule this encodes, and the reason it is a pure function rather than\n * scattered branches in a renderer: the VISUAL alert is unconditional and\n * calm, and AUDIO is the escalation channel. A driver within the limit\n * still sees the chip; only the sound waits for speeding.\n */\nexport interface AlertPresentation {\n /** Whether to show the chip at all. */\n visible: boolean;\n /** Whether the chip should render in its escalated state. */\n escalated: boolean;\n /** Whether audio should fire now. */\n audible: boolean;\n /** Which audio channel to use when `audible`. */\n audioMode: NavAlertAudioMode;\n /**\n * The earcon to play for THIS state: the design's calm sound, or its\n * escalated variant when `escalated`. Always set (even when `audible` is\n * false) so a host can pre-load it; play it only when `audible`.\n */\n soundUrl: string;\n /** Metres of lead this design guarantees before the camera. */\n leadDistanceM: number;\n}\n\n/**\n * Resolves a design plus live state into what to present.\n *\n * Escalation is by INTENSITY, not identity: `escalated` restyles the same\n * chip and re-uses the same earcon motif more insistently. It never swaps\n * in a different icon or a different sound - kind is carried by the icon\n * and by speech, urgency by timbre, and mixing the two channels is how\n * drivers end up unable to tell \"a camera\" from \"you are speeding\".\n */\nexport function alertPresentation(\n design: NavAlertsDesign,\n alert: CameraAlert,\n state: { speeding?: boolean } = {},\n): AlertPresentation {\n const kind = navCameraKind(alert.kind);\n const rules = design.kinds[kind];\n const speeding = state.speeding === true;\n const audible =\n rules.audioMode !== \"off\" &&\n rules.alertWhileDriving &&\n (rules.alertMode === \"always\" || (rules.alertMode === \"whenSpeeding\" && speeding));\n return {\n visible: rules.alertWhileDriving,\n escalated: speeding,\n audible,\n audioMode: rules.audioMode,\n soundUrl: alertSoundUrl(design, speeding),\n leadDistanceM: navAlertLeadDistanceM(design.leadDistance),\n };\n}\n\n/**\n * The earcon URL for a design in the calm or escalated state.\n *\n * A design-level `alertSoundUrl` / `escalatedSoundUrl` override wins;\n * otherwise the chosen built-in resolves against the hosted earcon\n * library. There is deliberately no per-kind sound: kind travels in the\n * icon and in speech, urgency travels in timbre.\n */\nexport function alertSoundUrl(design: NavAlertsDesign, escalated: boolean): string {\n const override = escalated ? design.escalatedSoundUrl : design.alertSoundUrl;\n if (override !== undefined) return override;\n return navAlertSoundUrl(escalated ? design.escalatedSound : design.alertSound);\n}\n\n/** Whether the map is being browsed or actively navigated. */\nexport type MapDisplayMode = \"browse\" | \"navigating\";\n\n/**\n * Whether a kind's pin should be drawn on the map in the given mode.\n *\n * Browsing and navigating are separate switches because they are separate\n * decisions - the market warns with or without a planned route, so a\n * design that shows a camera on the planning map is not thereby committed\n * to a cluttered driving map, nor the reverse.\n */\nexport function cameraShownOnMap(\n design: NavAlertsDesign,\n kind: NavCameraKind | string,\n mode: MapDisplayMode = \"browse\",\n): boolean {\n const rules = design.kinds[navCameraKind(kind)];\n return mode === \"navigating\" ? rules.showOnMapWhileNavigating : rules.showOnMap;\n}\n\n/**\n * The camera kinds a style should draw in the given mode, in the canonical\n * kind order. Feed it straight into a MapLibre `filter` (see\n * {@link cameraSymbolLayer}); an empty array means \"draw nothing\", which\n * a caller must honour by removing or hiding the layer.\n */\nexport function cameraKindsShownOnMap(\n design: NavAlertsDesign,\n mode: MapDisplayMode = \"browse\",\n): NavCameraKind[] {\n return NAV_CAMERA_KINDS.filter((kind) => cameraShownOnMap(design, kind, mode));\n}\n\n/**\n * A MapLibre symbol layer that draws camera POIs from the sprite sheet.\n *\n * Additive by design: the style compiler is untouched and ships no camera\n * layer of its own, because cameras arrive as host data (the gateway's\n * `POST /v1/cameras/along`, projected into a GeoJSON source) rather than\n * in the vector tiles. Point this at that source and the sprite icons\n * built from `map-assets/icons/cameras` render at the design's size, zoom\n * floor and per-mode visibility.\n *\n * The features must carry a `kind` property holding one of\n * {@link NAV_CAMERA_KINDS} (or the gateway's `redlight` spelling); an\n * unrecognised value falls back to the `unknown` icon, never to a guess at\n * a specific camera type.\n *\n * @param source GeoJSON source id holding the camera features.\n * @param variant Sprite variant to draw: `\"light\"` icons read on a dark\n * basemap, `\"dark\"` icons on a light one.\n */\nexport function cameraSymbolLayer(\n design: NavAlertsDesign,\n source: string,\n mode: MapDisplayMode = \"browse\",\n variant: \"light\" | \"dark\" = \"dark\",\n id = \"safety-cameras\",\n): Record<string, unknown> {\n const kinds = cameraKindsShownOnMap(design, mode);\n const iconImage: unknown[] = [\"match\", [\"get\", \"kind\"]];\n for (const kind of NAV_CAMERA_KINDS) {\n if (kind === \"unknown\") continue;\n // `red_light` is the design's spelling, `redlight` the gateway's wire\n // spelling — both must land on the same sprite.\n const values = kind === \"red_light\" ? [\"red_light\", \"redlight\"] : [kind];\n iconImage.push(values.length === 1 ? values[0] : values, cameraSpriteName(kind, variant));\n }\n iconImage.push(cameraSpriteName(\"unknown\", variant));\n return {\n id,\n type: \"symbol\",\n source,\n minzoom: design.mapMinZoom,\n filter: [\"in\", [\"get\", \"kind\"], [\"literal\", kinds as string[]]],\n layout: {\n \"icon-image\": iconImage,\n \"icon-size\": design.mapIconSize,\n \"icon-allow-overlap\": true,\n \"icon-ignore-placement\": false,\n },\n };\n}\n\n/**\n * Sprite image id for a camera kind, as built into the published sprite\n * sheet by `map-assets/icons/cameras/generate.mjs`.\n *\n * LOCKSTEP: the file names in `map-assets/sprites/svg/camera-*.svg` are\n * exactly these ids — spreet names each image after its file.\n */\nexport function cameraSpriteName(\n kind: NavCameraKind | string,\n variant: \"light\" | \"dark\" = \"dark\",\n): string {\n const normalised = navCameraKind(kind);\n const slug = normalised === \"red_light\" ? \"redlight\" : normalised.replace(/_/g, \"-\");\n return `camera-${slug}-${variant}`;\n}\n\n/**\n * Human-readable name for a camera kind, used in the chip's text and in\n * the spoken announcement. Kind lives here and in the icon, never in the\n * earcon.\n */\nexport function cameraKindLabel(kind: NavCameraKind | string): string {\n switch (navCameraKind(kind)) {\n case \"fixed\":\n return \"Speed camera\";\n case \"average\":\n return \"Average speed check\";\n case \"red_light\":\n return \"Red light camera\";\n case \"mobile_site\":\n return \"Mobile camera site\";\n default:\n return \"Safety camera\";\n }\n}\n\n/**\n * Single-colour SVG glyphs per camera kind, drawn in `currentColor` so the\n * chip's text token colours them in both states. 24x24 viewBox, no fills\n * that assume a light or dark chip.\n */\nconst ALERT_KIND_GLYPHS: Record<NavCameraKind, string> = {\n fixed:\n '<rect x=\"3\" y=\"8\" width=\"13\" height=\"9\" rx=\"2\"/><circle cx=\"9.5\" cy=\"12.5\" r=\"2.6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"/><path d=\"M16 11.5 21 9v7l-5-2.5z\"/>',\n average:\n '<rect x=\"2\" y=\"9\" width=\"7\" height=\"7\" rx=\"1.6\"/><rect x=\"15\" y=\"9\" width=\"7\" height=\"7\" rx=\"1.6\"/><path d=\"M9.8 12.5h4.4\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\"/><path d=\"M13 10.9l1.9 1.6-1.9 1.6z\"/>',\n red_light:\n '<rect x=\"8\" y=\"2.5\" width=\"8\" height=\"19\" rx=\"2.4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><circle cx=\"12\" cy=\"7\" r=\"1.8\"/><circle cx=\"12\" cy=\"12\" r=\"1.8\" opacity=\"0.45\"/><circle cx=\"12\" cy=\"17\" r=\"1.8\" opacity=\"0.45\"/>',\n mobile_site:\n '<rect x=\"4\" y=\"4.5\" width=\"12\" height=\"8\" rx=\"2\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-dasharray=\"3 2\"/><circle cx=\"10\" cy=\"8.5\" r=\"2.2\"/><path d=\"M10 12.5v3m0 0-4 5m4-5 4 5\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\"/>',\n unknown:\n '<circle cx=\"12\" cy=\"12\" r=\"9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><path d=\"M9.4 9.4a2.7 2.7 0 1 1 3.4 2.6v1.6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\"/><circle cx=\"12.4\" cy=\"16.6\" r=\"1.15\"/>',\n};\n\n/** Frame drawn around the glyph, per curated icon set. */\nconst ALERT_SET_FRAMES: Record<string, string> = {\n european:\n '<circle cx=\"12\" cy=\"12\" r=\"11\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" opacity=\"0.85\"/>',\n us: '<rect x=\"1.4\" y=\"1.4\" width=\"21.2\" height=\"21.2\" rx=\"4.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" opacity=\"0.85\"/>',\n minimal: \"\",\n brand: \"\",\n};\n\n/**\n * The icon for a kind under a design, as a complete inline SVG string.\n *\n * `iconSet` chooses the frame (a European circular plate, a US rounded\n * plate, or no frame); the glyph inside always encodes the KIND, because\n * that is the channel kind is allowed to travel on. `\"brand\"` draws the\n * unframed glyph as its fallback - it expects an `iconUrlOverrides` entry,\n * and {@link alertIconUrl} is what actually resolves one.\n */\nexport function alertIconSvg(design: NavAlertsDesign, kind: NavCameraKind | string): string {\n const normalised = navCameraKind(kind);\n const frame = ALERT_SET_FRAMES[design.iconSet] ?? \"\";\n const glyph = ALERT_KIND_GLYPHS[normalised];\n return `<svg viewBox=\"0 0 24 24\" width=\"100%\" height=\"100%\" fill=\"currentColor\" aria-hidden=\"true\">${frame}${glyph}</svg>`;\n}\n\n/**\n * The override URL for a kind, if the design sets one. Overrides win over\n * `iconSet` for that kind only; every other kind keeps the curated icon.\n */\nexport function alertIconUrl(\n design: NavAlertsDesign,\n kind: NavCameraKind | string,\n): string | undefined {\n return design.iconUrlOverrides?.[navCameraKind(kind)];\n}\n\n/**\n * Template-shaped content for an alert: the fields a head unit can\n * actually render.\n *\n * CarPlay's `CPNavigationAlert` and Android Auto's `Alert` inside a\n * `NavigationTemplate` take a title, a subtitle and an image - the system\n * draws them, and none of the chip's colour, radius or position tokens\n * survive the trip. Hosts targeting a head unit should read this instead\n * of the DOM chip, so styling degrades gracefully rather than being\n * assumed to render.\n */\nexport interface AlertChipContent {\n kind: NavCameraKind;\n /** Primary line, e.g. \"Average speed check\". */\n title: string;\n /** Secondary line: limit and distance when known, else empty. */\n subtitle: string;\n /** Override icon URL when the design sets one for this kind. */\n iconUrl?: string;\n}\n\n/** The text/icon content of an alert chip, free of any styling tokens. */\nexport function alertChipContent(\n design: NavAlertsDesign,\n alert: CameraAlert,\n): AlertChipContent {\n const kind = navCameraKind(alert.kind);\n const parts: string[] = [];\n if (typeof alert.limitKph === \"number\" && Number.isFinite(alert.limitKph)) {\n parts.push(`${Math.round(alert.limitKph)} km/h`);\n }\n if (typeof alert.distanceM === \"number\" && Number.isFinite(alert.distanceM)) {\n const m = Math.max(0, Math.round(alert.distanceM));\n parts.push(m >= 1000 ? `${(m / 1000).toFixed(1)} km` : `${m} m`);\n }\n const iconUrl = alertIconUrl(design, kind);\n return {\n kind,\n title: cameraKindLabel(kind),\n subtitle: parts.join(\" · \"),\n ...(iconUrl !== undefined ? { iconUrl } : {}),\n };\n}\n\n/**\n * The colour a host should paint the SPEED readout, given a design and\n * whether the driver is speeding.\n *\n * Deliberate division of labour: the escalation the driver reads is the\n * speed number turning the escalated colour, while the alert chip stays\n * legible in its own escalated tokens. Colouring the card and leaving the\n * speed untouched puts the urgency on the wrong element - the driver has\n * to act on the speed, so the speed is what changes. Returns `undefined`\n * when calm, meaning \"leave the readout in its normal colour\".\n */\nexport function alertSpeedReadoutColor(\n design: NavAlertsDesign,\n escalated: boolean,\n): string | undefined {\n return escalated ? design.escalatedBackground : undefined;\n}\n\n/** CSS positioning for each constrained chip slot. */\nconst CHIP_SLOT_CSS: Record<string, string> = {\n // Directly above the speed pill: the chip's own bottom margin keeps it\n // clear of the readout rather than overlapping it.\n aboveSpeed: \"align-self:center;margin-bottom:8px;\",\n topLeading: \"align-self:flex-start;\",\n topTrailing: \"align-self:flex-end;\",\n};\n\n/**\n * A minimal DOM safety-alert chip: kind icon, kind label and (when known)\n * the limit and distance, in a calm or escalated state.\n *\n * Style with the `mapmap-alert-chip` class, or pass a Studio design\n * (`extra.nav` `alerts` block, e.g. `map.navDesign?.alerts`) to match a\n * Studio theme. Framework-free and DOM-only, exactly like\n * {@link GuidanceBanner}; head units should read {@link alertChipContent}\n * instead.\n *\n * The chip NEVER overlaps the speed or the limit: its position comes from\n * a constrained slot enum, and `aboveSpeed` reserves its own clearance.\n */\nexport class CameraAlertChip {\n /** The chip root element; attach it wherever your UI needs it. */\n readonly element: HTMLElement;\n private readonly design: NavAlertsDesign | undefined;\n private escalated = false;\n\n constructor(container?: HTMLElement, design?: NavAlertsDesign) {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"CameraAlertChip requires a DOM environment\");\n this.design = design;\n this.element = doc.createElement(\"div\");\n this.element.className = \"mapmap-alert-chip\";\n this.element.setAttribute(\"role\", \"status\");\n if (design) this.element.dataset[\"position\"] = design.chipPosition;\n this.applyStateStyles();\n container?.appendChild(this.element);\n }\n\n /** Whether the chip is currently in its escalated state. */\n get isEscalated(): boolean {\n return this.escalated;\n }\n\n /**\n * Renders an alert (or hides the chip with `null`). `state.speeding`\n * drives the escalated state; the chip itself shows regardless, because\n * the visual alert is unconditional.\n *\n * A kind whose design turns `alertWhileDriving` off hides the chip: the\n * customer chose not to surface that kind while driving.\n */\n update(alert: CameraAlert | null, state: { speeding?: boolean } = {}): void {\n if (!alert) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n const doc = this.element.ownerDocument;\n const design = this.design;\n if (design) {\n const presentation = alertPresentation(design, alert, state);\n if (!presentation.visible) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n this.escalated = presentation.escalated;\n } else {\n this.escalated = state.speeding === true;\n }\n this.applyStateStyles();\n this.element.style.display = \"inline-flex\";\n this.element.dataset[\"state\"] = this.escalated ? \"escalated\" : \"calm\";\n\n const kind = navCameraKind(alert.kind);\n const content = design\n ? alertChipContent(design, alert)\n : { kind, title: cameraKindLabel(kind), subtitle: \"\", iconUrl: undefined };\n\n const icon = doc.createElement(\"span\");\n icon.className = \"mapmap-alert-chip-icon\";\n icon.style.cssText = \"display:inline-flex;width:20px;height:20px;flex:0 0 auto\";\n const overrideUrl = design ? alertIconUrl(design, kind) : undefined;\n if (overrideUrl) {\n const img = doc.createElement(\"img\");\n img.src = overrideUrl;\n img.alt = \"\";\n img.style.cssText = \"width:100%;height:100%;object-fit:contain\";\n icon.appendChild(img);\n } else if (design) {\n icon.innerHTML = alertIconSvg(design, kind);\n }\n\n const text = doc.createElement(\"span\");\n text.textContent = content.title;\n\n const children: HTMLElement[] = [icon, text];\n if (content.subtitle) {\n const detail = doc.createElement(\"span\");\n detail.className = \"mapmap-alert-chip-detail\";\n detail.textContent = content.subtitle;\n detail.style.cssText = \"opacity:0.85;font-weight:500\";\n children.push(detail);\n }\n this.element.replaceChildren(...children);\n }\n\n /** Writes the calm/escalated tokens (and slot) onto the root element. */\n private applyStateStyles(): void {\n const design = this.design;\n const shown = this.element.style.display !== \"none\" ? this.element.style.display : \"none\";\n if (!design) {\n this.element.style.cssText =\n `display:${shown};gap:8px;align-items:center;padding:8px 12px;` +\n `background:${this.escalated ? \"#c0392b\" : \"#101418\"};color:#fff;` +\n \"border-radius:10px;font:600 15px/1.3 system-ui,sans-serif\";\n return;\n }\n const background = this.escalated ? design.escalatedBackground : design.background;\n const color = this.escalated ? design.escalatedTextColor : design.textColor;\n this.element.style.cssText =\n `display:${shown};gap:8px;align-items:center;box-sizing:border-box;padding:8px 12px;` +\n `background:${background};color:${color};` +\n `border-radius:${design.cornerRadius}px;` +\n (design.outlineWidth > 0\n ? `border:${design.outlineWidth}px solid ${design.outlineColor};`\n : \"\") +\n (CHIP_SLOT_CSS[design.chipPosition] ?? \"\") +\n \"font:600 15px/1.3 system-ui,sans-serif\";\n }\n}\n","/**\n * Spoken turn-by-turn guidance over the browser's `SpeechSynthesis`.\n *\n * {@link VoiceGuidance} consumes the guidance updates emitted by the\n * `@mapmap/core` wasm `GuidanceSession` (`{ state: \"navigating\" | \"arrived\"\n * | \"offRoute\", spoken?, severity?, … }`). The core already schedules each\n * spoken prompt by its trigger distance and repeats it on every update\n * until it is superseded, so the speaking rule is simple: announce each\n * `utteranceId` exactly once, the first time it appears.\n *\n * Severity (derived in the Rust core — see `InstructionSeverity`) maps to\n * prosody and earcons:\n *\n * - `info` — normal manoeuvres: base rate/pitch, no earcon by default;\n * - `warning` — approaching a restriction (toll, ferry): slight pitch\n * lift, warning earcon when configured;\n * - `critical` — prohibitions (ADR tunnel block, gate): pitch and rate\n * lift, pending speech cancelled so the prompt is never queued behind\n * chatter, critical earcon when configured.\n *\n * Off-route updates carry no instruction; they play the warning earcon\n * once per off-route episode (the app recalculates and speech resumes on\n * the new session).\n *\n * Earcons are lazy URLs (see `map-assets/earcons/`, generated by\n * `scripts/generate-earcons.py`) — nothing is bundled with the SDK.\n * Everything no-ops safely where `speechSynthesis` is unavailable\n * (non-browser contexts, some webviews).\n */\n\nimport { ssmlToText } from \"./guidance.js\";\n\n/** Instruction urgency, as emitted by the core (`InstructionSeverity`). */\nexport type GuidanceSeverity = \"info\" | \"warning\" | \"critical\";\n\n/** The spoken prompt of a core guidance update. */\nexport interface GuidanceSpokenPrompt {\n /** Plain text for speech synthesis. */\n text: string;\n /** SSML form; browsers reject raw SSML, so it is stripped to text. */\n ssml?: string | null;\n /** Metres before the manoeuvre at which the core released the prompt. */\n triggerDistanceM: number;\n /** Unique utterance id — the de-duplication key. */\n utteranceId: string;\n}\n\n/** The subset of a core guidance update that {@link VoiceGuidance} reads. */\nexport interface VoiceGuidanceUpdate {\n /** Guidance state, as emitted by the wasm `GuidanceSession`. */\n state: \"navigating\" | \"arrived\" | \"offRoute\";\n /** Spoken prompt currently due (repeated until superseded). */\n spoken?: GuidanceSpokenPrompt | null;\n /** Urgency of the current step's instruction (default `info`). */\n severity?: GuidanceSeverity;\n /** BCP 47 locale of the instruction text, when the payload carries one. */\n voiceLocale?: string;\n}\n\n/** Options for {@link VoiceGuidance}. */\nexport interface VoiceGuidanceOptions {\n /** BCP 47 language for utterances, e.g. `en-GB`. An update's\n * `voiceLocale` takes precedence when present. */\n lang?: string;\n /** Base speech rate (0.1–10, default 1). Critical prompts speak\n * slightly faster than this base. */\n rate?: number;\n /** Volume for speech and earcons, 0–1 (default 1). */\n volume?: number;\n /** Start muted. */\n muted?: boolean;\n /** Severity → earcon audio URL. Absent entries play nothing. */\n earcons?: Partial<Record<GuidanceSeverity, string>>;\n}\n\n/** Speech parameters for one severity level. */\nexport interface SeverityProsody {\n /** Utterance rate. */\n rate: number;\n /** Utterance pitch (0–2, 1 = neutral). */\n pitch: number;\n /** Whether pending speech is cancelled before this prompt. */\n interrupt: boolean;\n}\n\n/**\n * Prosody for a severity level at a base rate. Pure — exported for tests\n * and for custom voice layers that want the same house style.\n */\nexport function severityProsody(\n severity: GuidanceSeverity,\n baseRate = 1,\n): SeverityProsody {\n switch (severity) {\n case \"critical\":\n return { rate: baseRate * 1.1, pitch: 1.2, interrupt: true };\n case \"warning\":\n return { rate: baseRate, pitch: 1.1, interrupt: false };\n default:\n return { rate: baseRate, pitch: 1, interrupt: false };\n }\n}\n\n/** Severities that play their earcon by default (info stays silent so a\n * chime does not precede every routine manoeuvre). */\nconst EARCON_SEVERITIES: readonly GuidanceSeverity[] = [\"warning\", \"critical\"];\n\n/**\n * Speaks core guidance updates through the browser's `SpeechSynthesis`,\n * with severity-aware prosody, optional earcons, and mute/volume\n * controls. Feed every update from the wasm `GuidanceSession` to\n * {@link VoiceGuidance.update}.\n */\nexport class VoiceGuidance {\n private readonly options: VoiceGuidanceOptions;\n private volume: number;\n private mutedState: boolean;\n private lastUtteranceId: string | undefined;\n private offRouteAnnounced = false;\n\n constructor(options: VoiceGuidanceOptions = {}) {\n this.options = options;\n this.volume = clampVolume(options.volume ?? 1);\n this.mutedState = options.muted ?? false;\n }\n\n /** Whether this environment can speak at all. */\n get available(): boolean {\n return synth() !== undefined && utteranceCtor() !== undefined;\n }\n\n /** Whether announcements are currently muted. */\n get muted(): boolean {\n return this.mutedState;\n }\n\n /** Mute announcements (also cancels anything mid-utterance). */\n mute(): void {\n this.mutedState = true;\n synth()?.cancel();\n }\n\n /** Unmute announcements. Prompts seen while muted are not replayed. */\n unmute(): void {\n this.mutedState = false;\n }\n\n /** Set the volume for speech and earcons (clamped to 0–1). */\n setVolume(volume: number): void {\n this.volume = clampVolume(volume);\n }\n\n /**\n * Consume one guidance update. Speaks the update's prompt the first\n * time its `utteranceId` appears; plays the warning earcon once per\n * off-route episode. Safe to call in any environment.\n */\n update(update: VoiceGuidanceUpdate): void {\n if (update.state === \"offRoute\") {\n if (!this.offRouteAnnounced) {\n this.offRouteAnnounced = true;\n this.playEarcon(\"warning\");\n }\n return;\n }\n this.offRouteAnnounced = false;\n const spoken = update.spoken;\n if (!spoken || spoken.utteranceId === this.lastUtteranceId) return;\n // Record before the mute check: prompts seen while muted must not\n // replay, stale, on unmute.\n this.lastUtteranceId = spoken.utteranceId;\n this.speak(spoken, update.severity ?? \"info\", update.voiceLocale);\n }\n\n /** Cancel any speech in progress and forget the de-duplication state. */\n dispose(): void {\n synth()?.cancel();\n this.lastUtteranceId = undefined;\n this.offRouteAnnounced = false;\n }\n\n private speak(\n prompt: GuidanceSpokenPrompt,\n severity: GuidanceSeverity,\n voiceLocale: string | undefined,\n ): void {\n if (this.mutedState) return;\n const synthesis = synth();\n const Utterance = utteranceCtor();\n if (!synthesis || !Utterance) return;\n\n const prosody = severityProsody(severity, this.options.rate ?? 1);\n if (prosody.interrupt) synthesis.cancel();\n if (EARCON_SEVERITIES.includes(severity)) this.playEarcon(severity);\n\n const text = prompt.ssml ? ssmlToText(prompt.ssml) : prompt.text;\n const utterance = new Utterance(text);\n const lang = voiceLocale ?? this.options.lang;\n if (lang) utterance.lang = lang;\n utterance.rate = prosody.rate;\n utterance.pitch = prosody.pitch;\n utterance.volume = this.volume;\n synthesis.speak(utterance);\n }\n\n private playEarcon(severity: GuidanceSeverity): void {\n if (this.mutedState) return;\n const url = this.options.earcons?.[severity];\n if (!url) return;\n const AudioCtor = (globalThis as { Audio?: typeof Audio }).Audio;\n if (!AudioCtor) return;\n const audio = new AudioCtor(url);\n audio.volume = this.volume;\n // Autoplay can be rejected before a user gesture; guidance must\n // never throw over a missing chime.\n void audio.play()?.catch?.(() => {});\n }\n}\n\nfunction synth(): SpeechSynthesis | undefined {\n return (globalThis as { speechSynthesis?: SpeechSynthesis }).speechSynthesis;\n}\n\nfunction utteranceCtor(): typeof SpeechSynthesisUtterance | undefined {\n return (\n globalThis as { SpeechSynthesisUtterance?: typeof SpeechSynthesisUtterance }\n ).SpeechSynthesisUtterance;\n}\n\nfunction clampVolume(volume: number): number {\n if (!Number.isFinite(volume)) return 1;\n return Math.min(1, Math.max(0, volume));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/diagnostics.ts","../src/coords.ts","../src/effects.ts","../src/logo.ts","../src/nav-design.ts","../src/poi-design.ts","../src/style.ts","../src/map.ts","../src/osrm.ts","../src/route.ts","../src/contrast.ts","../src/puck.ts","../src/daynight.ts","../src/language.ts","../src/probe.ts","../src/places.ts","../src/camera.ts","../src/isochrone.ts","../src/adr.ts","../src/guidance.ts","../src/voice.ts"],"names":["lng","lat","colour","alertSoundUrl","isRecord","maplibregl","EARTH_RADIUS_M","DEFAULT_ZOOM","now","boundsOf","deg","handle","max","fill","synth","iconUrl"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Self-diagnosing map errors - the SDK tells you what went wrong and how\n * to fix it, instead of a silently blank map.\n *\n * `MapMapMap` runs these checks at construction (and listens for tile\n * auth failures); each detected issue produces ONE `console.error` per\n * page with an actionable message and a docs link. Everything here is\n * best-effort and defensive: no check may ever throw or require a DOM\n * (server-side rendering and Node tests just skip the DOM checks).\n *\n * Issues covered - the documented gotchas that burn real integrations:\n * - a container whose height resolves to 0px (MapLibre renders into a\n * 0-tall canvas: no error, no map)\n * - a container element that is not attached to the DOM\n * - two maplibre-gl copies on one page (duplicate dependency /\n * micro-frontends - breaks the shared WebGL context and styles)\n * - WebGL unavailable (headless browsers, blocked GPU, old devices)\n * - missing/invalid API key (a 401 from the tile or routing endpoints)\n * - a basemap tiles URL that 404s (the map loads but renders blank)\n */\n\nconst DOCS = \"https://mapmap.ai/docs\";\n\n/** The distinct issues the diagnostics can report. */\nexport type DiagnosticIssue =\n | \"container-zero-height\"\n | \"container-detached\"\n | \"duplicate-maplibre\"\n | \"webgl-unavailable\"\n | \"invalid-api-key\"\n | \"basemap-not-found\";\n\n/** Issues already reported on this page: one console.error per issue. */\nconst reported = new Set<DiagnosticIssue>();\n\n/**\n * Cross-module registry of maplibre-gl module instances seen on this\n * page. `Symbol.for` + `globalThis` so the registry is shared even when\n * this SDK itself is bundled twice.\n */\nconst MAPLIBRE_REGISTRY_KEY = Symbol.for(\"mapmap.maplibre-instances\");\n\n/** Reset the once-per-page dedup - for tests (and hot-reload tooling). */\nexport function resetDiagnostics(): void {\n reported.clear();\n const holder = globalThis as Record<symbol, unknown>;\n delete holder[MAPLIBRE_REGISTRY_KEY];\n}\n\nfunction report(issue: DiagnosticIssue, message: string): void {\n if (reported.has(issue)) return;\n reported.add(issue);\n console.error(`MapMap [${issue}]: ${message}`);\n}\n\n/** What `runMapDiagnostics` needs; everything optional and structural. */\nexport interface MapDiagnosticsInput {\n /** The `container` option as given: an element or an element id. */\n container?: string | HTMLElement;\n /**\n * The constructed map (or any object with a MapLibre-style `on`). Used\n * to watch for tile-request auth failures.\n */\n map?: unknown;\n /** The maplibre-gl module the SDK is using (duplicate detection). */\n maplibre?: unknown;\n /** The gateway API key, if one was configured. */\n apiKey?: string | undefined;\n}\n\n/** A MapLibre `error` event, structurally. */\ninterface MapErrorEvent {\n error?: { status?: number; message?: string } | undefined;\n /** The source that raised the error, when it came from source loading. */\n sourceId?: string | undefined;\n}\n\n/**\n * Run the construction-time checks and attach the 401 watcher. Called by\n * `MapMapMap` automatically; exported for apps wrapping a raw\n * `maplibregl.Map` that still want the self-diagnosis.\n */\nexport function runMapDiagnostics(input: MapDiagnosticsInput): void {\n checkDuplicateMaplibre(input.maplibre);\n checkWebgl();\n checkContainer(input.container);\n watchForAuthFailures(input.map, input.apiKey);\n}\n\nfunction checkContainer(container: string | HTMLElement | undefined): void {\n if (container === undefined || typeof document === \"undefined\") return;\n let element: HTMLElement | null;\n try {\n element =\n typeof container === \"string\"\n ? document.getElementById(container)\n : container;\n } catch {\n return;\n }\n if (!element) return; // MapLibre throws its own clear error for this\n // Anything that is not element-shaped is MapLibre's problem to reject.\n if (typeof element.isConnected !== \"boolean\") return;\n if (!element.isConnected) {\n report(\n \"container-detached\",\n \"the map container element is not attached to the DOM, so nothing \" +\n \"can render. Append it to the document before constructing the \" +\n `map. ${DOCS}#container`,\n );\n return; // a detached element always measures 0 - skip the height check\n }\n if (element.clientHeight === 0) {\n report(\n \"container-zero-height\",\n \"the map container's height is 0px, so MapLibre is rendering into \" +\n \"an invisible canvas (no error, no map). Give it a real height, \" +\n `e.g. #map { height: 100vh; }. If the height arrives later (CSS ` +\n `load, layout), you can ignore this. ${DOCS}#container-height`,\n );\n }\n}\n\nfunction checkDuplicateMaplibre(maplibre: unknown): void {\n if (typeof maplibre !== \"object\" && typeof maplibre !== \"function\") return;\n if (maplibre === null) return;\n const holder = globalThis as Record<symbol, unknown>;\n const registry = (holder[MAPLIBRE_REGISTRY_KEY] ??=\n new Set<unknown>()) as Set<unknown>;\n registry.add(maplibre);\n // A UMD copy on window that differs from the module copy counts too.\n const windowCopy = (\n globalThis as { maplibregl?: unknown }\n ).maplibregl;\n if (\n windowCopy !== undefined &&\n (typeof windowCopy === \"object\" || typeof windowCopy === \"function\")\n ) {\n registry.add(windowCopy);\n }\n if (registry.size > 1) {\n report(\n \"duplicate-maplibre\",\n \"two different maplibre-gl instances are loaded on this page \" +\n \"(duplicate dependency, a CDN <script> next to the bundled copy, \" +\n \"or micro-frontends). Maps, styles and the pmtiles protocol \" +\n \"registration will not be shared between them. De-duplicate so \" +\n \"the app owns a single maplibre-gl - it is a peerDependency of \" +\n `@mapmap/maps for exactly this reason. ${DOCS}#duplicate-maplibre`,\n );\n }\n}\n\nfunction checkWebgl(): void {\n if (typeof document === \"undefined\") return;\n try {\n const canvas = document.createElement(\"canvas\");\n const gl =\n canvas.getContext(\"webgl2\") ?? canvas.getContext(\"webgl\");\n if (!gl) {\n report(\n \"webgl-unavailable\",\n \"this browser/environment reports no WebGL support, so the map \" +\n \"cannot render. Common causes: headless browsers without \" +\n \"--use-gl, blocked GPU/hardware acceleration, remote desktops. \" +\n `${DOCS}#webgl`,\n );\n }\n } catch {\n /* probe failure is not evidence either way; stay quiet */\n }\n}\n\nfunction watchForAuthFailures(map: unknown, apiKey: string | undefined): void {\n const on = (map as { on?: (event: string, fn: (ev: MapErrorEvent) => void) => void })\n ?.on;\n if (typeof on !== \"function\" || map === null || map === undefined) return;\n try {\n on.call(map, \"error\", (ev: MapErrorEvent) => {\n const status = ev?.error?.status;\n const message = ev?.error?.message ?? \"\";\n\n // A 404 on the basemap tiles source is the classic \"silently blank\n // map\": the style loads fine, MapLibre requests the PMTiles archive,\n // the CDN 404s, and nothing paints. Report it loudly rather than\n // leaving the developer staring at an empty canvas. Scoped to the\n // `territory` source (the basemap) so a missing sprite/glyph 404\n // does not masquerade as a dead basemap.\n const basemapMissing =\n status === 404 &&\n (ev?.sourceId === \"territory\" || /pmtiles|\\.pmtiles/i.test(message));\n if (basemapMissing) {\n report(\n \"basemap-not-found\",\n \"the basemap tiles returned HTTP 404, so the map renders blank. \" +\n \"The territory tiles URL points at a file that does not exist. \" +\n \"Check `territoryTilesUrl` (or your custom `style`) - the default \" +\n \"MapMap tiles are served at the CDN root \" +\n \"(e.g. https://tiles.mapmap.ai/planet.pmtiles), not under a \" +\n `/territories/ prefix. ${DOCS}#tiles`,\n );\n return;\n }\n\n // Only a numeric 401 status or an explicit \"unauthorised\" message\n // counts — a bare \"401\" in message text is as likely to be a tile\n // coordinate (z/x/y) as an HTTP status.\n const unauthorised =\n status === 401 || /unauthori[sz]ed/i.test(message);\n if (!unauthorised) return;\n report(\n \"invalid-api-key\",\n apiKey\n ? \"the gateway rejected your API key (HTTP 401). Check the \" +\n `\\`apiKey\\` for typos or revocation - keys look like ` +\n `\"snk_…\". ${DOCS}#authentication`\n : \"a request was rejected with HTTP 401 and no `apiKey` was \" +\n \"configured. Pass one to the map (`new MapMapMap({ apiKey: \" +\n '\"snk_…\" })`) - issue a free key with ' +\n `POST https://api.mapmap.ai/v1/keys. ${DOCS}#authentication`,\n );\n });\n } catch {\n /* never let diagnostics break map construction */\n }\n}\n","/**\n * Coordinate helpers - pure, browser-free logic.\n *\n * The gateway speaks the OSRM HTTP API: coordinates are `lon,lat` pairs\n * separated by `;`. MapLibre and GeoJSON use `[lng, lat]` order, so the one\n * job here is to normalise the three accepted input shapes into that wire\n * format without ever swapping the axes by accident.\n */\nimport type { LngLatLike } from \"./types.js\";\n\n/** Normalise any accepted shape to a `[lng, lat]` tuple. */\nexport function toLngLat(point: LngLatLike): [number, number] {\n if (Array.isArray(point)) {\n const [lng, lat] = point;\n assertFinite(lng, lat);\n return [lng, lat];\n }\n const lng = \"lng\" in point ? point.lng : point.lon;\n const lat = point.lat;\n assertFinite(lng, lat);\n return [lng, lat];\n}\n\n/** Format one point as an OSRM `lon,lat` coordinate. */\nexport function formatCoord(point: LngLatLike): string {\n const [lng, lat] = toLngLat(point);\n return `${lng},${lat}`;\n}\n\n/**\n * Format an ordered list of points as an OSRM coordinate path\n * (`lon,lat;lon,lat;…`). At least two points are required, matching the\n * gateway, which rejects single-coordinate requests.\n */\nexport function formatCoords(points: LngLatLike[]): string {\n if (points.length < 2) {\n throw new Error(\"at least two coordinates are required for a route\");\n }\n return points.map(formatCoord).join(\";\");\n}\n\n/**\n * Unwrap a line's longitudes onto a continuous range: shift each\n * successive point by ±360° so no consecutive delta exceeds 180°. An\n * antimeridian-crossing line (`…, 179.9, -179.9, …`) then interpolates\n * across the real 0.2° gap instead of spanning the whole world.\n * Latitudes are untouched; unwrapped longitudes may leave [-180, 180],\n * which trigonometric and mercator consumers read as the adjacent world\n * copy (MapLibre's convention).\n */\nexport function unwrapLngs(\n coordinates: [number, number][],\n): [number, number][] {\n const out: [number, number][] = [];\n for (const [lng, lat] of coordinates) {\n const prev = out[out.length - 1];\n let unwrapped = lng;\n if (prev) {\n while (unwrapped - prev[0] > 180) unwrapped -= 360;\n while (unwrapped - prev[0] < -180) unwrapped += 360;\n }\n out.push([unwrapped, lat]);\n }\n return out;\n}\n\nfunction assertFinite(lng: number, lat: number): void {\n if (!Number.isFinite(lng) || !Number.isFinite(lat)) {\n throw new Error(`invalid coordinate: lng=${lng}, lat=${lat}`);\n }\n if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {\n throw new Error(\n `coordinate out of range: lng=${lng} (±180), lat=${lat} (±90) - check lng/lat order`,\n );\n }\n}\n","/**\n * Effects engine - named, geometry-anchored visual effects rendered through\n * MapLibre's stable `CustomLayerInterface` (first-party GLSL, no runtime\n * dependencies). The first effect is `\"flow\"`: an animated energy ribbon\n * along the active route line, drawn as a triangle strip with a flowing\n * pulse gradient driven by a time uniform.\n *\n * Deliberately NOT full-map post-processing: MapLibre has no official\n * post-process hook, so every effect here anchors to geometry and rides the\n * supported custom-layer API. New effects register in {@link ROUTE_EFFECTS}.\n *\n * Accessibility and resilience:\n * - `prefers-reduced-motion: reduce` freezes the ribbon to a static\n * gradient (no animation loop, no repaints).\n * - If WebGL setup for the custom layer fails (shader compile/link, lost\n * context), the effect silently disables itself - the ordinary route\n * line underneath is untouched - and logs a single console warning.\n *\n * The tessellation and colour helpers are pure and unit-tested in Node;\n * only the layer object itself touches WebGL.\n */\nimport type { CustomLayerInterface, Map as MlMap } from \"maplibre-gl\";\nimport { unwrapLngs } from \"./coords.js\";\nimport type { RouteGeometry } from \"./types.js\";\n\n// Kept import-free of route.ts/places.ts on purpose: map.ts imports this\n// module, and both of those import map.ts (cycle), while the pure helpers\n// here must stay loadable in Node without maplibre-gl.\n\n/** MapMap brand signal blue - matches `SIGNAL_BLUE` in route.ts. */\nconst FLOW_COLOUR = \"#3a86ff\";\n\n/** Mean Earth radius in metres (IUGG) - matches places.ts. */\nconst EARTH_RADIUS_M = 6371008.8;\n\n/** Straight-line (haversine) distance between two `[lng, lat]`s, metres. */\nfunction haversineM(a: [number, number], b: [number, number]): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b[1] - a[1]);\n const dLon = rad(b[0] - a[0]);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a[1])) * Math.cos(rad(b[1])) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/** The names the effects registry knows. Grows as effects land. */\nexport type RouteEffectName = \"flow\";\n\n/** Options for the `\"flow\"` route effect (all optional). */\nexport interface RouteFlowOptions {\n /** Ribbon colour (hex or rgb()/rgba()). Defaults to MapMap signal blue. */\n color?: string;\n /** Ribbon width in CSS pixels. Defaults to `10`. */\n width?: number;\n /** Flow speed in pulse cycles per second. Defaults to `0.6`. */\n speed?: number;\n /** MapLibre layer id. Defaults to `\"mapmap-route-effect\"`. */\n id?: string;\n}\n\n/** Floats per ribbon vertex: x, y (mercator), nx, ny (unit normal), progress. */\nexport const RIBBON_FLOATS_PER_VERTEX = 5;\n\n/** A tessellated route ribbon, ready for a `TRIANGLE_STRIP` draw. */\nexport interface RibbonMesh {\n /**\n * Interleaved vertex data, {@link RIBBON_FLOATS_PER_VERTEX} floats per\n * vertex: mercator position, the unit extrusion normal (the shader\n * extrudes `pos + normal * halfWidth`, so width stays zoom-correct\n * without re-tessellating), and progress along the route (0 at the\n * start, 1 at the end - the flowing gradient's coordinate).\n */\n vertices: Float32Array;\n /** Number of vertices (two per route point kept). */\n vertexCount: number;\n}\n\n/**\n * Project a `[lng, lat]` to web-mercator world coordinates in [0, 1]\n * (MapLibre's `MercatorCoordinate` convention: x east, y south).\n */\nexport function lngLatToMercator(lngLat: [number, number]): [number, number] {\n const [lng, lat] = lngLat;\n const x = (lng + 180) / 360;\n const y =\n (1 - Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI) / 360)) / Math.PI) / 2;\n return [x, y];\n}\n\n/**\n * Tessellate a route line into a centreline triangle strip: two vertices\n * per point, each carrying the point's mercator position, a unit extrusion\n * normal (averaged between adjacent segments at joins - a bevel-free miter\n * that slightly thins very sharp corners, which is invisible on a soft\n * glow ribbon), and normalised progress along the line.\n *\n * Pure: no WebGL, no map. Consecutive duplicate points are dropped; fewer\n * than two distinct points yield an empty mesh.\n */\nexport function tessellateRouteRibbon(\n coordinates: [number, number][],\n): RibbonMesh {\n // Unwrap longitudes first so an antimeridian-crossing route projects to\n // adjacent mercator world copies instead of a ribbon spanning the whole\n // world; then project and drop consecutive duplicates (zero-length\n // segments have no direction and would produce NaN normals).\n const points: [number, number][] = [];\n for (const lngLat of unwrapLngs(coordinates)) {\n const p = lngLatToMercator(lngLat);\n const last = points[points.length - 1];\n if (!last || last[0] !== p[0] || last[1] !== p[1]) points.push(p);\n }\n if (points.length < 2) {\n return { vertices: new Float32Array(0), vertexCount: 0 };\n }\n\n // Cumulative mercator distance -> progress 0..1 along the line.\n const cumulative: number[] = [0];\n for (let i = 1; i < points.length; i++) {\n const dx = points[i]![0] - points[i - 1]![0];\n const dy = points[i]![1] - points[i - 1]![1];\n cumulative.push(cumulative[i - 1]! + Math.hypot(dx, dy));\n }\n const total = cumulative[cumulative.length - 1]!;\n\n const vertices = new Float32Array(\n points.length * 2 * RIBBON_FLOATS_PER_VERTEX,\n );\n let out = 0;\n for (let i = 0; i < points.length; i++) {\n const prev = points[i - 1];\n const here = points[i]!;\n const next = points[i + 1];\n // Direction at this point: the segment direction at the ends, the\n // normalised average of both segment directions at interior joins.\n let dirX = 0;\n let dirY = 0;\n if (prev) {\n const len = Math.hypot(here[0] - prev[0], here[1] - prev[1]);\n dirX += (here[0] - prev[0]) / len;\n dirY += (here[1] - prev[1]) / len;\n }\n if (next) {\n const len = Math.hypot(next[0] - here[0], next[1] - here[1]);\n dirX += (next[0] - here[0]) / len;\n dirY += (next[1] - here[1]) / len;\n }\n const dirLen = Math.hypot(dirX, dirY);\n // A perfect 180-degree switchback averages to zero; fall back to the\n // incoming segment's direction.\n if (dirLen < 1e-12 && prev) {\n const len = Math.hypot(here[0] - prev[0], here[1] - prev[1]);\n dirX = (here[0] - prev[0]) / len;\n dirY = (here[1] - prev[1]) / len;\n } else {\n dirX /= dirLen;\n dirY /= dirLen;\n }\n // Left-hand unit normal to the direction of travel.\n const nx = -dirY;\n const ny = dirX;\n const progress = total > 0 ? cumulative[i]! / total : 0;\n // Two strip vertices: one extruded each side of the centreline.\n for (const side of [1, -1]) {\n vertices[out++] = here[0];\n vertices[out++] = here[1];\n vertices[out++] = nx * side;\n vertices[out++] = ny * side;\n vertices[out++] = progress;\n }\n }\n return { vertices, vertexCount: points.length * 2 };\n}\n\n/**\n * Parse a CSS colour to premultiplication-ready `[r, g, b, a]` (0-1\n * channels). Supports the hex forms and `rgb()`/`rgba()`; anything else\n * (named colours, `hsl()`) returns `undefined` and the caller falls back\n * to the default - this runs where no canvas is guaranteed, so no\n * browser colour parser is available.\n */\nexport function parseCssColour(\n colour: string,\n): [number, number, number, number] | undefined {\n const v = colour.trim();\n if (v.startsWith(\"#\")) {\n const hex = v.slice(1);\n if (!/^[0-9a-fA-F]+$/.test(hex)) return undefined;\n if (hex.length === 3 || hex.length === 4) {\n const parts = hex.split(\"\").map((c) => parseInt(c + c, 16) / 255);\n const [r, g, b, a] = parts;\n if (r === undefined || g === undefined || b === undefined) return undefined;\n return [r, g, b, a ?? 1];\n }\n if (hex.length === 6 || hex.length === 8) {\n const chan = (i: number): number =>\n parseInt(hex.slice(i, i + 2), 16) / 255;\n return [chan(0), chan(2), chan(4), hex.length === 8 ? chan(6) : 1];\n }\n return undefined;\n }\n const fn = /^rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*(?:,\\s*([\\d.]+)\\s*)?\\)$/.exec(v);\n if (fn) {\n const r = Number(fn[1]) / 255;\n const g = Number(fn[2]) / 255;\n const b = Number(fn[3]) / 255;\n const a = fn[4] !== undefined ? Number(fn[4]) : 1;\n if ([r, g, b, a].some((c) => !Number.isFinite(c) || c < 0 || c > 1)) {\n return undefined;\n }\n return [r, g, b, a];\n }\n return undefined;\n}\n\n/** Whether the user has asked for reduced motion. Safe without a DOM. */\nexport function prefersReducedMotion(): boolean {\n if (typeof matchMedia !== \"function\") return false;\n try {\n return matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n } catch {\n return false;\n }\n}\n\nconst VERTEX_SHADER = `\nuniform mat4 u_matrix;\nuniform float u_half_width;\nattribute vec2 a_pos;\nattribute vec2 a_normal;\nattribute float a_progress;\nvarying float v_progress;\nvoid main() {\n v_progress = a_progress;\n gl_Position = u_matrix * vec4(a_pos + a_normal * u_half_width, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `\nprecision mediump float;\nuniform vec4 u_color;\nuniform float u_phase;\nuniform float u_repeats;\nvarying float v_progress;\nvoid main() {\n float t = fract(v_progress * u_repeats - u_phase);\n // A soft comet: rises quickly, decays slowly, never fully dark so the\n // ribbon always traces the route.\n float pulse = smoothstep(0.0, 0.25, t) * (1.0 - smoothstep(0.35, 1.0, t));\n float energy = 0.25 + 0.75 * pulse;\n float alpha = u_color.a * energy;\n // Premultiplied alpha, matching MapLibre's framebuffer convention.\n gl_FragColor = vec4(u_color.rgb * alpha, alpha);\n}\n`;\n\n/** Warned-once flag for WebGL setup failures (one line per page, not per frame). */\nlet warnedWebglFailure = false;\n\n/** Test-only reset for the warn-once flag. */\nexport function resetEffectsWarnings(): void {\n warnedWebglFailure = false;\n}\n\n/** Default flow parameters (exported so docs/tests state one truth). */\nexport const FLOW_DEFAULTS = {\n color: FLOW_COLOUR,\n width: 10,\n speed: 0.6,\n} as const;\n\n/** World size in pixels at a zoom, for the pixel->mercator width scale. */\nfunction mercatorUnitsPerPixel(zoom: number): number {\n return 1 / (512 * 2 ** zoom);\n}\n\n/**\n * Great-circle length of a route in metres (drives how many flow pulses\n * fit along it, so short and long routes animate at a similar density).\n */\nfunction routeLengthM(coordinates: [number, number][]): number {\n let length = 0;\n for (let i = 1; i < coordinates.length; i++) {\n length += haversineM(coordinates[i - 1]!, coordinates[i]!);\n }\n return length;\n}\n\n/**\n * A MapLibre custom layer (`CustomLayerInterface`) drawing the flowing\n * route ribbon. Construct via {@link createRouteEffect} (the registry) or\n * use `MapMapMap.setRouteEffect(\"flow\")`, which manages the lifecycle.\n */\nexport class FlowRouteEffectLayer implements CustomLayerInterface {\n readonly id: string;\n readonly type = \"custom\" as const;\n readonly renderingMode = \"2d\" as const;\n\n private geometry: RouteGeometry;\n private readonly colour: [number, number, number, number];\n private readonly widthPx: number;\n private readonly speed: number;\n private readonly animate: boolean;\n\n private mapRef: MlMap | undefined;\n private glRef: WebGLRenderingContext | WebGL2RenderingContext | undefined;\n private program: WebGLProgram | null = null;\n private buffer: WebGLBuffer | null = null;\n private vertexCount = 0;\n private repeats = 8;\n private startedAt = 0;\n private failed = false;\n private aPos = 0;\n private aNormal = 0;\n private aProgress = 0;\n private uMatrix: WebGLUniformLocation | null = null;\n private uHalfWidth: WebGLUniformLocation | null = null;\n private uColor: WebGLUniformLocation | null = null;\n private uPhase: WebGLUniformLocation | null = null;\n private uRepeats: WebGLUniformLocation | null = null;\n\n constructor(geometry: RouteGeometry, options: RouteFlowOptions = {}) {\n this.id = options.id ?? \"mapmap-route-effect\";\n this.geometry = geometry;\n this.colour =\n (options.color !== undefined ? parseCssColour(options.color) : undefined) ??\n (parseCssColour(FLOW_DEFAULTS.color) as [number, number, number, number]);\n this.widthPx = options.width ?? FLOW_DEFAULTS.width;\n this.speed = options.speed ?? FLOW_DEFAULTS.speed;\n // Reduced motion: keep the ribbon (a static gradient still marks the\n // route) but freeze the phase and never request repaints.\n this.animate = !prefersReducedMotion();\n }\n\n /** Swap the ribbon onto a new route line (e.g. after a reroute). */\n setGeometry(geometry: RouteGeometry): void {\n this.geometry = geometry;\n if (this.glRef && !this.failed) this.upload(this.glRef);\n this.mapRef?.triggerRepaint();\n }\n\n onAdd(map: MlMap, gl: WebGLRenderingContext | WebGL2RenderingContext): void {\n this.mapRef = map;\n this.glRef = gl;\n this.startedAt = now();\n try {\n const program = gl.createProgram();\n if (!program) throw new Error(\"createProgram returned null\");\n for (const [kind, source] of [\n [gl.VERTEX_SHADER, VERTEX_SHADER],\n [gl.FRAGMENT_SHADER, FRAGMENT_SHADER],\n ] as const) {\n const shader = gl.createShader(kind);\n if (!shader) throw new Error(\"createShader returned null\");\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error(gl.getShaderInfoLog(shader) ?? \"shader compile failed\");\n }\n gl.attachShader(program, shader);\n }\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(gl.getProgramInfoLog(program) ?? \"program link failed\");\n }\n this.program = program;\n this.aPos = gl.getAttribLocation(program, \"a_pos\");\n this.aNormal = gl.getAttribLocation(program, \"a_normal\");\n this.aProgress = gl.getAttribLocation(program, \"a_progress\");\n this.uMatrix = gl.getUniformLocation(program, \"u_matrix\");\n this.uHalfWidth = gl.getUniformLocation(program, \"u_half_width\");\n this.uColor = gl.getUniformLocation(program, \"u_color\");\n this.uPhase = gl.getUniformLocation(program, \"u_phase\");\n this.uRepeats = gl.getUniformLocation(program, \"u_repeats\");\n this.upload(gl);\n } catch (error) {\n // Static fallback: the plain route line underneath is untouched;\n // the ribbon simply never draws. One warning per page.\n this.failed = true;\n if (!warnedWebglFailure) {\n warnedWebglFailure = true;\n console.warn(\n `MapMap: route effect \"flow\" disabled (WebGL setup failed: ` +\n `${error instanceof Error ? error.message : String(error)}). ` +\n \"Falling back to the plain route line.\",\n );\n }\n }\n }\n\n onRemove(\n _map: MlMap,\n gl: WebGLRenderingContext | WebGL2RenderingContext,\n ): void {\n if (this.buffer) gl.deleteBuffer(this.buffer);\n if (this.program) gl.deleteProgram(this.program);\n this.buffer = null;\n this.program = null;\n this.mapRef = undefined;\n this.glRef = undefined;\n }\n\n render(gl: WebGLRenderingContext | WebGL2RenderingContext, args: unknown): void {\n if (this.failed || !this.program || !this.buffer || this.vertexCount < 3) {\n return;\n }\n const matrix = projectionMatrixOf(args);\n if (!matrix || !this.mapRef) return;\n\n gl.useProgram(this.program);\n gl.uniformMatrix4fv(this.uMatrix, false, matrix);\n const halfWidth =\n (this.widthPx / 2) * mercatorUnitsPerPixel(this.mapRef.getZoom());\n gl.uniform1f(this.uHalfWidth, halfWidth);\n gl.uniform4f(this.uColor, ...this.colour);\n const phase = this.animate\n ? ((now() - this.startedAt) / 1000) * this.speed % 1\n : 0;\n gl.uniform1f(this.uPhase, phase);\n gl.uniform1f(this.uRepeats, this.repeats);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n const stride = RIBBON_FLOATS_PER_VERTEX * 4;\n gl.enableVertexAttribArray(this.aPos);\n gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);\n gl.enableVertexAttribArray(this.aNormal);\n gl.vertexAttribPointer(this.aNormal, 2, gl.FLOAT, false, stride, 8);\n gl.enableVertexAttribArray(this.aProgress);\n gl.vertexAttribPointer(this.aProgress, 1, gl.FLOAT, false, stride, 16);\n\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); // premultiplied alpha\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.vertexCount);\n\n if (this.animate) this.mapRef.triggerRepaint();\n }\n\n private upload(gl: WebGLRenderingContext | WebGL2RenderingContext): void {\n const mesh = tessellateRouteRibbon(this.geometry.coordinates);\n this.vertexCount = mesh.vertexCount;\n // Pulse density scales with route length: one pulse roughly every\n // 500 m, clamped so a short hop still flows and a long haul doesn't\n // strobe.\n this.repeats = Math.min(\n 80,\n Math.max(2, Math.round(routeLengthM(this.geometry.coordinates) / 500)),\n );\n if (!this.buffer) this.buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n gl.bufferData(gl.ARRAY_BUFFER, mesh.vertices, gl.STATIC_DRAW);\n }\n}\n\n/** Monotonic-ish clock that works in browsers and Node tests. */\nfunction now(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n}\n\n/**\n * The main projection matrix out of a custom layer `render` argument:\n * MapLibre v4 passes the matrix itself, v5 passes an args object carrying\n * `defaultProjectionData.mainMatrix`.\n */\nfunction projectionMatrixOf(args: unknown): Float32Array | number[] | undefined {\n if (Array.isArray(args)) return args as number[];\n if (args instanceof Float32Array || args instanceof Float64Array) {\n return args instanceof Float64Array ? new Float32Array(args) : args;\n }\n if (typeof args === \"object\" && args !== null) {\n const data = (args as { defaultProjectionData?: { mainMatrix?: unknown } })\n .defaultProjectionData;\n const main = data?.mainMatrix;\n if (Array.isArray(main)) return main as number[];\n if (main instanceof Float32Array) return main;\n if (main instanceof Float64Array) return new Float32Array(main);\n }\n return undefined;\n}\n\n/** A route effect layer: a custom layer that can retarget its geometry. */\nexport interface RouteEffectLayer extends CustomLayerInterface {\n setGeometry(geometry: RouteGeometry): void;\n}\n\n/**\n * The effect registry: name -> layer factory. New effects (ambient life,\n * seasonal snow, fog-of-exploration) add an entry here and a name to\n * {@link RouteEffectName}.\n */\nexport const ROUTE_EFFECTS: Record<\n RouteEffectName,\n (geometry: RouteGeometry, options?: RouteFlowOptions) => RouteEffectLayer\n> = {\n flow: (geometry, options) => new FlowRouteEffectLayer(geometry, options),\n};\n\n/**\n * Create a named route effect layer. Throws an agent-readable error for\n * unknown names (the accepted list included).\n */\nexport function createRouteEffect(\n name: RouteEffectName,\n geometry: RouteGeometry,\n options?: RouteFlowOptions,\n): RouteEffectLayer {\n const factory = ROUTE_EFFECTS[name];\n if (!factory) {\n throw new Error(\n `unknown route effect ${JSON.stringify(name)}; accepted effects: ` +\n Object.keys(ROUTE_EFFECTS).join(\", \"),\n );\n }\n return factory(geometry, options);\n}\n","/**\n * The MapMap logo control: a small wordmark on the map, the same\n * convention as Google Maps' and Mapbox's marks. On by default in\n * {@link MapMapMap}; positionable, and removable with `logo: false`\n * (attribution itself is separate and never removable).\n *\n * The mark is an inline SVG (no network fetch, works offline and under\n * strict CSPs): the MapMap brand lockup — the three-colour route mark\n * plus the lowercase wordmark. Height stays at 20px so existing layouts\n * hold.\n */\n\n/** Corner positions accepted by the logo control. */\nexport type LogoPosition = \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\";\n\n/** Options for {@link LogoControl}. */\nexport interface LogoOptions {\n /** Corner to render in. Default `bottom-right`, above the attribution. */\n position?: LogoPosition;\n /** Link target when clicked. Default the MapMap site. */\n href?: string;\n}\n\n/**\n * The inline wordmark (height 20px): the outline-light lockup — the\n * line-art route mark plus the dark wordmark — over a white halo stroke\n * so it stays legible on any base map.\n */\nexport const LOGO_SVG =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"85\" height=\"20\" viewBox=\"0 0 156 37\" fill=\"none\" role=\"img\" aria-label=\"MapMap\"><g stroke=\"#ffffff\" stroke-linejoin=\"round\" stroke-linecap=\"round\"><path d=\"M138.576 33.2887V11.4951H142.24V14.1161H142.456C142.649 13.7308 142.92 13.3215 143.269 12.8881C143.619 12.4479 144.093 12.0729 144.69 11.7634C145.287 11.4469 146.048 11.2887 146.975 11.2887C148.196 11.2887 149.297 11.6017 150.279 12.2277C151.267 12.8469 152.049 13.7652 152.625 14.9829C153.209 16.1936 153.5 17.6796 153.5 19.4407C153.5 21.1811 153.215 22.6602 152.646 23.8778C152.076 25.0955 151.301 26.0242 150.32 26.6639C149.339 27.3037 148.227 27.6236 146.985 27.6236C146.079 27.6236 145.328 27.4722 144.731 27.1696C144.134 26.8669 143.654 26.5023 143.29 26.0757C142.933 25.6424 142.655 25.233 142.456 24.8478H142.302V33.2887H138.576ZM142.23 19.42C142.23 20.445 142.374 21.3428 142.662 22.1133C142.957 22.8838 143.379 23.4857 143.928 23.9191C144.484 24.3456 145.156 24.5589 145.946 24.5589C146.769 24.5589 147.458 24.3387 148.014 23.8985C148.57 23.4513 148.989 22.8425 149.27 22.072C149.558 21.2946 149.702 20.4106 149.702 19.42C149.702 18.4363 149.562 17.5626 149.28 16.799C148.999 16.0354 148.58 15.4369 148.025 15.0035C147.469 14.5701 146.776 14.3534 145.946 14.3534C145.15 14.3534 144.474 14.5632 143.918 14.9829C143.362 15.4025 142.94 15.9907 142.652 16.7474C142.371 17.5041 142.23 18.395 142.23 19.42Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M127.352 27.6649C126.35 27.6649 125.448 27.486 124.645 27.1283C123.849 26.7637 123.218 26.2271 122.751 25.5185C122.291 24.81 122.062 23.9363 122.062 22.8975C122.062 22.0032 122.226 21.2637 122.556 20.6789C122.885 20.0942 123.334 19.6264 123.904 19.2756C124.473 18.9247 125.115 18.6599 125.829 18.481C126.549 18.2953 127.293 18.1611 128.062 18.0786C128.988 17.9823 129.74 17.8963 130.316 17.8206C130.892 17.738 131.311 17.6142 131.572 17.4491C131.839 17.2771 131.973 17.0123 131.973 16.6545V16.5926C131.973 15.8153 131.743 15.2133 131.284 14.7868C130.824 14.3603 130.162 14.147 129.297 14.147C128.384 14.147 127.661 14.3465 127.125 14.7455C126.597 15.1445 126.24 15.6158 126.055 16.1592L122.576 15.6639C122.851 14.7008 123.303 13.896 123.935 13.2493C124.566 12.5958 125.338 12.1073 126.251 11.784C127.163 11.4538 128.172 11.2887 129.276 11.2887C130.038 11.2887 130.796 11.3781 131.551 11.557C132.306 11.7359 132.995 12.0317 133.62 12.4444C134.244 12.8503 134.745 13.4041 135.123 14.1058C135.507 14.8075 135.699 15.6846 135.699 16.7371V27.345H132.117V25.1677H131.994C131.767 25.608 131.448 26.0207 131.036 26.406C130.632 26.7843 130.12 27.0904 129.503 27.3243C128.892 27.5514 128.175 27.6649 127.352 27.6649ZM128.319 24.92C129.067 24.92 129.716 24.7721 130.265 24.4763C130.813 24.1736 131.235 23.7746 131.531 23.2793C131.832 22.784 131.983 22.244 131.983 21.6592V19.7915C131.867 19.8878 131.668 19.9773 131.386 20.0598C131.112 20.1424 130.803 20.2146 130.46 20.2765C130.117 20.3384 129.777 20.3934 129.441 20.4416C129.105 20.4898 128.813 20.531 128.566 20.5654C128.011 20.6411 127.513 20.7649 127.074 20.9369C126.635 21.1089 126.288 21.3497 126.034 21.6592C125.781 21.9619 125.654 22.354 125.654 22.8356C125.654 23.5235 125.904 24.0429 126.405 24.3938C126.906 24.7446 127.544 24.92 128.319 24.92Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M97.6602 27.345V11.4951H101.221V14.1883H101.407C101.736 13.2803 102.281 12.5717 103.043 12.0626C103.805 11.5467 104.714 11.2887 105.771 11.2887C106.841 11.2887 107.743 11.5501 108.477 12.0729C109.219 12.5889 109.74 13.294 110.042 14.1883H110.207C110.557 13.3078 111.147 12.6061 111.977 12.0833C112.814 11.5535 113.805 11.2887 114.951 11.2887C116.406 11.2887 117.593 11.7496 118.513 12.6714C119.432 13.5933 119.892 14.9382 119.892 16.7061V27.345H116.156V17.284C116.156 16.3003 115.895 15.5814 115.373 15.1273C114.852 14.6664 114.214 14.436 113.459 14.436C112.56 14.436 111.857 14.718 111.349 15.2821C110.848 15.8394 110.598 16.5651 110.598 17.4594V27.345H106.944V17.1292C106.944 16.3106 106.697 15.6571 106.203 15.1686C105.716 14.6802 105.078 14.436 104.288 14.436C103.753 14.436 103.266 14.5736 102.827 14.8487C102.388 15.117 102.038 15.4988 101.777 15.9941C101.516 16.4826 101.386 17.0535 101.386 17.7071V27.345H97.6602Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M80.416 33.2887V11.4951H84.0801V14.1161H84.2962C84.4884 13.7308 84.7594 13.3215 85.1093 12.8881C85.4593 12.4479 85.9327 12.0729 86.5297 11.7634C87.1267 11.4469 87.8883 11.2887 88.8146 11.2887C90.036 11.2887 91.1373 11.6017 92.1185 12.2277C93.1065 12.8469 93.8888 13.7652 94.4651 14.9829C95.0484 16.1936 95.34 17.6796 95.34 19.4407C95.34 21.1811 95.0552 22.6602 94.4857 23.8778C93.9162 25.0955 93.1408 26.0242 92.1596 26.6639C91.1784 27.3037 90.0668 27.6236 88.8249 27.6236C87.9192 27.6236 87.1678 27.4722 86.5709 27.1696C85.9739 26.8669 85.4936 26.5023 85.1299 26.0757C84.7731 25.6424 84.4952 25.233 84.2962 24.8478H84.1419V33.2887H80.416ZM84.0698 19.42C84.0698 20.445 84.2139 21.3428 84.5021 22.1133C84.7971 22.8838 85.2191 23.4857 85.7681 23.9191C86.3238 24.3456 86.9963 24.5589 87.7854 24.5589C88.6088 24.5589 89.2983 24.3387 89.8541 23.8985C90.4099 23.4513 90.8285 22.8425 91.1098 22.072C91.398 21.2946 91.5421 20.4106 91.5421 19.42C91.5421 18.4363 91.4014 17.5626 91.1201 16.799C90.8388 16.0354 90.4202 15.4369 89.8644 15.0035C89.3086 14.5701 88.6156 14.3534 87.7854 14.3534C86.9894 14.3534 86.3136 14.5632 85.7578 14.9829C85.202 15.4025 84.78 15.9907 84.4918 16.7474C84.2105 17.5041 84.0698 18.395 84.0698 19.42Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M69.1921 27.6649C68.1904 27.6649 67.2881 27.486 66.4852 27.1283C65.6893 26.7637 65.058 26.2271 64.5914 25.5185C64.1317 24.81 63.9019 23.9363 63.9019 22.8975C63.9019 22.0032 64.0665 21.2637 64.3959 20.6789C64.7252 20.0942 65.1747 19.6264 65.7442 19.2756C66.3137 18.9247 66.9553 18.6599 67.6689 18.481C68.3893 18.2953 69.1338 18.1611 69.9023 18.0786C70.8286 17.9823 71.58 17.8963 72.1564 17.8206C72.7327 17.738 73.1513 17.6142 73.412 17.4491C73.6796 17.2771 73.8134 17.0123 73.8134 16.6545V16.5926C73.8134 15.8153 73.5836 15.2133 73.1238 14.7868C72.6641 14.3603 72.002 14.147 71.1374 14.147C70.2248 14.147 69.5009 14.3465 68.9657 14.7455C68.4374 15.1445 68.0806 15.6158 67.8953 16.1592L64.4165 15.6639C64.6909 14.7008 65.1438 13.896 65.7751 13.2493C66.4063 12.5958 67.1783 12.1073 68.0909 11.784C69.0034 11.4538 70.0121 11.2887 71.1168 11.2887C71.8785 11.2887 72.6367 11.3781 73.3914 11.557C74.1462 11.7359 74.8358 12.0317 75.4602 12.4444C76.0846 12.8503 76.5855 13.4041 76.9629 14.1058C77.3471 14.8075 77.5393 15.6846 77.5393 16.7371V27.345H73.9575V25.1677H73.834C73.6076 25.608 73.2885 26.0207 72.8768 26.406C72.472 26.7843 71.9608 27.0904 71.3433 27.3243C70.7326 27.5514 70.0155 27.6649 69.1921 27.6649ZM70.1596 24.92C70.9075 24.92 71.556 24.7721 72.1049 24.4763C72.6538 24.1736 73.0758 23.7746 73.3709 23.2793C73.6728 22.784 73.8237 22.244 73.8237 21.6592V19.7915C73.7071 19.8878 73.5081 19.9773 73.2268 20.0598C72.9523 20.1424 72.6435 20.2146 72.3004 20.2765C71.9574 20.3384 71.6177 20.3934 71.2815 20.4416C70.9453 20.4898 70.6537 20.531 70.4066 20.5654C69.8509 20.6411 69.3534 20.7649 68.9143 20.9369C68.4751 21.1089 68.1286 21.3497 67.8747 21.6592C67.6208 21.9619 67.4939 22.354 67.4939 22.8356C67.4939 23.5235 67.7443 24.0429 68.2452 24.3938C68.7461 24.7446 69.3843 24.92 70.1596 24.92Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M39.5 27.345V11.4951H43.0612V14.1883H43.2464C43.5758 13.2803 44.1213 12.5717 44.8829 12.0626C45.6446 11.5467 46.5537 11.2887 47.6104 11.2887C48.6808 11.2887 49.5831 11.5501 50.3173 12.0729C51.0584 12.5889 51.5798 13.294 51.8817 14.1883H52.0464C52.3964 13.3078 52.9865 12.6061 53.8167 12.0833C54.6538 11.5535 55.6453 11.2887 56.7912 11.2887C58.2459 11.2887 59.4329 11.7496 60.3524 12.6714C61.2718 13.5933 61.7316 14.9382 61.7316 16.7061V27.345H57.9954V17.284C57.9954 16.3003 57.7347 15.5814 57.2132 15.1273C56.6917 14.6664 56.0536 14.436 55.2988 14.436C54.3999 14.436 53.6966 14.718 53.1889 15.2821C52.688 15.8394 52.4375 16.5651 52.4375 17.4594V27.345H48.7837V17.1292C48.7837 16.3106 48.5367 15.6571 48.0427 15.1686C47.5555 14.6802 46.9174 14.436 46.1283 14.436C45.5931 14.436 45.1059 14.5736 44.6668 14.8487C44.2276 15.117 43.8777 15.4988 43.617 15.9941C43.3562 16.4826 43.2258 17.0535 43.2258 17.7071V27.345H39.5Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/><path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke-width=\"4.96\"/><path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke-width=\"4.96\"/><path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke-width=\"4.96\"/></g><path d=\"M138.576 33.2887V11.4951H142.24V14.1161H142.456C142.649 13.7308 142.92 13.3215 143.269 12.8881C143.619 12.4479 144.093 12.0729 144.69 11.7634C145.287 11.4469 146.048 11.2887 146.975 11.2887C148.196 11.2887 149.297 11.6017 150.279 12.2277C151.267 12.8469 152.049 13.7652 152.625 14.9829C153.209 16.1936 153.5 17.6796 153.5 19.4407C153.5 21.1811 153.215 22.6602 152.646 23.8778C152.076 25.0955 151.301 26.0242 150.32 26.6639C149.339 27.3037 148.227 27.6236 146.985 27.6236C146.079 27.6236 145.328 27.4722 144.731 27.1696C144.134 26.8669 143.654 26.5023 143.29 26.0757C142.933 25.6424 142.655 25.233 142.456 24.8478H142.302V33.2887H138.576ZM142.23 19.42C142.23 20.445 142.374 21.3428 142.662 22.1133C142.957 22.8838 143.379 23.4857 143.928 23.9191C144.484 24.3456 145.156 24.5589 145.946 24.5589C146.769 24.5589 147.458 24.3387 148.014 23.8985C148.57 23.4513 148.989 22.8425 149.27 22.072C149.558 21.2946 149.702 20.4106 149.702 19.42C149.702 18.4363 149.562 17.5626 149.28 16.799C148.999 16.0354 148.58 15.4369 148.025 15.0035C147.469 14.5701 146.776 14.3534 145.946 14.3534C145.15 14.3534 144.474 14.5632 143.918 14.9829C143.362 15.4025 142.94 15.9907 142.652 16.7474C142.371 17.5041 142.23 18.395 142.23 19.42Z\" fill=\"#26282A\"/><path d=\"M127.352 27.6649C126.35 27.6649 125.448 27.486 124.645 27.1283C123.849 26.7637 123.218 26.2271 122.751 25.5185C122.291 24.81 122.062 23.9363 122.062 22.8975C122.062 22.0032 122.226 21.2637 122.556 20.6789C122.885 20.0942 123.334 19.6264 123.904 19.2756C124.473 18.9247 125.115 18.6599 125.829 18.481C126.549 18.2953 127.293 18.1611 128.062 18.0786C128.988 17.9823 129.74 17.8963 130.316 17.8206C130.892 17.738 131.311 17.6142 131.572 17.4491C131.839 17.2771 131.973 17.0123 131.973 16.6545V16.5926C131.973 15.8153 131.743 15.2133 131.284 14.7868C130.824 14.3603 130.162 14.147 129.297 14.147C128.384 14.147 127.661 14.3465 127.125 14.7455C126.597 15.1445 126.24 15.6158 126.055 16.1592L122.576 15.6639C122.851 14.7008 123.303 13.896 123.935 13.2493C124.566 12.5958 125.338 12.1073 126.251 11.784C127.163 11.4538 128.172 11.2887 129.276 11.2887C130.038 11.2887 130.796 11.3781 131.551 11.557C132.306 11.7359 132.995 12.0317 133.62 12.4444C134.244 12.8503 134.745 13.4041 135.123 14.1058C135.507 14.8075 135.699 15.6846 135.699 16.7371V27.345H132.117V25.1677H131.994C131.767 25.608 131.448 26.0207 131.036 26.406C130.632 26.7843 130.12 27.0904 129.503 27.3243C128.892 27.5514 128.175 27.6649 127.352 27.6649ZM128.319 24.92C129.067 24.92 129.716 24.7721 130.265 24.4763C130.813 24.1736 131.235 23.7746 131.531 23.2793C131.832 22.784 131.983 22.244 131.983 21.6592V19.7915C131.867 19.8878 131.668 19.9773 131.386 20.0598C131.112 20.1424 130.803 20.2146 130.46 20.2765C130.117 20.3384 129.777 20.3934 129.441 20.4416C129.105 20.4898 128.813 20.531 128.566 20.5654C128.011 20.6411 127.513 20.7649 127.074 20.9369C126.635 21.1089 126.288 21.3497 126.034 21.6592C125.781 21.9619 125.654 22.354 125.654 22.8356C125.654 23.5235 125.904 24.0429 126.405 24.3938C126.906 24.7446 127.544 24.92 128.319 24.92Z\" fill=\"#26282A\"/><path d=\"M97.6602 27.345V11.4951H101.221V14.1883H101.407C101.736 13.2803 102.281 12.5717 103.043 12.0626C103.805 11.5467 104.714 11.2887 105.771 11.2887C106.841 11.2887 107.743 11.5501 108.477 12.0729C109.219 12.5889 109.74 13.294 110.042 14.1883H110.207C110.557 13.3078 111.147 12.6061 111.977 12.0833C112.814 11.5535 113.805 11.2887 114.951 11.2887C116.406 11.2887 117.593 11.7496 118.513 12.6714C119.432 13.5933 119.892 14.9382 119.892 16.7061V27.345H116.156V17.284C116.156 16.3003 115.895 15.5814 115.373 15.1273C114.852 14.6664 114.214 14.436 113.459 14.436C112.56 14.436 111.857 14.718 111.349 15.2821C110.848 15.8394 110.598 16.5651 110.598 17.4594V27.345H106.944V17.1292C106.944 16.3106 106.697 15.6571 106.203 15.1686C105.716 14.6802 105.078 14.436 104.288 14.436C103.753 14.436 103.266 14.5736 102.827 14.8487C102.388 15.117 102.038 15.4988 101.777 15.9941C101.516 16.4826 101.386 17.0535 101.386 17.7071V27.345H97.6602Z\" fill=\"#26282A\"/><path d=\"M80.416 33.2887V11.4951H84.0801V14.1161H84.2962C84.4884 13.7308 84.7594 13.3215 85.1093 12.8881C85.4593 12.4479 85.9327 12.0729 86.5297 11.7634C87.1267 11.4469 87.8883 11.2887 88.8146 11.2887C90.036 11.2887 91.1373 11.6017 92.1185 12.2277C93.1065 12.8469 93.8888 13.7652 94.4651 14.9829C95.0484 16.1936 95.34 17.6796 95.34 19.4407C95.34 21.1811 95.0552 22.6602 94.4857 23.8778C93.9162 25.0955 93.1408 26.0242 92.1596 26.6639C91.1784 27.3037 90.0668 27.6236 88.8249 27.6236C87.9192 27.6236 87.1678 27.4722 86.5709 27.1696C85.9739 26.8669 85.4936 26.5023 85.1299 26.0757C84.7731 25.6424 84.4952 25.233 84.2962 24.8478H84.1419V33.2887H80.416ZM84.0698 19.42C84.0698 20.445 84.2139 21.3428 84.5021 22.1133C84.7971 22.8838 85.2191 23.4857 85.7681 23.9191C86.3238 24.3456 86.9963 24.5589 87.7854 24.5589C88.6088 24.5589 89.2983 24.3387 89.8541 23.8985C90.4099 23.4513 90.8285 22.8425 91.1098 22.072C91.398 21.2946 91.5421 20.4106 91.5421 19.42C91.5421 18.4363 91.4014 17.5626 91.1201 16.799C90.8388 16.0354 90.4202 15.4369 89.8644 15.0035C89.3086 14.5701 88.6156 14.3534 87.7854 14.3534C86.9894 14.3534 86.3136 14.5632 85.7578 14.9829C85.202 15.4025 84.78 15.9907 84.4918 16.7474C84.2105 17.5041 84.0698 18.395 84.0698 19.42Z\" fill=\"#26282A\"/><path d=\"M69.1921 27.6649C68.1904 27.6649 67.2881 27.486 66.4852 27.1283C65.6893 26.7637 65.058 26.2271 64.5914 25.5185C64.1317 24.81 63.9019 23.9363 63.9019 22.8975C63.9019 22.0032 64.0665 21.2637 64.3959 20.6789C64.7252 20.0942 65.1747 19.6264 65.7442 19.2756C66.3137 18.9247 66.9553 18.6599 67.6689 18.481C68.3893 18.2953 69.1338 18.1611 69.9023 18.0786C70.8286 17.9823 71.58 17.8963 72.1564 17.8206C72.7327 17.738 73.1513 17.6142 73.412 17.4491C73.6796 17.2771 73.8134 17.0123 73.8134 16.6545V16.5926C73.8134 15.8153 73.5836 15.2133 73.1238 14.7868C72.6641 14.3603 72.002 14.147 71.1374 14.147C70.2248 14.147 69.5009 14.3465 68.9657 14.7455C68.4374 15.1445 68.0806 15.6158 67.8953 16.1592L64.4165 15.6639C64.6909 14.7008 65.1438 13.896 65.7751 13.2493C66.4063 12.5958 67.1783 12.1073 68.0909 11.784C69.0034 11.4538 70.0121 11.2887 71.1168 11.2887C71.8785 11.2887 72.6367 11.3781 73.3914 11.557C74.1462 11.7359 74.8358 12.0317 75.4602 12.4444C76.0846 12.8503 76.5855 13.4041 76.9629 14.1058C77.3471 14.8075 77.5393 15.6846 77.5393 16.7371V27.345H73.9575V25.1677H73.834C73.6076 25.608 73.2885 26.0207 72.8768 26.406C72.472 26.7843 71.9608 27.0904 71.3433 27.3243C70.7326 27.5514 70.0155 27.6649 69.1921 27.6649ZM70.1596 24.92C70.9075 24.92 71.556 24.7721 72.1049 24.4763C72.6538 24.1736 73.0758 23.7746 73.3709 23.2793C73.6728 22.784 73.8237 22.244 73.8237 21.6592V19.7915C73.7071 19.8878 73.5081 19.9773 73.2268 20.0598C72.9523 20.1424 72.6435 20.2146 72.3004 20.2765C71.9574 20.3384 71.6177 20.3934 71.2815 20.4416C70.9453 20.4898 70.6537 20.531 70.4066 20.5654C69.8509 20.6411 69.3534 20.7649 68.9143 20.9369C68.4751 21.1089 68.1286 21.3497 67.8747 21.6592C67.6208 21.9619 67.4939 22.354 67.4939 22.8356C67.4939 23.5235 67.7443 24.0429 68.2452 24.3938C68.7461 24.7446 69.3843 24.92 70.1596 24.92Z\" fill=\"#26282A\"/><path d=\"M39.5 27.345V11.4951H43.0612V14.1883H43.2464C43.5758 13.2803 44.1213 12.5717 44.8829 12.0626C45.6446 11.5467 46.5537 11.2887 47.6104 11.2887C48.6808 11.2887 49.5831 11.5501 50.3173 12.0729C51.0584 12.5889 51.5798 13.294 51.8817 14.1883H52.0464C52.3964 13.3078 52.9865 12.6061 53.8167 12.0833C54.6538 11.5535 55.6453 11.2887 56.7912 11.2887C58.2459 11.2887 59.4329 11.7496 60.3524 12.6714C61.2718 13.5933 61.7316 14.9382 61.7316 16.7061V27.345H57.9954V17.284C57.9954 16.3003 57.7347 15.5814 57.2132 15.1273C56.6917 14.6664 56.0536 14.436 55.2988 14.436C54.3999 14.436 53.6966 14.718 53.1889 15.2821C52.688 15.8394 52.4375 16.5651 52.4375 17.4594V27.345H48.7837V17.1292C48.7837 16.3106 48.5367 15.6571 48.0427 15.1686C47.5555 14.6802 46.9174 14.436 46.1283 14.436C45.5931 14.436 45.1059 14.5736 44.6668 14.8487C44.2276 15.117 43.8777 15.4988 43.617 15.9941C43.3562 16.4826 43.2258 17.0535 43.2258 17.7071V27.345H39.5Z\" fill=\"#26282A\"/><path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/><path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/><path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/></svg>';\n\nconst DEFAULT_HREF = \"https://mapmap.ai\";\n\n/**\n * A MapLibre `IControl` rendering the MapMap wordmark. Typed structurally\n * (`onAdd`/`onRemove`) so it needs no maplibre-gl import and works with\n * any instance the host app bundles.\n */\nexport class LogoControl {\n private container: HTMLElement | undefined;\n private readonly href: string;\n\n constructor(options: LogoOptions = {}) {\n this.href = options.href ?? DEFAULT_HREF;\n }\n\n onAdd(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"LogoControl requires a DOM environment\");\n const link = doc.createElement(\"a\");\n link.className = \"maplibregl-ctrl mapmap-logo\";\n link.href = this.href;\n link.target = \"_blank\";\n link.rel = \"noopener\";\n link.setAttribute(\"aria-label\", \"MapMap\");\n link.style.cssText =\n \"display:block;line-height:0;margin:0 8px 4px 8px;opacity:0.9;pointer-events:auto\";\n // LOGO_SVG is a compile-time constant, parsed rather than assigned to\n // innerHTML so no HTML-injection surface exists even if it changes.\n const svg = new DOMParser().parseFromString(LOGO_SVG, \"image/svg+xml\").documentElement;\n link.appendChild(doc.importNode(svg, true));\n this.container = link;\n return link;\n }\n\n onRemove(): void {\n this.container?.remove();\n this.container = undefined;\n }\n}\n","/**\n * Studio navigation-design block (`extra.nav`) - types, defaults and parser.\n *\n * MapMap Studio's Navigation panel designs the turn-by-turn look - route\n * line, current-position puck and banner instruction - and stores the result\n * as a small design-token block under `extra.nav` in the theme JSON it\n * downloads/copies. This module reads that block so the same theme file\n * styles real navigation UI: `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` all accept a design from it.\n *\n * LOCKSTEP: this file mirrors `website/lib/studio-nav.ts` (the Studio\n * reference parser) - identical interfaces, defaults, clamps and URL rules.\n * Keep the two in sync so a theme previews in Studio exactly as the SDK\n * renders it. Not imported from the website because the packages do not\n * depend on each other.\n *\n * PUBLISH NOTE: the block travels with the THEME DOCUMENT, never with the\n * compiled `style.json`. That includes hosted publishing: the canonical\n * `sn_style` crate stores `extra` verbatim (bounded at 256 KB serialised)\n * and the gateway serves it back from `GET /styles/{id}/theme`, so a design\n * survives Studio's publish flow too. Read it from a theme file you pass to\n * `createMap` / `buildStyle`, or fetch it from a hosted style with\n * {@link navDesignFromThemeUrl} — a compiled style URL alone never carries\n * it.\n */\nimport type { Theme } from \"./style.js\";\n\n/** Route-line tokens (defaults match {@link RouteLayer}'s built-in look). */\nexport interface NavRouteDesign {\n /** Line colour. Default is MapMap signal blue (`SIGNAL_BLUE`). */\n color: string;\n /** Line width in px at mid zoom. */\n width: number;\n /** Line opacity, 0-1. */\n opacity: number;\n /** Casing (outline) colour drawn under the line. */\n casingColor: string;\n /**\n * Casing width in px. Defaults to `width + 4`.\n *\n * Optional because the casing was previously always `width + 4`, which\n * cannot express a design whose casing is not exactly four wider than\n * its line (the playground's is 9 over a 4.5 line).\n */\n casingWidth?: number;\n /**\n * Casing opacity, 0-1. Defaults to {@link NavRouteDesign.opacity}.\n *\n * Optional because casing and line previously shared one opacity, which\n * cannot express a translucent casing under a solid line.\n */\n casingOpacity?: number;\n /**\n * Line dash pattern, in line-widths, as MapLibre's `line-dasharray`.\n * Omitted or `null` draws a solid line.\n */\n dash?: number[] | null;\n}\n\n/** Current-position puck tokens. */\nexport interface NavPuckDesign {\n /** Puck fill colour. */\n color: string;\n /** Puck diameter in px. */\n size: number;\n /** Whether the heading arrow is drawn on the puck. */\n headingArrow: boolean;\n /**\n * Optional custom puck image (`https:` or `data:` URI, PNG/SVG). When set\n * it replaces the built-in dot + arrow; `size` still scales it. Optional\n * since v1 - themes saved without it load unchanged.\n */\n imageUrl?: string;\n}\n\n/** Banner-instruction tokens (defaults match {@link GuidanceBanner}). */\nexport interface NavBannerDesign {\n /** Banner background colour. */\n background: string;\n /** Banner text (and arrow) colour. */\n textColor: string;\n /** Primary text size in px. */\n fontSize: number;\n /** Whether the lane diagram row is shown when lanes are present. */\n showLanes: boolean;\n /** Inner padding in px, 6-24. Optional since v1; default 10. */\n padding?: number;\n /** Corner radius in px, 0-24. Optional since v1; default 10. */\n cornerRadius?: number;\n /** Maximum banner width in px, 200-520. Optional since v1; default 340. */\n maxWidth?: number;\n /**\n * Banner height in px, 40-120. Optional since v1; unset means auto -\n * the banner takes its natural content height (old themes keep theirs).\n */\n height?: number;\n}\n\n/**\n * Drive-camera tokens: how the chase cam frames a turn-by-turn drive.\n * The whole block is optional since v1 - themes saved without it load\n * unchanged and the SDK keeps its built-in framing. Every field is itself\n * optional (absent = the documented default). `NavigationCamera` reads\n * `pitch`/`zoom` as its option defaults; `speedMps` drives Studio's demo\n * drive (and any route simulator) - a camera following real GPS fixes\n * ignores it.\n */\nexport interface NavCameraDesign {\n /** Chase-cam tilt in degrees, 0-85. Default 60. */\n pitch?: number;\n /** Chase-cam zoom, 14-20. Default 17.5. */\n zoom?: number;\n /** Drive speed in metres per second, 2-40. Default 12 (~43 km/h). */\n speedMps?: number;\n}\n\n/**\n * Defaults for the optional `camera` block. LOCKSTEP: mirrors\n * `NAV_CAMERA_DEFAULTS` in `website/lib/studio-nav.ts`.\n */\nexport const NAV_CAMERA_DEFAULTS = {\n pitch: 60,\n zoom: 17.5,\n speedMps: 12,\n} as const;\n\n/**\n * Safety-camera kinds a design can style, matching the kind the data model\n * already carries per camera. LOCKSTEP: mirrors `NAV_CAMERA_KINDS` in\n * `website/lib/studio-nav.ts`.\n *\n * WIRE NOTE: the gateway serialises `sn_safety::CameraKind` lowercase\n * (`fixed` / `average` / `redlight` / `unknown`); `mobile_site` is a\n * product-level kind a host may classify itself (the sidecar deliberately\n * leaves an OSM `speed_camera=mobile` node as `unknown` rather than\n * overclaiming a fixed installation). Normalise a wire value with\n * {@link navCameraKind} before indexing a design.\n */\nexport const NAV_CAMERA_KINDS = [\n \"fixed\",\n \"average\",\n \"red_light\",\n \"mobile_site\",\n \"unknown\",\n] as const;\n\n/** One safety-camera kind. */\nexport type NavCameraKind = (typeof NAV_CAMERA_KINDS)[number];\n\n/**\n * Normalises a camera kind from the wire (or any host classifier) onto a\n * {@link NavCameraKind}. Unrecognised values become `\"unknown\"`, never a\n * guess: a mislabelled camera would alert a driver about the wrong thing.\n */\nexport function navCameraKind(value: unknown): NavCameraKind {\n if (typeof value !== \"string\") return \"unknown\";\n switch (value.trim().toLowerCase()) {\n case \"fixed\":\n case \"permanent\":\n return \"fixed\";\n case \"average\":\n case \"average_speed\":\n case \"section\":\n case \"section_control\":\n return \"average\";\n case \"red_light\":\n case \"redlight\":\n case \"traffic_signals\":\n return \"red_light\";\n case \"mobile\":\n case \"mobile_site\":\n return \"mobile_site\";\n default:\n return \"unknown\";\n }\n}\n\n/** Curated icon sets a design can pick for the alert chip and map pins. */\nexport const NAV_ALERT_ICON_SETS = [\"european\", \"us\", \"minimal\", \"brand\"] as const;\n\n/** One curated icon set. `\"brand\"` means \"use my `iconUrlOverrides`\". */\nexport type NavAlertIconSet = (typeof NAV_ALERT_ICON_SETS)[number];\n\n/**\n * When a kind alerts AUDIBLY while driving.\n *\n * The visual chip is governed by `alertWhileDriving` and is deliberately\n * unconditional and calm; audio is the escalation channel (the shipping\n * model: the pop-up always appears, the sound only when the driver is over\n * the limit). UI labels must describe the behaviour - \"Always alert\",\n * \"Warn if speeding\", \"Never alert\" - and must never say \"Auto\", which\n * Organic Maps relabelled after users could not tell what it did.\n */\nexport const NAV_ALERT_MODES = [\"always\", \"whenSpeeding\", \"never\"] as const;\n\n/** One alert mode. */\nexport type NavAlertMode = (typeof NAV_ALERT_MODES)[number];\n\n/**\n * Audio channel for a kind: silent, a non-verbal earcon, or an earcon\n * followed by speech naming the kind. Kind is carried in the ICON and in\n * SPEECH, never in the earcon's identity - urgency lives in timbre, so the\n * escalated state is the same motif made more insistent, not a new sound.\n */\nexport const NAV_ALERT_AUDIO_MODES = [\"off\", \"earcon\", \"earcon_and_speech\"] as const;\n\n/** One audio mode. */\nexport type NavAlertAudioMode = (typeof NAV_ALERT_AUDIO_MODES)[number];\n\n/**\n * The built-in earcon library, as a curated enum rather than a free URL.\n *\n * A design picks ONE sound for the calm alert and ONE for its escalated\n * variant - never one per camera kind. Kind is carried by the icon and by\n * speech; urgency is carried by timbre, so the escalated state is the same\n * motif made more insistent. Per-kind sounds would ask a driver to learn\n * five timbres at 70 mph, which no shipping product does.\n *\n * `zoneEnter` / `zoneClear` are the average-speed corridor pair a host\n * plays at the entry and exit of a corridor. They are offered here too so\n * a design can borrow their timbre, but the corridor itself always uses\n * the pair - it is a boundary crossing, not a point alert.\n */\nexport const NAV_ALERT_SOUNDS = [\n \"cameraCalm\",\n \"cameraUrgent\",\n \"overspeedSoft\",\n \"zoneEnter\",\n \"zoneClear\",\n] as const;\n\n/** One built-in earcon. */\nexport type NavAlertSound = (typeof NAV_ALERT_SOUNDS)[number];\n\n/**\n * File name of each built-in earcon, relative to\n * {@link NAV_ALERT_SOUND_BASE_URL}. Mono, ~0.5-0.9 s, mixed dry with no\n * reverb tail so they stay crisp over road noise and never trail into the\n * spoken instruction that follows.\n */\nexport const NAV_ALERT_SOUND_FILES: Record<NavAlertSound, string> = {\n cameraCalm: \"earcon-camera-calm.mp3\",\n cameraUrgent: \"earcon-camera-urgent.mp3\",\n overspeedSoft: \"earcon-overspeed-soft.mp3\",\n zoneEnter: \"earcon-zone-enter.mp3\",\n zoneClear: \"earcon-zone-clear.mp3\",\n};\n\n/**\n * Where the built-in earcons are hosted. Public, unmetered and immutable\n * (the files are content-stable; a new sound gets a new name). Pass your\n * own base to {@link navAlertSoundUrl} to self-host them - the SDK bundles\n * no audio, exactly like `VoiceGuidance`'s earcon URLs.\n */\nexport const NAV_ALERT_SOUND_BASE_URL = \"https://mapmap.ai/earcons/\";\n\n/**\n * Absolute URL for a built-in earcon. An unrecognised value falls back to\n * `cameraCalm` rather than returning nothing: a missing alert sound is a\n * silent failure a driver cannot see.\n */\nexport function navAlertSoundUrl(\n sound: unknown,\n baseUrl: string = NAV_ALERT_SOUND_BASE_URL,\n): string {\n const name = (NAV_ALERT_SOUNDS as readonly string[]).includes(sound as string)\n ? (sound as NavAlertSound)\n : \"cameraCalm\";\n return `${baseUrl.replace(/\\/*$/, \"/\")}${NAV_ALERT_SOUND_FILES[name]}`;\n}\n\n/** Lead-distance presets. Not a free number: see {@link NAV_ALERT_LEAD_DISTANCE_M}. */\nexport const NAV_ALERT_LEAD_DISTANCES = [\"short\", \"standard\", \"long\"] as const;\n\n/** One lead-distance preset. */\nexport type NavAlertLeadDistance = (typeof NAV_ALERT_LEAD_DISTANCES)[number];\n\n/**\n * Metres before the camera at which the alert may first appear, per preset.\n * These are FLOORS, not targets: a host may announce earlier (a motorway\n * closing speed eats 400 m in nine seconds) but never later. Exposed as an\n * enum rather than a numeric field precisely so no design can set a lead\n * below the safety floor.\n */\nexport const NAV_ALERT_LEAD_DISTANCE_M: Record<NavAlertLeadDistance, number> = {\n short: 150,\n standard: 250,\n long: 400,\n};\n\n/** Metres of lead for a preset (garbage falls back to `standard`). */\nexport function navAlertLeadDistanceM(preset: unknown): number {\n return NAV_ALERT_LEAD_DISTANCE_M[\n (NAV_ALERT_LEAD_DISTANCES as readonly string[]).includes(preset as string)\n ? (preset as NavAlertLeadDistance)\n : \"standard\"\n ];\n}\n\n/**\n * Where the chip sits. Constrained slots, never free x/y: the chip must not\n * occlude the current speed or the limit. Covering exactly the two numbers\n * the alert is telling the driver to act on has been the single\n * most-complained-about defect in the category since 2023, and a free\n * position would let a customer reintroduce it.\n */\nexport const NAV_ALERT_CHIP_POSITIONS = [\"aboveSpeed\", \"topLeading\", \"topTrailing\"] as const;\n\n/** One chip position slot. */\nexport type NavAlertChipPosition = (typeof NAV_ALERT_CHIP_POSITIONS)[number];\n\n/**\n * Per-kind surfaces and channels. The three booleans are orthogonal: a\n * kind can appear on the map without alerting, alert without appearing on\n * the map, or be listed in the route preview only.\n */\nexport interface NavAlertKindDesign {\n /**\n * Draw a pin for this kind while BROWSING the map (no active guidance).\n *\n * Kept as the browse-mode field under its original name so themes saved\n * before the browse/navigate split round-trip unchanged.\n */\n showOnMap: boolean;\n /**\n * Draw a pin for this kind on the map DURING active navigation.\n *\n * Separate from {@link showOnMap} because the two are genuinely\n * different decisions: a fleet product may want a clean driving map and\n * a fully annotated planning map, or the reverse. Defaults to `true`,\n * and absent in an older theme reads as `true` - the market shows\n * cameras with or without a planned route, so gating map display behind\n * guidance would be more restrictive than every product a driver has\n * used.\n */\n showOnMapWhileNavigating: boolean;\n /** Show the alert chip for this kind while driving. */\n alertWhileDriving: boolean;\n /** List this kind in the pre-drive route preview. */\n showInRoutePreview: boolean;\n /** When the AUDIBLE alert fires. The chip itself follows `alertWhileDriving`. */\n alertMode: NavAlertMode;\n /** Which audio channel this kind uses. */\n audioMode: NavAlertAudioMode;\n}\n\n/**\n * Safety-alert tokens (`extra.nav.alerts`): the camera alert chip, its\n * escalated state, per-kind icons and surfaces, and the average-speed\n * corridor highlight.\n *\n * The whole block is optional since v1 - themes saved without it load\n * unchanged and hosts keep their built-in look - but a block that IS\n * present is always complete: every field, including both escalated\n * tokens, parses to a value. The escalated state can be restyled, never\n * removed.\n *\n * Two states only, calm and escalated. There is no amber tier: no shipping\n * navigation product uses a three-colour alert state and drivers have no\n * learned mapping for one.\n *\n * NOT STYLEABLE HERE: whether cameras may be shown at all. That is a\n * server-side jurisdiction policy applied before any camera leaves the\n * gateway. A design styles what the policy permits and nothing more.\n */\nexport interface NavAlertsDesign {\n /** Chip background in the calm (default) state. */\n background: string;\n /** Chip text and icon colour in the calm state. */\n textColor: string;\n /** Chip outline colour (both states). */\n outlineColor: string;\n /** Chip corner radius in px, 0-24. */\n cornerRadius: number;\n /** Chip outline width in px, 0-4. */\n outlineWidth: number;\n /** Chip background when escalated (driver over the limit). */\n escalatedBackground: string;\n /** Chip text and icon colour when escalated. */\n escalatedTextColor: string;\n /** Curated icon set for the chip and map pins. */\n iconSet: NavAlertIconSet;\n /**\n * Per-kind icon overrides (`https:` or `data:` URIs only). Any kind left\n * out keeps `iconSet`'s icon. Absent when no kind is overridden.\n */\n iconUrlOverrides?: Partial<Record<NavCameraKind, string>>;\n /**\n * The earcon played for a calm alert. One sound for the whole design,\n * never one per kind - see {@link NAV_ALERT_SOUNDS}.\n */\n alertSound: NavAlertSound;\n /**\n * Optional replacement for the calm earcon (`https:` or `data:` URIs\n * only, same rule as `iconUrlOverrides`). Absent = the built-in\n * {@link alertSound}.\n */\n alertSoundUrl?: string;\n /**\n * The earcon played when the driver is over the limit. The escalated\n * state is not removable - it can be restyled and its sound chosen, but\n * a design cannot silence the escalation itself (set the kind's\n * `audioMode` to `off` if you want no audio at all).\n */\n escalatedSound: NavAlertSound;\n /** Optional replacement for the escalated earcon; same URL rule. */\n escalatedSoundUrl?: string;\n /** Map pin size as a multiplier of the default ramp, 0.75-1.5. */\n mapIconSize: number;\n /** Lowest zoom at which map pins are drawn, 9-14. */\n mapMinZoom: number;\n /** Lead-distance preset; see {@link NAV_ALERT_LEAD_DISTANCE_M}. */\n leadDistance: NavAlertLeadDistance;\n /** Which constrained slot the chip occupies. */\n chipPosition: NavAlertChipPosition;\n /** Colour of the average-speed corridor highlight on the route line. */\n corridorColor: string;\n /** Corridor highlight opacity, 0-1. */\n corridorOpacity: number;\n /** Per-kind surfaces and channels; always all five kinds. */\n kinds: Record<NavCameraKind, NavAlertKindDesign>;\n}\n\n/** The `extra.nav` block: navigation design tokens for the SDKs. */\nexport interface NavDesign {\n /** Block schema version; currently always 1. */\n version: 1;\n route: NavRouteDesign;\n puck: NavPuckDesign;\n banner: NavBannerDesign;\n /**\n * Optional since v1: drive-camera framing (pitch/zoom) and speed. Absent\n * means \"SDK built-ins\" - the block stays `version: 1` either way.\n */\n camera?: NavCameraDesign;\n /**\n * Optional since v1: safety-alert chip, per-kind surfaces and corridor\n * highlight. Absent means \"SDK built-ins\"; the block stays `version: 1`.\n */\n alerts?: NavAlertsDesign;\n}\n\n/**\n * Defaults for the optional `alerts` block. LOCKSTEP: mirrors\n * `defaultNavAlertsDesign` in `website/lib/studio-nav.ts`.\n *\n * Calm chip = the banner's dark pill, so an unstyled alert already matches\n * the rest of the guidance surface. Escalated = a red that clears 4.5:1\n * against white text.\n *\n * Per-kind defaults follow the \"visual always, audio conditional\" rule:\n * the three confidently classified kinds alert unconditionally, a mobile\n * site (a location where enforcement sometimes happens, not a device)\n * warns only if speeding, and an unclassified camera stays on the map but\n * does not interrupt a drive.\n */\nexport function defaultNavAlertsDesign(): NavAlertsDesign {\n const alertingKind = (\n alertMode: NavAlertMode,\n audioMode: NavAlertAudioMode,\n showInRoutePreview: boolean,\n alertWhileDriving = true,\n ): NavAlertKindDesign => ({\n showOnMap: true,\n showOnMapWhileNavigating: true,\n alertWhileDriving,\n showInRoutePreview,\n alertMode,\n audioMode,\n });\n return {\n background: \"#101418\",\n textColor: \"#ffffff\",\n outlineColor: \"#ffffff\",\n cornerRadius: 10,\n outlineWidth: 1.5,\n escalatedBackground: \"#c0392b\",\n escalatedTextColor: \"#ffffff\",\n iconSet: \"european\",\n alertSound: \"cameraCalm\",\n escalatedSound: \"cameraUrgent\",\n mapIconSize: 1,\n mapMinZoom: 12,\n leadDistance: \"standard\",\n chipPosition: \"aboveSpeed\",\n corridorColor: \"#e05c6c\",\n corridorOpacity: 0.55,\n kinds: {\n fixed: alertingKind(\"always\", \"earcon\", true),\n average: alertingKind(\"always\", \"earcon_and_speech\", true),\n red_light: alertingKind(\"always\", \"earcon\", true),\n mobile_site: alertingKind(\"whenSpeeding\", \"earcon\", false),\n unknown: alertingKind(\"whenSpeeding\", \"off\", false, false),\n },\n };\n}\n\n/**\n * Defaults mirror what the SDK draws today with no design: `RouteLayer`'s\n * signal-blue line over a dark casing, and `GuidanceBanner`'s dark pill.\n */\nexport function defaultNavDesign(): NavDesign {\n return {\n version: 1,\n route: { color: \"#3a86ff\", width: 4.5, opacity: 1, casingColor: \"#1f438a\" },\n puck: { color: \"#1f6fff\", size: 14, headingArrow: true },\n banner: {\n background: \"#101418\",\n textColor: \"#ffffff\",\n fontSize: 16,\n showLanes: true,\n padding: 10,\n cornerRadius: 10,\n maxWidth: 340,\n },\n };\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction str(v: unknown, fallback: string): string {\n return typeof v === \"string\" && v.trim() !== \"\" ? v : fallback;\n}\n\nfunction num(v: unknown, fallback: number, min: number, max: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : fallback;\n}\n\n/** Optional clamped number: absent/malformed stays `undefined` (= auto). */\nfunction optNum(v: unknown, min: number, max: number): number | undefined {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : undefined;\n}\n\nfunction bool(v: unknown, fallback: boolean): boolean {\n return typeof v === \"boolean\" ? v : fallback;\n}\n\n/**\n * Optional puck-image URL: only `https:` or `data:` URIs are accepted;\n * anything else (including absence) yields `undefined` - the built-in puck.\n */\nfunction puckImageUrl(v: unknown): string | undefined {\n return assetUrl(v);\n}\n\n/** Same URL rule as {@link puckImageUrl}, for alert icon overrides. */\nfunction iconUrl(v: unknown): string | undefined {\n return assetUrl(v);\n}\n\n/**\n * The one asset-URL rule the whole block uses: only `https:` or `data:`\n * URIs are accepted, so a theme can never point a driver-facing surface at\n * plaintext `http:`, a `javascript:` payload or a `file:` path. Anything\n * else (including absence) yields `undefined` - the built-in asset.\n */\nfunction assetUrl(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n return /^(https:|data:)/i.test(t) ? t : undefined;\n}\n\n/** One of `allowed`, or `fallback` for anything else (including absence). */\nfunction oneOf<T extends string>(v: unknown, allowed: readonly T[], fallback: T): T {\n return typeof v === \"string\" && (allowed as readonly string[]).includes(v) ? (v as T) : fallback;\n}\n\n/** Lenient parse of one kind's surfaces and channels. */\nfunction parseNavAlertKind(value: unknown, d: NavAlertKindDesign): NavAlertKindDesign {\n const k = isRecord(value) ? value : {};\n return {\n showOnMap: bool(k.showOnMap, d.showOnMap),\n showOnMapWhileNavigating: bool(k.showOnMapWhileNavigating, d.showOnMapWhileNavigating),\n alertWhileDriving: bool(k.alertWhileDriving, d.alertWhileDriving),\n showInRoutePreview: bool(k.showInRoutePreview, d.showInRoutePreview),\n alertMode: oneOf(k.alertMode, NAV_ALERT_MODES, d.alertMode),\n audioMode: oneOf(k.audioMode, NAV_ALERT_AUDIO_MODES, d.audioMode),\n };\n}\n\n/**\n * Lenient parse of an `extra.nav.alerts` value. Every numeric is clamped,\n * every enum validated, and garbage falls back per field to the defaults -\n * so a hand-edited or older theme can never produce an alert that is\n * unreadable, positioned over the speed readout, or missing its escalated\n * state. The escalated tokens in particular always come back set, even\n * when the input omits or nulls them: a driver-facing escalation is not a\n * removable feature.\n */\nexport function parseNavAlertsDesign(value: unknown): NavAlertsDesign {\n const d = defaultNavAlertsDesign();\n const a = isRecord(value) ? value : {};\n const kindsIn = isRecord(a.kinds) ? a.kinds : {};\n const kinds = {} as Record<NavCameraKind, NavAlertKindDesign>;\n for (const kind of NAV_CAMERA_KINDS) {\n kinds[kind] = parseNavAlertKind(kindsIn[kind], d.kinds[kind]);\n }\n // Icon overrides are dropped entirely when nothing survives validation,\n // so a default design stays free of an empty object (and round-trips).\n const overridesIn = isRecord(a.iconUrlOverrides) ? a.iconUrlOverrides : {};\n const iconUrlOverrides: Partial<Record<NavCameraKind, string>> = {};\n for (const kind of NAV_CAMERA_KINDS) {\n const url = iconUrl(overridesIn[kind]);\n if (url !== undefined) iconUrlOverrides[kind] = url;\n }\n // Sound overrides follow the icon-override rule exactly: only `https:`\n // or `data:` URIs survive, and a rejected one silently falls back to the\n // chosen built-in rather than leaving the alert mute.\n const alertSoundUrl = assetUrl(a.alertSoundUrl);\n const escalatedSoundUrl = assetUrl(a.escalatedSoundUrl);\n return {\n background: str(a.background, d.background),\n textColor: str(a.textColor, d.textColor),\n outlineColor: str(a.outlineColor, d.outlineColor),\n cornerRadius: num(a.cornerRadius, d.cornerRadius, 0, 24),\n outlineWidth: num(a.outlineWidth, d.outlineWidth, 0, 4),\n escalatedBackground: str(a.escalatedBackground, d.escalatedBackground),\n escalatedTextColor: str(a.escalatedTextColor, d.escalatedTextColor),\n iconSet: oneOf(a.iconSet, NAV_ALERT_ICON_SETS, d.iconSet),\n ...(Object.keys(iconUrlOverrides).length > 0 ? { iconUrlOverrides } : {}),\n alertSound: oneOf(a.alertSound, NAV_ALERT_SOUNDS, d.alertSound),\n ...(alertSoundUrl !== undefined ? { alertSoundUrl } : {}),\n escalatedSound: oneOf(a.escalatedSound, NAV_ALERT_SOUNDS, d.escalatedSound),\n ...(escalatedSoundUrl !== undefined ? { escalatedSoundUrl } : {}),\n mapIconSize: num(a.mapIconSize, d.mapIconSize, 0.75, 1.5),\n mapMinZoom: num(a.mapMinZoom, d.mapMinZoom, 9, 14),\n leadDistance: oneOf(a.leadDistance, NAV_ALERT_LEAD_DISTANCES, d.leadDistance),\n chipPosition: oneOf(a.chipPosition, NAV_ALERT_CHIP_POSITIONS, d.chipPosition),\n corridorColor: str(a.corridorColor, d.corridorColor),\n corridorOpacity: num(a.corridorOpacity, d.corridorOpacity, 0, 1),\n kinds,\n };\n}\n\n/**\n * Lenient parse of an `extra.nav` value: unknown or malformed fields fall\n * back to the defaults, so an imported theme never fails on its nav block.\n * LOCKSTEP: identical semantics to `parseNavDesign` in\n * `website/lib/studio-nav.ts` (same clamps, same fallbacks).\n */\nexport function parseNavDesign(value: unknown): NavDesign {\n const d = defaultNavDesign();\n if (!isRecord(value)) return d;\n const route = isRecord(value.route) ? value.route : {};\n const puck = isRecord(value.puck) ? value.puck : {};\n const banner = isRecord(value.banner) ? value.banner : {};\n return {\n version: 1,\n route: {\n color: str(route.color, d.route.color),\n width: num(route.width, d.route.width, 0.5, 20),\n opacity: num(route.opacity, d.route.opacity, 0, 1),\n casingColor: str(route.casingColor, d.route.casingColor),\n },\n puck: {\n color: str(puck.color, d.puck.color),\n size: num(puck.size, d.puck.size, 6, 40),\n headingArrow: bool(puck.headingArrow, d.puck.headingArrow),\n imageUrl: puckImageUrl(puck.imageUrl),\n },\n banner: {\n background: str(banner.background, d.banner.background),\n textColor: str(banner.textColor, d.banner.textColor),\n fontSize: num(banner.fontSize, d.banner.fontSize, 10, 32),\n showLanes: bool(banner.showLanes, d.banner.showLanes),\n padding: num(banner.padding, d.banner.padding ?? 10, 6, 24),\n cornerRadius: num(banner.cornerRadius, d.banner.cornerRadius ?? 10, 0, 24),\n maxWidth: num(banner.maxWidth, d.banner.maxWidth ?? 340, 200, 520),\n height: optNum(banner.height, 40, 120),\n },\n // Camera is optional since v1: absent (or malformed) stays undefined so\n // old themes round-trip byte-identical; a present block clamps per\n // field, each absent field meaning \"use the default\".\n ...(isRecord(value.camera)\n ? {\n camera: {\n pitch: optNum(value.camera.pitch, 0, 85),\n zoom: optNum(value.camera.zoom, 14, 20),\n speedMps: optNum(value.camera.speedMps, 2, 40),\n },\n }\n : {}),\n // Alerts is optional since v1 on the same terms as camera: absent (or\n // malformed) stays undefined so old themes round-trip byte-identical.\n // Unlike camera, a PRESENT block always parses complete - every field\n // filled from the defaults - because half an alert design is a safety\n // defect, not a partial style.\n ...(isRecord(value.alerts) ? { alerts: parseNavAlertsDesign(value.alerts) } : {}),\n };\n}\n\n/**\n * Reads and parses the `extra.nav` block from a Studio theme document.\n * Returns `undefined` when the theme carries no nav block at all (so\n * callers can tell \"no design\" apart from \"default design\"); a present but\n * malformed block parses leniently to the defaults.\n */\nexport function navDesignFromTheme(theme: Theme | undefined | null): NavDesign | undefined {\n const extra = theme?.extra;\n if (typeof extra !== \"object\" || extra === null || !(\"nav\" in extra)) {\n return undefined;\n }\n return parseNavDesign((extra as { nav?: unknown }).nav);\n}\n\n/**\n * Fetches a hosted theme document and reads its `extra.nav` block.\n *\n * Point it at the gateway's theme endpoint - the design a Studio publish\n * stores alongside the compiled style:\n *\n * ```ts\n * const design = await navDesignFromThemeUrl(\n * \"https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme\",\n * );\n * ```\n *\n * The endpoint is public (no API key) and never cached, so this always\n * reflects the latest published version. Returns `undefined` when the\n * theme carries no nav block (same contract as {@link navDesignFromTheme});\n * throws on network failure, a non-2xx response or a non-JSON body.\n *\n * @param fetchImpl Optional `fetch` replacement (tests, Node polyfills).\n * Defaults to the global `fetch`.\n */\nexport async function navDesignFromThemeUrl(\n url: string,\n fetchImpl?: typeof fetch,\n): Promise<NavDesign | undefined> {\n // Wrap rather than alias the global so browsers keep their `this` binding.\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL) => globalThis.fetch(input));\n const response = await doFetch(url);\n if (!response.ok) {\n throw new Error(`fetching theme ${url}: HTTP ${response.status}`);\n }\n const theme = (await response.json()) as Theme;\n return navDesignFromTheme(theme);\n}\n","/**\n * Studio POI category-design block (`extra.poi`) - types, defaults, parser\n * and appliers.\n *\n * MapMap Studio's POIs panel colours the ~8 POI categories - the coloured\n * category dot drawn under a POI label, and the `poi-labels` text colour -\n * and stores the result as a small design-token block under `extra.poi` in\n * the theme JSON it downloads/copies/publishes, exactly like the navigation\n * design under `extra.nav` (see nav-design.ts). This module reads that\n * block and applies the label-text part to a live MapLibre map; the dot\n * images themselves are runtime-rasterised by their host (the MapMap\n * website today - sprite-based icons arrive with marker packs).\n *\n * LOCKSTEP: this file mirrors `website/lib/studio-poi.ts` (the Studio\n * reference parser) - identical category ids, built-in colours, leniency\n * and expression building. The class->category mapping mirrors\n * `website/lib/poi-icons.ts` (`POI_CLASS_CATEGORIES`). Keep them in sync so\n * a theme previews in Studio exactly as the SDK applies it. Not imported\n * from the website because the packages do not depend on each other.\n *\n * PUBLISH NOTE: the block travels with the THEME DOCUMENT, never with the\n * compiled `style.json`. The canonical `sn_style` crate stores `extra`\n * verbatim (bounded at 256 KB serialised) and the gateway serves it back\n * from `GET /styles/{id}/theme`, so a design survives Studio's publish\n * flow. Read it from a theme file you pass to `createMap` / `buildStyle`,\n * or fetch it from a hosted style with {@link poiDesignFromThemeUrl} - a\n * compiled style URL alone never carries it.\n */\nimport type { Theme } from \"./style.js\";\n\n/** One category's overrides. Both fields optional: absent = built-in. */\nexport interface PoiCategoryDesign {\n /** Dot fill colour (replaces the built-in category brand colour). */\n color?: string;\n /** Label text colour for this category (replaces `textSecondary`). */\n textColor?: string;\n}\n\n/** The `extra.poi` block: POI category design. */\nexport interface PoiDesign {\n /** Block schema version; currently always 1. */\n version: 1;\n /** Overrides by category id; empty = all built-in. */\n categories: Record<string, PoiCategoryDesign>;\n}\n\n/**\n * The valid category ids with their built-in dot colours, in presentation\n * order. LOCKSTEP: mirrors `POI_CATEGORIES` in `website/lib/poi-icons.ts`.\n */\nexport const POI_CATEGORY_COLORS: readonly (readonly [string, string])[] = [\n [\"food_drink\", \"#e8734a\"],\n [\"shopping\", \"#4a90d9\"],\n [\"transport\", \"#3a86ff\"],\n [\"lodging\", \"#9b6dd6\"],\n [\"health\", \"#e05c6c\"],\n [\"culture_leisure\", \"#3aa675\"],\n [\"education\", \"#d9a13a\"],\n [\"services\", \"#7a8699\"],\n];\n\n/** The valid category ids, in presentation order. */\nexport const POI_CATEGORY_IDS: readonly string[] = POI_CATEGORY_COLORS.map(([id]) => id);\n\n/**\n * OpenMapTiles `poi` layer `class` values grouped into the categories\n * above; every class not listed falls through to `services`. LOCKSTEP:\n * mirrors `POI_CLASS_CATEGORIES` in `website/lib/poi-icons.ts`.\n */\nexport const POI_CLASS_CATEGORIES: Record<string, string[]> = {\n food_drink: [\n \"restaurant\",\n \"fast_food\",\n \"cafe\",\n \"bar\",\n \"pub\",\n \"biergarten\",\n \"food_court\",\n \"alcohol_shop\",\n ],\n shopping: [\n \"shop\",\n \"grocery\",\n \"supermarket\",\n \"clothing_store\",\n \"mall\",\n \"department_store\",\n \"convenience\",\n \"bakery\",\n \"marketplace\",\n ],\n transport: [\n \"railway\",\n \"railway_station\",\n \"subway\",\n \"bus\",\n \"bus_station\",\n \"ferry_terminal\",\n \"aerodrome\",\n \"airport\",\n \"airfield\",\n ],\n lodging: [\n \"lodging\",\n \"hotel\",\n \"motel\",\n \"hostel\",\n \"guest_house\",\n \"camp_site\",\n \"caravan_site\",\n \"alpine_hut\",\n ],\n health: [\"hospital\", \"pharmacy\", \"doctors\", \"dentist\", \"veterinary\", \"clinic\"],\n culture_leisure: [\n \"museum\",\n \"theatre\",\n \"cinema\",\n \"attraction\",\n \"park\",\n \"stadium\",\n \"art_gallery\",\n \"zoo\",\n \"swimming_pool\",\n \"golf\",\n \"playground\",\n \"cemetery\",\n \"garden\",\n \"picnic_site\",\n \"viewpoint\",\n ],\n education: [\"school\", \"college\", \"university\", \"library\", \"kindergarten\"],\n services: [\n \"bank\",\n \"post\",\n \"police\",\n \"town_hall\",\n \"place_of_worship\",\n \"courthouse\",\n \"embassy\",\n \"fire_station\",\n \"community_centre\",\n \"toilet\",\n \"telephone\",\n \"atm\",\n ],\n};\n\n/** The built-in dot colour for a category id. */\nexport function builtInPoiColor(categoryId: string): string | undefined {\n return POI_CATEGORY_COLORS.find(([id]) => id === categoryId)?.[1];\n}\n\n/** No overrides: every category keeps its built-in dot and label colours. */\nexport function defaultPoiDesign(): PoiDesign {\n return { version: 1, categories: {} };\n}\n\n/** True when the design changes nothing. */\nexport function poiDesignIsDefault(design: PoiDesign): boolean {\n return Object.keys(design.categories).length === 0;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/**\n * Cheap CSS colour check (hex forms + functional notations), mirroring\n * `isCssColour` in style.ts / `website/lib/studio-style.ts`.\n */\nfunction colour(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n if (t.startsWith(\"#\")) {\n const hex = t.slice(1);\n return [3, 4, 6, 8].includes(hex.length) && /^[0-9a-fA-F]+$/.test(hex) ? t : undefined;\n }\n for (const prefix of [\"rgb(\", \"rgba(\", \"hsl(\", \"hsla(\"]) {\n if (t.startsWith(prefix) && t.endsWith(\")\")) return t;\n }\n return undefined;\n}\n\n/**\n * Lenient parse of an `extra.poi` value: unknown category ids and invalid\n * colours are dropped rather than failing, so an imported theme never\n * breaks on its POI block. LOCKSTEP: identical semantics to\n * `parsePoiDesign` in `website/lib/studio-poi.ts`.\n */\nexport function parsePoiDesign(value: unknown): PoiDesign {\n const design = defaultPoiDesign();\n if (!isRecord(value) || !isRecord(value.categories)) return design;\n for (const id of POI_CATEGORY_IDS) {\n const raw = value.categories[id];\n if (!isRecord(raw)) continue;\n const category: PoiCategoryDesign = {};\n const color = colour(raw.color);\n const textColor = colour(raw.textColor);\n if (color !== undefined) category.color = color;\n if (textColor !== undefined) category.textColor = textColor;\n if (Object.keys(category).length > 0) design.categories[id] = category;\n }\n return design;\n}\n\n/**\n * Reads and parses the `extra.poi` block from a Studio theme document.\n * Returns `undefined` when the theme carries no poi block at all (so\n * callers can tell \"no design\" apart from \"default design\"); a present but\n * malformed block parses leniently to the defaults. Same contract as\n * `navDesignFromTheme`.\n */\nexport function poiDesignFromTheme(theme: Theme | undefined | null): PoiDesign | undefined {\n const extra = theme?.extra;\n if (typeof extra !== \"object\" || extra === null || !(\"poi\" in extra)) {\n return undefined;\n }\n return parsePoiDesign((extra as { poi?: unknown }).poi);\n}\n\n/**\n * Fetches a hosted theme document and reads its `extra.poi` block - point\n * it at the gateway's public, never-cached theme endpoint, e.g.\n * `https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme`. Returns\n * `undefined` when the theme carries no poi block; throws on network\n * failure, a non-2xx response or a non-JSON body. Same contract as\n * {@link navDesignFromThemeUrl}.\n *\n * @param fetchImpl Optional `fetch` replacement (tests, Node polyfills).\n */\nexport async function poiDesignFromThemeUrl(\n url: string,\n fetchImpl?: typeof fetch,\n): Promise<PoiDesign | undefined> {\n // Wrap rather than alias the global so browsers keep their `this` binding.\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL) => globalThis.fetch(input));\n const response = await doFetch(url);\n if (!response.ok) {\n throw new Error(`fetching theme ${url}: HTTP ${response.status}`);\n }\n const theme = (await response.json()) as Theme;\n return poiDesignFromTheme(theme);\n}\n\n/**\n * The `poi-labels` `text-color` value for a design: the plain fallback\n * colour when no category overrides label text, otherwise a `match`\n * expression keyed on the tile's `class` property. Every non-services\n * category always gets an arm (override or fallback) so unmatched classes\n * - the `services` fallback arm - never inherit another category's colour.\n * LOCKSTEP: mirrors `poiTextColorExpression` in `website/lib/studio-poi.ts`.\n */\nexport function poiTextColorExpression(design: PoiDesign, fallback: string): unknown {\n if (!POI_CATEGORY_IDS.some((id) => design.categories[id]?.textColor)) return fallback;\n const arms = POI_CATEGORY_IDS.filter((id) => id !== \"services\").flatMap((id) => [\n POI_CLASS_CATEGORIES[id],\n design.categories[id]?.textColor ?? fallback,\n ]);\n return [\n \"match\",\n [\"get\", \"class\"],\n ...arms,\n design.categories.services?.textColor ?? fallback,\n ];\n}\n\n/** The subset of the MapLibre map surface {@link applyPoiDesign} touches. */\ninterface PoiPaintMap {\n getStyle(): { layers?: { id: string; type?: string }[] } | undefined;\n setPaintProperty(layerId: string, name: string, value: unknown): unknown;\n}\n\n/**\n * Applies a design's per-category label text colours to every `poi-labels`\n * layer on a live map (including per-territory clones named\n * `poi-labels@<territory>`). `fallbackTextColor` is the colour\n * non-overridden categories keep - pass the style's `poi-labels` text\n * colour (the theme's `textSecondary` slot; defaults to the light-base\n * value). A default design restores the plain fallback, so this is safe to\n * call on every design change.\n *\n * NOTE: runtime paint changes do not survive a later `setStyle`; re-apply\n * after style swaps (the MapMap website bakes the expression into the\n * style object instead for exactly this reason).\n */\nexport function applyPoiDesign(\n map: PoiPaintMap,\n design: PoiDesign,\n fallbackTextColor = \"#6b6b6b\",\n): void {\n const value = poiTextColorExpression(design, fallbackTextColor);\n for (const layer of map.getStyle()?.layers ?? []) {\n if (layer.id === \"poi-labels\" || layer.id.startsWith(\"poi-labels@\")) {\n map.setPaintProperty(layer.id, \"text-color\", value);\n }\n }\n}\n","/**\n * MapMap style assembly - pure, browser-free port of the `sn-style` crate.\n *\n * This module mirrors `crates/sn-style` (theme.rs + compile.rs), the\n * canonical MapMap Studio theme engine, so client-side and build-side\n * styles compile identically. A {@link Theme} is a small, agent-friendly\n * JSON document (named palette slots + per-layer overrides) that\n * {@link buildStyle} turns into a full MapLibre style-spec v8 style over\n * the MapMap territory tiles (OpenMapTiles schema, as emitted by\n * `sn-factory`'s Planetiler stage and served as PMTiles).\n *\n * The `pmtiles://` URL prefix is resolved by the pmtiles protocol handler\n * that {@link registerPmtilesProtocol} installs on the MapLibre instance.\n *\n * Attribution: \"© OpenStreetMap contributors\" (ODbL) and \"© OpenMapTiles\"\n * (CC-BY 4.0 schema) are legally required and stamped on every compiled\n * style's tile source. There is no theme field that can remove them.\n */\nimport type { StyleSpecification } from \"maplibre-gl\";\n\n/** A loose JSON object - skeleton layers are assembled as plain JSON. */\ntype JsonObject = Record<string, unknown>;\n\n/** Which built-in palette a theme starts from. */\nexport type MapMapTheme = \"light\" | \"dark\";\n\n/** The OSM attribution string. Legally required (ODbL) - never removed. */\nexport const OSM_ATTRIBUTION = \"© OpenStreetMap contributors\";\n\n/** The OpenMapTiles schema attribution (CC-BY 4.0). */\nexport const OPENMAPTILES_ATTRIBUTION = \"© OpenMapTiles\";\n\n/**\n * Combined attribution stamped on every compiled style's tile source.\n * Legally required (ODbL + CC-BY) - enforced, not themable: no theme\n * field can remove it.\n */\nexport const FULL_ATTRIBUTION = \"© OpenStreetMap contributors © OpenMapTiles\";\n\n/** Default glyph endpoint (PBF fontstacks), mirroring `sn_style::DEFAULT_GLYPHS_URL`. */\nexport const DEFAULT_GLYPHS_URL = \"https://fonts.mapmap.ai/{fontstack}/{range}.pbf\";\n\n/** A sensible default territory tiles URL (overridable per map). */\nexport const DEFAULT_TERRITORY_TILES_URL =\n \"pmtiles://https://tiles.mapmap.ai/planet.pmtiles\";\n\n/**\n * Every source-layer the Planetiler (OpenMapTiles-schema) tiles emit.\n * The style skeleton covers all of them; extra layers referencing anything\n * else are rejected. Mirrors `sn_style::SOURCE_LAYERS`.\n */\nexport const SOURCE_LAYERS: readonly string[] = [\n \"aerodrome_label\",\n \"aeroway\",\n \"boundary\",\n \"building\",\n \"housenumber\",\n \"landcover\",\n \"landuse\",\n \"mountain_peak\",\n \"park\",\n \"place\",\n \"poi\",\n \"transportation\",\n \"transportation_name\",\n \"water\",\n \"water_name\",\n \"waterway\",\n];\n\n/**\n * The named palette slots as `[slot, lightDefault, darkDefault]`, mirroring\n * `sn_style::palette_slots()`. Order is stable and documentation-worthy: it\n * is the order a Studio UI should present them in.\n */\nexport const PALETTE_SLOTS: readonly (readonly [string, string, string])[] = [\n [\"background\", \"#f4f2ee\", \"#12161c\"],\n [\"water\", \"#a8c8e8\", \"#1b2c40\"],\n [\"waterway\", \"#a8c8e8\", \"#1b2c40\"],\n [\"landcover\", \"#e3e8dd\", \"#182029\"],\n [\"landuse\", \"#ece8e1\", \"#171e26\"],\n [\"park\", \"#c8e2bf\", \"#1a2a1f\"],\n [\"building\", \"#e0d6c4\", \"#252d37\"],\n [\"aeroway\", \"#dcd9d2\", \"#232b34\"],\n [\"road\", \"#ffffff\", \"#2b333d\"],\n [\"roadMajor\", \"#f6d9a0\", \"#4a5461\"],\n [\"path\", \"#d9d4ca\", \"#2a323c\"],\n [\"rail\", \"#d0cbc2\", \"#262e37\"],\n [\"boundary\", \"#b9a6c9\", \"#4a3d57\"],\n [\"boundaryMinor\", \"#c9bcd6\", \"#3a3247\"],\n [\"textPrimary\", \"#3a3a3a\", \"#d6dbe1\"],\n [\"textSecondary\", \"#6b6b6b\", \"#9aa3ad\"],\n [\"textHalo\", \"#ffffff\", \"#12161c\"],\n];\n\n/**\n * Per-layer override: merged onto the skeleton layer with the same id.\n * Mirrors `sn_style::LayerOverride`.\n */\nexport interface LayerOverride {\n /** Hide the layer entirely (`layout.visibility = \"none\"`). */\n visible?: boolean;\n /** Paint properties merged over the skeleton's (per-key, override wins). */\n paint?: Record<string, unknown>;\n /** Layout properties merged over the skeleton's. */\n layout?: Record<string, unknown>;\n /** Replace the skeleton's filter (per-attribute styling hook). */\n filter?: unknown;\n minzoom?: number;\n maxzoom?: number;\n}\n\n/**\n * The optional visual-effects block, mirroring `sn_style::Effects`. Unlike\n * `extra`, this IS carried into the compiled style — as\n * `metadata[\"mapmap:effects\"]` — so any consumer of a compiled `style.json`\n * (hosted style URL, baked territory package) can honour it without the\n * theme document. Renderers that do not know the effects engine ignore the\n * metadata and render the style unchanged.\n */\nexport interface ThemeEffects {\n /** Route-line effect: `\"flow\"` (animated energy ribbon) or `\"none\"`. */\n route?: \"flow\" | \"none\";\n /**\n * Effect parameters, validated per effect. For `flow`: `color` (CSS\n * colour), `width` (px, 0.5-40), `speed` (cycles/s, 0-10).\n */\n params?: Record<string, unknown>;\n}\n\n/** The accepted `params` keys for the `flow` effect. */\nconst FLOW_PARAM_KEYS: readonly string[] = [\"color\", \"width\", \"speed\"];\n\n/**\n * Validate a theme's effects block, mirroring\n * `sn_style::theme::validate_effects` (same agent-readable messages).\n */\nfunction validateEffects(effects: ThemeEffects): void {\n const route = effects.route ?? \"none\";\n if (route !== \"flow\" && route !== \"none\") {\n throw new Error(\n `invalid effects block: unknown route effect ${JSON.stringify(route)}; ` +\n 'accepted: \"flow\", \"none\"',\n );\n }\n if (!effects.params) return;\n if (route === \"none\") {\n throw new Error(\n 'invalid effects block: \"params\" requires \"route\" to name an effect (e.g. \"flow\")',\n );\n }\n for (const [key, value] of Object.entries(effects.params)) {\n if (key === \"color\") {\n if (typeof value !== \"string\" || !isCssColour(value)) {\n throw new Error(\n `invalid effects block: params.color has invalid colour ` +\n `${JSON.stringify(value)}; use #rgb/#rrggbb/#rrggbbaa or ` +\n \"rgb()/rgba()/hsl()/hsla()\",\n );\n }\n } else if (key === \"width\") {\n if (typeof value !== \"number\" || value < 0.5 || value > 40) {\n throw new Error(\n \"invalid effects block: params.width must be a number between \" +\n `0.5 and 40 (pixels), got ${JSON.stringify(value)}`,\n );\n }\n } else if (key === \"speed\") {\n if (typeof value !== \"number\" || value < 0 || value > 10) {\n throw new Error(\n \"invalid effects block: params.speed must be a number between \" +\n `0 and 10 (cycles per second), got ${JSON.stringify(value)}`,\n );\n }\n } else {\n throw new Error(\n `invalid effects block: unknown params key ${JSON.stringify(key)}; ` +\n `accepted keys: ${FLOW_PARAM_KEYS.join(\", \")}`,\n );\n }\n }\n}\n\n/**\n * A MapMap Studio theme: the unit users and agents edit, store and publish.\n * Mirrors `sn_style::Theme` (all fields carry serde defaults, so everything\n * is optional here).\n */\nexport interface Theme {\n /** Human-readable theme name, e.g. `\"midnight-fleet\"`. */\n name?: string;\n /** Built-in palette to start from. Defaults to `\"light\"`. */\n base?: MapMapTheme;\n /** Palette overrides by slot name (see {@link PALETTE_SLOTS}). */\n palette?: Record<string, string>;\n /** Per-layer overrides by skeleton layer id. */\n layers?: Record<string, LayerOverride>;\n /**\n * Render buildings as 3D extrusions. Adds a `building-3d` fill-extrusion\n * layer (zoom 15+) driven by the tiles' `render_height` /\n * `render_min_height` attributes, and caps the flat `building` footprint\n * layer at that zoom so the two hand off cleanly (the extrusion rises\n * from flat as you zoom in). Web-safe; native navigation SDKs should\n * leave this off by default until MapLibre Native's fill-extrusion\n * memory use at street zooms is fixed (maplibre-native#4107). Mirrors\n * `Theme::buildings_3d`.\n */\n buildings_3d?: boolean;\n /**\n * Label fonts. Every fontstack must exist on the glyph server; until that\n * ships (P2), leave this at its default (`\"MapMap Sans Regular\"`).\n */\n fonts?: { regular?: string };\n /** Override the glyph endpoint (defaults to {@link DEFAULT_GLYPHS_URL}). */\n glyphs?: string;\n /** Optional sprite URL (icons/shields - P2, no default sprite exists). */\n sprite?: string;\n /**\n * Extra fully-formed MapLibre layers appended above the skeleton (below\n * labels). Each must reference the `territory` source and a known\n * source-layer.\n */\n extra_layers?: JsonObject[];\n /**\n * Optional visual effects (route ribbon etc.). Compiled into\n * `metadata[\"mapmap:effects\"]` on the style — see {@link ThemeEffects}.\n * Mirrors `Theme::effects`.\n */\n effects?: ThemeEffects;\n /**\n * Non-style extras carried by the THEME DOCUMENT, not the compiled\n * style. Studio stores its navigation design block here (`extra.nav`;\n * see `nav-design.ts`) and its POI category design (`extra.poi`; see\n * `poi-design.ts`). {@link buildStyle} ignores it entirely - the\n * compiled `style.json` is byte-identical with or without it. Mirrors\n * `Theme::extra` in the canonical Rust crate: the hosted styles API\n * stores the block verbatim (bounded at 256 KB serialised) and serves it\n * back from `GET /styles/{id}/theme`, so a Studio design survives\n * publishing - consume it via `createMap` with a theme document or\n * `navDesignFromThemeUrl` / `poiDesignFromThemeUrl` with the hosted\n * theme URL.\n */\n extra?: { nav?: unknown; poi?: unknown };\n}\n\nexport interface BuildStyleOptions {\n /**\n * Label language: an ISO 639 code selects `name:<code>` with a\n * local-name fallback; the literal `\"local\"` selects the local name\n * outright; omitted keeps the default (English-first). The tiles carry\n * the OSM `name:*` set, so switching involves no tile rebuild.\n */\n labelLanguage?: string;\n /**\n * Theme to build: a built-in name (`\"light\"` / `\"dark\"`) or a full\n * {@link Theme} document. Defaults to `\"light\"`.\n */\n theme?: MapMapTheme | Theme;\n /**\n * PMTiles URL for the territory tiles. Accepts either a `pmtiles://…` URL\n * or a plain `https://…` URL (the `pmtiles://` prefix is added for you).\n */\n territoryTilesUrl?: string;\n}\n\n/** Ensure a tiles URL carries the `pmtiles://` protocol prefix. */\nexport function toPmtilesUrl(url: string): string {\n return url.startsWith(\"pmtiles://\") ? url : `pmtiles://${url}`;\n}\n\n/**\n * Cheap CSS colour check: hex forms and the functional notations MapLibre\n * accepts. Deliberately permissive on the inside of `rgb()`/`hsl()`.\n * Mirrors `sn_style::theme::is_css_colour`.\n */\nfunction isCssColour(value: string): boolean {\n const v = value.trim();\n if (v.startsWith(\"#\")) {\n const hex = v.slice(1);\n return (\n [3, 4, 6, 8].includes(hex.length) && /^[0-9a-fA-F]+$/.test(hex)\n );\n }\n for (const prefix of [\"rgb(\", \"rgba(\", \"hsl(\", \"hsla(\"]) {\n if (v.startsWith(prefix) && v.endsWith(\")\")) return true;\n }\n return false;\n}\n\n/**\n * Resolve the effective palette for a theme: base defaults + overrides.\n * Fails on unknown slots or unparseable colours (agent self-correction).\n * Mirrors `sn_style::theme::resolve_palette`.\n */\nfunction resolvePalette(theme: Theme): Record<string, string> {\n const base = theme.base ?? \"light\";\n const palette: Record<string, string> = {};\n // Membership is checked against the slot list, not with `in` (which would\n // accept Object.prototype keys like \"toString\" that the Rust compiler\n // rejects as UnknownPaletteSlot).\n const knownSlots = new Set(PALETTE_SLOTS.map(([slot]) => slot));\n for (const [slot, light, dark] of PALETTE_SLOTS) {\n palette[slot] = base === \"dark\" ? dark : light;\n }\n for (const [slot, value] of Object.entries(theme.palette ?? {})) {\n if (!knownSlots.has(slot)) {\n const accepted = PALETTE_SLOTS.map(([s]) => s).join(\", \");\n throw new Error(\n `unknown palette slot ${JSON.stringify(slot)}; accepted slots: ${accepted}`,\n );\n }\n if (!isCssColour(value)) {\n throw new Error(\n `palette slot ${JSON.stringify(slot)} has invalid colour ` +\n `${JSON.stringify(value)}; use #rgb/#rrggbb/#rrggbbaa or ` +\n \"rgb()/rgba()/hsl()/hsla()\",\n );\n }\n palette[slot] = value;\n }\n return palette;\n}\n\n/**\n * Per-channel linear blend of two `#rrggbb` colours: `t` = 0 returns `a`,\n * `t` = 1 returns `b`. Mirrors `compile.rs`'s `mix()`.\n *\n * Used to DERIVE road-casing and building-outline colours from existing\n * palette slots rather than adding new ones — the 17-slot palette is a\n * published contract, and deriving means user overrides flow through\n * automatically. Blending against `textSecondary` (which flips with\n * light/dark themes) keeps the derived edges visible in both for free.\n *\n * Inputs that are not 6-digit hex are returned as-is (`a`), so a theme\n * carrying an exotic colour value degrades to no tint rather than NaN.\n *\n * Exported for tests; deliberately not re-exported from the package index.\n */\nexport function mixColour(a: string, b: string, t: number): string {\n const parse = (s: string): [number, number, number] | null =>\n /^#[0-9a-fA-F]{6}$/.test(s)\n ? [\n parseInt(s.slice(1, 3), 16),\n parseInt(s.slice(3, 5), 16),\n parseInt(s.slice(5, 7), 16),\n ]\n : null;\n const ca = parse(a);\n const cb = parse(b);\n if (!ca || !cb) return a;\n const k = Math.min(1, Math.max(0, t));\n const hex = (i: 0 | 1 | 2): string =>\n Math.min(255, Math.max(0, Math.round(ca[i] + (cb[i] - ca[i]) * k)))\n .toString(16)\n .padStart(2, \"0\");\n return `#${hex(0)}${hex(1)}${hex(2)}`;\n}\n\n/** Skeleton fill layer, mirroring `compile.rs`'s `fill()` helper. */\n\n/**\n * Per-class tint for the `landuse` fill. Mirrors `landuse_colour()` in\n * compile.rs.\n *\n * Landuse was one flat colour, so a hospital campus, a school field and a\n * retail park were visually the same object. The tints are DERIVED from\n * existing palette slots via `mixColour` rather than added as new slots: the\n * palette is a documented 17-slot contract, and a per-class slot explosion\n * would be a breaking change to every saved theme and preset.\n *\n * The `match` input is `[\"get\", \"class\"]` with a default branch, so classes\n * absent from this list (and features with no `class` at all, where `get`\n * yields null) fall through to the untinted slot colour rather than\n * disappearing. Kept deliberately subtle - these are background fills.\n */\nfunction landuseColour(p: (slot: string) => string): unknown[] {\n const base = p(\"landuse\");\n return [\n \"match\",\n [\"get\", \"class\"],\n // Civic/medical: leans towards the building tone.\n [\"hospital\"], mixColour(base, p(\"building\"), 0.55),\n // Education campuses read as semi-green grounds.\n [\"school\", \"university\", \"college\", \"kindergarten\", \"library\"],\n mixColour(base, p(\"park\"), 0.35),\n [\"cemetery\"], mixColour(base, p(\"park\"), 0.6),\n // Sports/play surfaces borrow the park green outright.\n [\"pitch\", \"playground\"], mixColour(base, p(\"park\"), 0.75),\n // Restricted land greys off.\n [\"military\"], mixColour(base, p(\"textSecondary\"), 0.3),\n [\"retail\", \"commercial\"], mixColour(base, p(\"building\"), 0.35),\n [\"residential\", \"suburb\", \"neighbourhood\"], mixColour(base, p(\"building\"), 0.18),\n [\"railway\"], mixColour(base, p(\"textSecondary\"), 0.2),\n base,\n ];\n}\n\n/**\n * Per-class tint for the `landcover` fill - see `landuseColour` for why these\n * are mixed from existing slots rather than given palette slots. Mirrors\n * `landcover_colour()` in compile.rs.\n */\nfunction landcoverColour(p: (slot: string) => string): unknown[] {\n const base = p(\"landcover\");\n return [\n \"match\",\n [\"get\", \"class\"],\n [\"wood\", \"forest\"], mixColour(base, p(\"park\"), 0.75),\n [\"grass\"], mixColour(base, p(\"park\"), 0.45),\n [\"wetland\"], mixColour(base, p(\"park\"), 0.3),\n [\"farmland\"], mixColour(base, p(\"landuse\"), 0.4),\n [\"sand\"], mixColour(base, p(\"building\"), 0.5),\n [\"rock\"], mixColour(base, p(\"textSecondary\"), 0.25),\n base,\n ];\n}\n\n/**\n * `[\"!in\", \"class\", ...]` excluding everything in the `transportation` layer\n * that is not a driveable road, for the layers (bridges, one-way arrows) that\n * address the road network as a whole rather than by rank. Mirrors\n * `not_a_road_filter()` in compile.rs.\n */\nfunction notARoadFilter(): unknown[] {\n return [\"!in\", \"class\", \"rail\", \"transit\", \"ferry\", \"path\", \"track\", \"pedestrian\", \"aerialway\"];\n}\n\n/**\n * Tunnels dim so they read as passing UNDER the surrounding network. Mirrors\n * `tunnel_opacity()` in compile.rs.\n *\n * `line-dasharray` would be the other conventional treatment but it takes no\n * data expression in MapLibre, so it cannot be driven off `brunnel` without\n * splitting every road layer in two. Opacity is the proportionate choice.\n *\n * `match` on a missing field is safe: `[\"get\", \"brunnel\"]` yields null for the\n * ~86% of features that carry no brunnel, and null takes the default.\n */\nfunction tunnelOpacity(): unknown[] {\n return [\"match\", [\"get\", \"brunnel\"], \"tunnel\", 0.55, 1.0];\n}\n\nfunction fill(\n id: string,\n sourceLayer: string,\n // Widened from `string` for the per-class `match` expressions that tint\n // landuse/landcover (see `landuseColour`).\n colour: string | unknown[],\n opacity: number,\n minzoom?: number,\n): JsonObject {\n const layer: JsonObject = {\n id,\n type: \"fill\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n paint: { \"fill-color\": colour, \"fill-opacity\": opacity },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Skeleton symbol layer, mirroring `compile.rs`'s `symbol()` helper. */\nfunction symbol(\n id: string,\n sourceLayer: string,\n textField: unknown,\n font: readonly string[],\n textSize: unknown,\n colour: string,\n halo: string,\n minzoom?: number,\n extraLayout?: JsonObject,\n): JsonObject {\n const layout: JsonObject = {\n \"text-field\": textField,\n \"text-font\": font,\n \"text-size\": textSize,\n ...extraLayout,\n };\n const layer: JsonObject = {\n id,\n type: \"symbol\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n layout,\n paint: {\n \"text-color\": colour,\n \"text-halo-color\": halo,\n \"text-halo-width\": 1.2,\n },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Apply a per-layer override, mirroring `compile.rs`'s `apply_override`. */\nfunction applyOverride(layer: JsonObject, layerOverride: LayerOverride): void {\n if (layerOverride.paint) mergeObject(layer, \"paint\", layerOverride.paint);\n if (layerOverride.layout) mergeObject(layer, \"layout\", layerOverride.layout);\n if (layerOverride.filter !== undefined) layer[\"filter\"] = layerOverride.filter;\n if (layerOverride.minzoom !== undefined) layer[\"minzoom\"] = layerOverride.minzoom;\n if (layerOverride.maxzoom !== undefined) layer[\"maxzoom\"] = layerOverride.maxzoom;\n if (layerOverride.visible === false) {\n const layout = (layer[\"layout\"] ??= {}) as JsonObject;\n layout[\"visibility\"] = \"none\";\n }\n}\n\nfunction mergeObject(\n layer: JsonObject,\n key: \"paint\" | \"layout\",\n overrides: Record<string, unknown>,\n): void {\n const target = (layer[key] ??= {}) as JsonObject;\n for (const [k, v] of Object.entries(overrides)) target[k] = v;\n}\n\n/** Validate one extra layer, mirroring `compile.rs`'s `validate_extra_layer`. */\nfunction validateExtraLayer(index: number, layer: unknown): JsonObject {\n const invalid = (reason: string): Error =>\n new Error(`extra layer ${index} is invalid: ${reason}`);\n if (typeof layer !== \"object\" || layer === null || Array.isArray(layer)) {\n throw invalid(\"must be an object\");\n }\n const obj = layer as JsonObject;\n const id = obj[\"id\"];\n if (typeof id !== \"string\") throw invalid('must have a string \"id\"');\n if (id.length === 0) throw invalid('\"id\" must be non-empty');\n if (obj[\"type\"] !== \"background\") {\n if (obj[\"source\"] !== \"territory\") {\n throw invalid('\"source\" must be \"territory\"');\n }\n const sourceLayer = obj[\"source-layer\"];\n if (typeof sourceLayer !== \"string\") {\n throw invalid('must have a string \"source-layer\"');\n }\n if (!SOURCE_LAYERS.includes(sourceLayer)) {\n throw invalid(\n `unknown source-layer ${JSON.stringify(sourceLayer)}; accepted: ` +\n SOURCE_LAYERS.join(\", \"),\n );\n }\n }\n return obj;\n}\n\n/**\n * Assemble a full MapLibre style for the MapMap tiles - a faithful port of\n * `sn_style::compile`, so a {@link Theme} compiles to the same style here\n * as it does in `sn-factory`/`sn-gateway`. Pure: returns a plain object,\n * touches no browser APIs, and is safe to snapshot in tests.\n *\n * Throws an `Error` with an agent-readable message (offending key + the\n * accepted values) on unknown palette slots, invalid colours, unknown layer\n * ids and invalid extra layers, mirroring `sn_style::StyleError`.\n */\n/**\n * The accepted top-level {@link Theme} keys (mirrors serde\n * `deny_unknown_fields`). `extra` is the one deliberate divergence from the\n * Rust crate: it carries Studio's nav design block in the theme FILE and is\n * ignored by compilation (the gateway still rejects it on `/styles`, which\n * is why Studio strips it on publish).\n */\nconst THEME_KEYS: readonly string[] = [\n \"name\",\n \"base\",\n \"palette\",\n \"layers\",\n \"fonts\",\n \"glyphs\",\n \"sprite\",\n \"extra_layers\",\n \"extra\",\n \"buildings_3d\",\n \"effects\",\n];\n\n/**\n * The `metadata` key a compiled style carries its effects block under.\n * Shared with `sn-style` (compile.rs) and read back by `MapMapMap` to\n * auto-enable the route effect for styles that request one.\n */\nexport const EFFECTS_METADATA_KEY = \"mapmap:effects\";\n\n/**\n * The effects block from a compiled style's `metadata`, if the style\n * carries a valid one (`{ route: \"flow\", params? }`). Lenient by design —\n * it reads FOREIGN styles (hosted URLs, baked packages), so anything\n * malformed returns `undefined` rather than throwing.\n */\nexport function effectsFromStyleMetadata(\n metadata: unknown,\n): { route: \"flow\"; params?: Record<string, unknown> } | undefined {\n if (typeof metadata !== \"object\" || metadata === null) return undefined;\n const block = (metadata as JsonObject)[EFFECTS_METADATA_KEY];\n if (typeof block !== \"object\" || block === null) return undefined;\n const { route, params } = block as JsonObject;\n if (route !== \"flow\") return undefined;\n return typeof params === \"object\" && params !== null\n ? { route, params: params as Record<string, unknown> }\n : { route };\n}\n\n/**\n * Zoom at which 3D building extrusions start (and the flat footprint layer\n * stops) when a theme sets `buildings_3d`. Mirrors\n * `compile.rs::BUILDINGS_3D_MINZOOM`. Exported for\n * `MapMapMap.setBuildings3d`, which performs the same handoff at runtime.\n */\nexport const BUILDINGS_3D_MINZOOM = 15;\n\n/**\n * The `building-3d` fill-extrusion layer a theme with `buildings_3d` gets:\n * heights from the tiles' `render_height`/`render_min_height` (5 m coalesce\n * fallback for tiles missing them), rising from flat over half a zoom so\n * the handoff from the footprint layer is seamless. Mirrors the layer\n * `compile.rs` emits, byte for byte. Shared by {@link buildStyle} and\n * `MapMapMap.setBuildings3d` so the two can never drift.\n */\nexport function buildings3dLayer(colour: unknown): JsonObject {\n return {\n id: \"building-3d\",\n type: \"fill-extrusion\",\n source: \"territory\",\n \"source-layer\": \"building\",\n minzoom: BUILDINGS_3D_MINZOOM,\n paint: {\n \"fill-extrusion-color\": colour,\n \"fill-extrusion-height\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_height\"], 5],\n ],\n \"fill-extrusion-base\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_min_height\"], 0],\n ],\n \"fill-extrusion-opacity\": 0.85,\n \"fill-extrusion-vertical-gradient\": true,\n },\n };\n}\n\n/** The `text-field` expression for the requested label language. */\nfunction nameFieldFor(labelLanguage?: string): unknown {\n if (labelLanguage === \"local\") return [\"get\", \"name\"];\n if (labelLanguage) return [\"coalesce\", [\"get\", `name:${labelLanguage}`], [\"get\", \"name\"]];\n return [\"coalesce\", [\"get\", \"name:en\"], [\"get\", \"name\"]];\n}\n\nexport function buildStyle(options: BuildStyleOptions = {}): StyleSpecification {\n const input = options.theme ?? \"light\";\n if (typeof input === \"object\") {\n // Mirror the Rust Theme's serde deny_unknown_fields: a typo'd key\n // (e.g. \"extraLayers\", \"pallete\") must fail loudly here too, not\n // silently render the default style.\n for (const key of Object.keys(input)) {\n if (!THEME_KEYS.includes(key)) {\n throw new Error(\n `unknown theme field ${JSON.stringify(key)}; accepted fields: ` +\n THEME_KEYS.join(\", \"),\n );\n }\n }\n }\n const theme: Theme =\n typeof input === \"string\" ? { name: input, base: input } : input;\n const palette = resolvePalette(theme);\n const p = (slot: string): string => palette[slot] as string;\n const font = [theme.fonts?.regular ?? \"MapMap Sans Regular\"] as const;\n const nameField = nameFieldFor(options.labelLanguage);\n const tilesUrl = toPmtilesUrl(\n options.territoryTilesUrl ?? DEFAULT_TERRITORY_TILES_URL,\n );\n\n // The skeleton: every OpenMapTiles source-layer styled, palette-driven.\n // Order is paint order (first = bottom). Mirrors compile.rs exactly.\n const layers: JsonObject[] = [\n {\n id: \"background\",\n type: \"background\",\n paint: { \"background-color\": p(\"background\") },\n },\n fill(\"landcover\", \"landcover\", landcoverColour(p), 0.6),\n fill(\"landuse\", \"landuse\", landuseColour(p), 0.45),\n fill(\"park\", \"park\", p(\"park\"), 0.7),\n fill(\"water\", \"water\", p(\"water\"), 1.0),\n {\n id: \"waterway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"waterway\",\n paint: {\n \"line-color\": p(\"waterway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.5, 16, 3],\n },\n },\n {\n id: \"aeroway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"aeroway\",\n minzoom: 10,\n filter: [\"in\", \"class\", \"runway\", \"taxiway\"],\n paint: {\n \"line-color\": p(\"aeroway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 10, 1, 16, 6],\n },\n },\n fill(\"building\", \"building\", p(\"building\"), 1.0, 13),\n // Building footprints sit at barely 1.2:1 against the background, so at\n // street zooms the fill alone reads as nothing. An outline restores the\n // block structure without touching the `building` slot default or the\n // fill opacity, which would alter every saved theme and preset. Starts\n // at BUILDINGS_3D_MINZOOM so it hands off to the extrusion at exactly\n // the zoom the flat fill does.\n {\n id: \"building-outline\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"building\",\n minzoom: BUILDINGS_3D_MINZOOM,\n paint: {\n \"line-color\": mixColour(p(\"building\"), p(\"textSecondary\"), 0.6),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 15, 0.3, 20, 1.6,\n ],\n },\n },\n {\n id: \"rail\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 8,\n filter: [\"in\", \"class\", \"rail\", \"transit\"],\n paint: {\n \"line-color\": p(\"rail\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 8, 0.4, 14, 1.6, 20, 6,\n ],\n },\n },\n // The `transportation` layer carries POLYGON features for pedestrian\n // plazas and footway areas (61 in a single Soho tile). Without a fill\n // they were only ever hairline-dashed as outlines, leaving town centres\n // empty.\n {\n id: \"pedestrian-areas\",\n type: \"fill\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 14,\n // A fill layer only ever draws polygonal geometry, so the class match\n // is the whole filter. An explicit [\"==\", [\"geometry-type\"], \"Polygon\"]\n // clause looks right but matches NOTHING here: MapLibre reports these\n // multi-ring plazas as \"MultiPolygon\" (verified live — the clause\n // rendered 0 of 73 features).\n filter: [\"match\", [\"get\", \"class\"], [\"path\", \"pedestrian\"], true, false],\n paint: {\n \"fill-color\": p(\"path\"),\n \"fill-opacity\": 0.7,\n },\n },\n {\n id: \"road-path\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"in\", \"class\", \"path\", \"track\", \"pedestrian\"],\n paint: {\n \"line-color\": p(\"path\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 13, 0.8, 16, 2.5, 18, 6, 20, 18,\n ],\n \"line-dasharray\": [3, 1.5],\n },\n },\n // Road casings. ALL casings are drawn beneath ALL road fills (rather\n // than casing/fill pairs) so that at junctions a minor road's casing\n // never paints over a major road's fill. Colours are derived, not new\n // palette slots — see `mixColour`.\n {\n id: \"road-minor-casing\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\n \"!in\",\n \"class\",\n \"motorway\",\n \"trunk\",\n \"primary\",\n \"rail\",\n \"transit\",\n \"path\",\n \"track\",\n \"pedestrian\",\n \"ferry\",\n ],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": mixColour(p(\"road\"), p(\"textSecondary\"), 0.45),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 12, 0.5, 14, 5, 16, 10, 17, 14, 18, 21, 19, 37, 20, 64,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n {\n id: \"road-major-casing\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 6,\n filter: [\"in\", \"class\", \"motorway\", \"trunk\", \"primary\"],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": mixColour(p(\"roadMajor\"), p(\"textSecondary\"), 0.45),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 6, 2, 14, 8, 16, 13, 17, 19, 18, 30, 19, 54, 20, 96,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n // Road widths ramp all the way to z20. They previously ended at z16, so\n // z17+ rendered frozen at z16 weights (4 px minor) against a 15-30 px\n // reference — the \"schematic lines\" bug.\n // Fills take round caps/joins like their casings: with the default butt\n // caps, consecutive segments split at junction nodes leave wedge gaps\n // the casing shows through — a pale notch exactly where roads join.\n {\n id: \"road-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\n \"!in\",\n \"class\",\n \"motorway\",\n \"trunk\",\n \"primary\",\n \"rail\",\n \"transit\",\n \"path\",\n \"track\",\n \"pedestrian\",\n \"ferry\",\n ],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": p(\"road\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 8, 0.5, 13, 1.5, 14, 3, 16, 7, 17, 10, 18, 16, 19, 29, 20, 52,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n {\n id: \"road-major\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\"in\", \"class\", \"motorway\", \"trunk\", \"primary\"],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": p(\"roadMajor\"),\n \"line-width\": [\n \"interpolate\",\n [\"exponential\", 1.2],\n [\"zoom\"],\n 6, 1, 14, 5.5, 16, 10, 17, 15, 18, 24, 19, 44, 20, 80,\n ],\n \"line-opacity\": tunnelOpacity(),\n },\n },\n // Bridges are REDRAWN on top of the whole flat road network (casing\n // then fill) so an overpass reads as crossing over what it spans\n // instead of as a flat junction. This is the proportionate treatment:\n // true multi-level ordering would need one layer pair per distinct\n // `layer` value, which is unbounded. The extra-wide casing supplies the\n // shadow edge that sells the crossing.\n {\n id: \"road-bridge-casing\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"all\", [\"==\", \"brunnel\", \"bridge\"], notARoadFilter()],\n layout: { \"line-cap\": \"butt\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": mixColour(p(\"road\"), p(\"textSecondary\"), 0.8),\n \"line-width\": [\"interpolate\", [\"exponential\", 1.2], [\"zoom\"], 13, 3, 16, 13, 17, 19, 18, 30, 19, 54, 20, 96],\n },\n },\n {\n id: \"road-bridge\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"all\", [\"==\", \"brunnel\", \"bridge\"], notARoadFilter()],\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": [\n \"match\",\n [\"get\", \"class\"],\n [\"motorway\", \"trunk\", \"primary\"], p(\"roadMajor\"),\n p(\"road\"),\n ],\n \"line-width\": [\"interpolate\", [\"exponential\", 1.2], [\"zoom\"], 13, 1.5, 16, 8, 17, 15, 18, 24, 19, 44, 20, 80],\n },\n },\n {\n id: \"boundary-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n minzoom: 6,\n filter: [\"all\", [\">=\", \"admin_level\", 3], [\"<=\", \"admin_level\", 8]],\n paint: {\n \"line-color\": p(\"boundaryMinor\"),\n \"line-width\": 0.6,\n \"line-dasharray\": [2, 2],\n },\n },\n {\n id: \"boundary\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n filter: [\"<=\", \"admin_level\", 2],\n paint: {\n \"line-color\": p(\"boundary\"),\n \"line-width\": 1,\n \"line-dasharray\": [3, 2],\n },\n },\n ];\n\n // 3D buildings: a fill-extrusion layer above the road network (2D layers\n // drawn after an extrusion paint over its pitched volumes, so it must\n // come last in the base map), below extras and labels. The flat\n // footprint layer is capped at the extrusion minzoom. Mirrors compile.rs.\n if (theme.buildings_3d) {\n // Both the flat fill AND its outline hand off to the extrusion at the\n // same zoom, so the 2D block edges do not keep drawing on top of the\n // pitched volumes.\n for (const id of [\"building\", \"building-outline\"]) {\n const flat = layers.find((l) => l[\"id\"] === id) as JsonObject;\n flat[\"maxzoom\"] = BUILDINGS_3D_MINZOOM;\n }\n layers.push(buildings3dLayer(p(\"building\")));\n }\n\n // User/agent-supplied extra layers sit above the base map, below labels.\n (theme.extra_layers ?? []).forEach((extra, index) => {\n layers.push(structuredClone(validateExtraLayer(index, extra)));\n });\n\n layers.push(\n // One-way arrows, drawn as a TEXT symbol rather than a sprite icon. The\n // skeleton ships no sprite at all (`sprite` is an optional user-supplied\n // URL), so an `icon-image` arrow would render nothing for every default\n // style - a text glyph needs only the glyph server the labels already use.\n //\n // The font is PINNED rather than following `theme.fonts`: U+2192 is absent\n // from 5 of the bundled fontstacks (Barlow, Noto Serif, Nunito, Open\n // Sans, Rubik - verified by decoding their 8448-8703 glyph ranges), so a\n // themed font would silently drop every arrow. \"MapMap Sans Regular\" is\n // the default fontstack and carries it (verified the same way).\n //\n // `text-keep-upright` MUST be false: left at its `true` default MapLibre\n // flips glyphs on right-to-left line segments to keep them readable, which\n // would reverse the very thing the arrow encodes.\n {\n id: \"road-oneway\",\n type: \"symbol\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 16,\n // `oneway` is 1 (forward), -1 (reverse) or 0/absent. The string forms\n // are matched too: legacy `==` is strictly typed, and a tile build that\n // encodes the attribute as a string would otherwise match nothing.\n filter: [\n \"all\",\n [\n \"any\",\n [\"==\", \"oneway\", 1],\n [\"==\", \"oneway\", -1],\n [\"==\", \"oneway\", \"1\"],\n [\"==\", \"oneway\", \"-1\"],\n ],\n notARoadFilter(),\n ],\n layout: {\n \"symbol-placement\": \"line\",\n \"symbol-spacing\": 200,\n \"text-field\": \"\\u2192\",\n \"text-font\": [\"MapMap Sans Regular\"],\n \"text-size\": [\"interpolate\", [\"linear\"], [\"zoom\"], 16, 8, 20, 12],\n \"text-rotation-alignment\": \"map\",\n \"text-pitch-alignment\": \"map\",\n \"text-keep-upright\": false,\n // -1 means the arrow points against the digitisation direction.\n \"text-rotate\": [\n \"case\",\n [\"any\", [\"==\", [\"get\", \"oneway\"], -1], [\"==\", [\"get\", \"oneway\"], \"-1\"]],\n 180,\n 0,\n ],\n // Arrows are road furniture, not labels: they should not lose\n // collisions with names, nor push them out.\n \"text-allow-overlap\": true,\n \"text-ignore-placement\": true,\n },\n paint: {\n \"text-color\": mixColour(p(\"road\"), p(\"textSecondary\"), 0.55),\n \"text-halo-color\": p(\"textHalo\"),\n \"text-halo-width\": 1.0,\n },\n },\n symbol(\n \"housenumber\",\n \"housenumber\",\n [\"get\", \"housenumber\"],\n font,\n 10,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 17,\n ),\n symbol(\n \"road-labels\",\n \"transportation_name\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 12, 11, 16, 12.5, 20, 15],\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 12,\n {\n \"symbol-placement\": \"line\",\n // Street names must be able to REPEAT along a long road: at z18 the\n // map was drawing 80 POI labels to 11 road labels, reading as a pin\n // cloud rather than a street network. Spacing tightens as the same\n // street comes to fill more of the screen.\n \"symbol-spacing\": [\"interpolate\", [\"linear\"], [\"zoom\"], 12, 400, 16, 260, 18, 320, 20, 520],\n },\n ),\n symbol(\n \"water-name\",\n \"water_name\",\n nameField,\n font,\n 12,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n {\n // POI rebalancing. `poi.rank` is populated on 100% of features (1 = most\n // prominent), so it can do two jobs: a zoom-stepped ceiling admits only the\n // headline POIs at mid zooms and opens right up by z18, where the user has\n // asked for detail; and `symbol-sort-key` makes the survivors compete by\n // rank, so when labels do collide the landmark wins and the vape shop\n // loses. Lower sort key = placed first, and lower rank = more important, so\n // `rank` can be used directly. This rebalances rather than hides.\n ...symbol(\n \"poi-labels\",\n \"poi\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 14,\n {\n \"text-anchor\": \"top\",\n \"symbol-sort-key\": [\"coalesce\", [\"get\", \"rank\"], 99],\n },\n ),\n filter: [\n \"<=\",\n [\"coalesce\", [\"get\", \"rank\"], 99],\n [\"step\", [\"zoom\"], 6, 15, 10, 16, 15, 17, 22, 18, 40, 19, 120],\n ],\n },\n symbol(\n \"mountain-peak-labels\",\n \"mountain_peak\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n symbol(\n \"aerodrome-labels\",\n \"aerodrome_label\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 10,\n ),\n // Label hierarchy: settlements and regions wait until z4 so world\n // zooms aren't a flat democracy of states, cities and villages;\n // continent labels are dropped entirely as clutter.\n {\n ...symbol(\n \"place-labels\",\n \"place\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 4, 10.5, 12, 16],\n p(\"textPrimary\"),\n p(\"textHalo\"),\n 4,\n ),\n filter: [\"match\", [\"get\", \"class\"], [\"country\", \"continent\"], false, true],\n },\n // Countries: the most prominent text on the map at world zooms —\n // larger, letter-spaced, visible from z1, ceding to the regional\n // hierarchy from z10. Drawn last = wins label collisions.\n {\n ...symbol(\n \"country-labels\",\n \"place\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 1, 11, 3, 13.5, 6, 18],\n p(\"textPrimary\"),\n p(\"textHalo\"),\n 1,\n { \"text-letter-spacing\": 0.08, \"text-max-width\": 7 },\n ),\n filter: [\"==\", [\"get\", \"class\"], \"country\"],\n maxzoom: 10,\n },\n );\n\n // Reject duplicate layer ids (e.g. an extra layer reusing a skeleton id),\n // mirroring `validate_style` in sn-style's validate.rs — the Rust compiler\n // rejects these and MapLibre would error at style load.\n const seenIds = new Set<string>();\n for (const layer of layers) {\n const layerId = layer[\"id\"] as string;\n if (seenIds.has(layerId)) {\n throw new Error(`duplicate layer id ${JSON.stringify(layerId)}`);\n }\n seenIds.add(layerId);\n }\n\n // Apply per-layer overrides.\n const accepted = layers.map((l) => l[\"id\"] as string).join(\", \");\n for (const [id, layerOverride] of Object.entries(theme.layers ?? {})) {\n const layer = layers.find((l) => l[\"id\"] === id);\n if (!layer) {\n throw new Error(\n `unknown layer id ${JSON.stringify(id)}; accepted ids: ${accepted}`,\n );\n }\n applyOverride(layer, layerOverride);\n }\n\n const style: JsonObject = {\n version: 8,\n name: theme.name ? `MapMap ${theme.name}` : \"MapMap\",\n glyphs: theme.glyphs ?? DEFAULT_GLYPHS_URL,\n sources: {\n territory: {\n type: \"vector\",\n url: tilesUrl,\n // Legally required (ODbL + CC-BY) - enforced, not themable. There\n // is no theme field that can remove it.\n attribution: FULL_ATTRIBUTION,\n },\n },\n layers,\n };\n if (theme.sprite !== undefined) style[\"sprite\"] = theme.sprite;\n\n // Effects ride the COMPILED style (unlike `extra`, which is theme-only):\n // `metadata[\"mapmap:effects\"]` is the one channel a hosted style URL or a\n // baked territory package carries, so `MapMapMap` can auto-enable the\n // route ribbon from the style alone. Mirrors compile.rs.\n if (theme.effects) {\n validateEffects(theme.effects);\n if ((theme.effects.route ?? \"none\") !== \"none\") {\n const block: JsonObject = { route: theme.effects.route };\n if (theme.effects.params) block[\"params\"] = theme.effects.params;\n style[\"metadata\"] = { [EFFECTS_METADATA_KEY]: block };\n }\n }\n\n // The object above is structurally a MapLibre style; the cast avoids\n // hand-satisfying every discriminated-union member of StyleSpecification.\n return style as unknown as StyleSpecification;\n}\n","/**\n * MapMapMap - the branded MapLibre GL map.\n *\n * A thin wrapper over `maplibregl.Map`. MapLibre does all the rendering; this\n * class only wires in the MapMap default style, registers the pmtiles\n * protocol, and keeps the gateway `apiKey`/`baseUrl` handy so routing and ADR\n * helpers can reuse them.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n LayerSpecification,\n Map as MlMap,\n MapOptions,\n StyleSpecification,\n} from \"maplibre-gl\";\nimport { Protocol } from \"pmtiles\";\nimport { runMapDiagnostics } from \"./diagnostics.js\";\nimport {\n createRouteEffect,\n type RouteEffectLayer,\n type RouteEffectName,\n type RouteFlowOptions,\n} from \"./effects.js\";\nimport { LogoControl, type LogoOptions } from \"./logo.js\";\nimport { navDesignFromTheme, type NavDesign } from \"./nav-design.js\";\nimport { poiDesignFromTheme, type PoiDesign } from \"./poi-design.js\";\nimport {\n BUILDINGS_3D_MINZOOM,\n buildStyle,\n buildings3dLayer,\n effectsFromStyleMetadata,\n type MapMapTheme,\n type Theme,\n} from \"./style.js\";\nimport type { RouteGeometry } from \"./types.js\";\n\n// Tracked per maplibre-gl module instance, not with a single flag: bundlers\n// can duplicate maplibre-gl, and each copy needs its own registration.\nconst pmtilesRegistered = new WeakSet<object>();\n\n/**\n * Register the `pmtiles://` protocol on a MapLibre instance. Idempotent per\n * maplibre-gl instance, and safe to call before constructing any map.\n * Exposed for apps that build their own `maplibregl.Map` (possibly from\n * their own bundled maplibre-gl copy) but still want to read MapMap PMTiles.\n */\nexport function registerPmtilesProtocol(gl: typeof maplibregl = maplibregl): void {\n if (pmtilesRegistered.has(gl)) return;\n const protocol = new Protocol();\n gl.addProtocol(\"pmtiles\", protocol.tile);\n pmtilesRegistered.add(gl);\n}\n\nexport interface MapMapOptions {\n /**\n * The MapMap wordmark on the map (like the Google Maps / Mapbox marks).\n * Default on at bottom-right, above the attribution; `false` removes\n * it, or pass `{ position, href }` to customise.\n */\n logo?: boolean | LogoOptions;\n /** The container element or its id. */\n container: string | HTMLElement;\n /** Gateway API key (`snk_…`), used by routing and ADR helpers. */\n apiKey?: string;\n /** Gateway base URL for routing/ADR. Defaults to `https://api.mapmap.ai`. */\n baseUrl?: string;\n /**\n * Style to load. A theme name (`\"light\"` / `\"dark\"`), a MapMap Studio\n * `Theme` document, a full MapLibre `StyleSpecification`, or a style URL.\n * Defaults to `\"light\"`.\n */\n style?: MapMapTheme | Theme | StyleSpecification | string;\n /** Override the territory PMTiles URL used by the default styles. */\n territoryTilesUrl?: string;\n /** Initial centre as `[lng, lat]`. Defaults to the UK. */\n center?: [number, number];\n /** Initial zoom. Defaults to `5`. */\n zoom?: number;\n /**\n * Extra MapLibre `MapOptions` merged last (escape hatch for hash, bearing,\n * maxBounds, etc.). `container` and `style` here are ignored.\n */\n mapOptions?: Partial<Omit<MapOptions, \"container\" | \"style\">>;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.mapmap.ai\";\nconst DEFAULT_CENTER: [number, number] = [-1.5, 52.6];\nconst DEFAULT_ZOOM = 5;\nconst DEFAULT_EFFECT_LAYER_ID = \"mapmap-route-effect\";\n\n/** Options for {@link MapMapMap.setRouteEffect}. */\nexport interface SetRouteEffectOptions extends RouteFlowOptions {\n /**\n * The route line to attach the effect to. Optional: when omitted the\n * effect is ARMED and applies as soon as a `RouteLayer` draws a route\n * (RouteLayer feeds every drawn geometry to the map automatically).\n */\n geometry?: RouteGeometry;\n}\n\n/** The flow options carried by a style's `metadata[\"mapmap:effects\"].params`. */\nfunction flowOptionsFromParams(params: Record<string, unknown>): RouteFlowOptions {\n const options: RouteFlowOptions = {};\n if (typeof params[\"color\"] === \"string\") options.color = params[\"color\"];\n if (typeof params[\"width\"] === \"number\") options.width = params[\"width\"];\n if (typeof params[\"speed\"] === \"number\") options.speed = params[\"speed\"];\n return options;\n}\n\n/** The MapMap map: a branded, tiles-and-routing-ready MapLibre map. */\nexport class MapMapMap {\n /** The underlying MapLibre map. Use it for any native MapLibre call. */\n readonly map: MlMap;\n /** Gateway API key, if provided. */\n readonly apiKey: string | undefined;\n /** Gateway base URL (no trailing slash). */\n readonly baseUrl: string;\n /**\n * The Studio navigation design (`extra.nav`) parsed from the theme passed\n * as `style`, when it carried one. `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` pick this up as their default look; `undefined` means\n * the theme had no nav block (or `style` was not a theme document).\n */\n readonly navDesign: NavDesign | undefined;\n /**\n * The Studio POI category design (`extra.poi`) parsed from the theme\n * passed as `style`, when it carried one. Apply its label-text part with\n * `applyPoiDesign(map.map, map.poiDesign)`; `undefined` means the theme\n * had no poi block (or `style` was not a theme document).\n */\n readonly poiDesign: PoiDesign | undefined;\n\n // Route-effect state (see setRouteEffect / effects.ts). `explicit`\n // records an app-level decision, which always wins over a style's\n // metadata auto-enable.\n private effectName: RouteEffectName | null = null;\n private effectOptions: RouteFlowOptions = {};\n private effectGeometry: RouteGeometry | undefined;\n private effectExplicit = false;\n private effectLayer: RouteEffectLayer | undefined;\n\n constructor(options: MapMapOptions) {\n registerPmtilesProtocol();\n\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n const theme = themeOf(options.style);\n this.navDesign = navDesignFromTheme(theme);\n this.poiDesign = poiDesignFromTheme(theme);\n\n const style = resolveStyle(options.style, options.territoryTilesUrl);\n\n this.map = new maplibregl.Map({\n container: options.container,\n style,\n center: options.center ?? DEFAULT_CENTER,\n zoom: options.zoom ?? DEFAULT_ZOOM,\n attributionControl: { compact: false },\n ...options.mapOptions,\n });\n\n // The MapMap mark, Google/Mapbox-style. Default on (bottom-right,\n // above the attribution); `logo: false` removes it, `logo: {...}`\n // repositions it. Attribution is separate and never removable.\n if (options.logo !== false) {\n const logoOptions = options.logo === true ? {} : (options.logo ?? {});\n this.map.addControl(\n new LogoControl(logoOptions),\n logoOptions.position ?? \"bottom-right\",\n );\n }\n\n // Route effects: styles compiled with an `effects` block carry\n // `metadata[\"mapmap:effects\"]`; honour it on every style (re)load\n // unless the app has called setRouteEffect itself. Custom layers are\n // wiped by setStyle like all runtime layers, so this also re-installs\n // an active effect after a theme swap.\n this.map.on(\"style.load\", this.handleStyleLoadForEffects);\n\n // Self-diagnosing errors: one actionable console.error per issue per\n // page (0px container, duplicate maplibre-gl, WebGL, 401s). Fully\n // defensive - never throws, skips DOM checks server-side.\n runMapDiagnostics({\n container: options.container,\n map: this.map,\n maplibre: maplibregl,\n apiKey: this.apiKey,\n });\n }\n\n private readonly handleStyleLoadForEffects = (): void => {\n if (!this.effectExplicit) {\n const block = effectsFromStyleMetadata(this.styleMetadata());\n this.effectName = block?.route ?? null;\n this.effectOptions = block?.params ? flowOptionsFromParams(block.params) : {};\n }\n // The old layer object died with the old style; re-add a fresh one.\n // Deferred a microtask so layers other style.load handlers re-install\n // (RouteLayer's line) land first and the ribbon stays on top.\n this.effectLayer = undefined;\n queueMicrotask(() => this.applyRouteEffect());\n };\n\n /** The current style's `metadata`, if it can be read yet. */\n private styleMetadata(): unknown {\n try {\n return (\n this.map as { getStyle?: () => { metadata?: unknown } | undefined }\n ).getStyle?.()?.metadata;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Set (or clear) the visual effect on the active route line - the\n * effects-engine entry point (see `effects.ts`). The first effect is\n * `\"flow\"`: an animated energy ribbon flowing along the route, drawn in\n * a MapLibre custom layer with first-party GLSL.\n *\n * ```ts\n * const route = await routes.route(from, to);\n * map.setRouteEffect(\"flow\"); // uses the drawn route\n * map.setRouteEffect(\"flow\", { color: \"#ff7a1f\" }); // options\n * map.setRouteEffect(null); // back to the plain line\n * ```\n *\n * Geometry: pass `{ geometry }` explicitly, or omit it and the effect\n * attaches to whatever route a `RouteLayer` on this map draws (current\n * and future - RouteLayer reports every drawn line via\n * {@link setRouteEffectGeometry}).\n *\n * Styles whose theme carried an `effects` block auto-enable their effect\n * from the compiled style's metadata; calling this method (with any\n * value, including `null`) overrides the style's wish for the lifetime\n * of this map.\n *\n * Accessibility/resilience (see effects.ts): honours\n * `prefers-reduced-motion` (static gradient, no animation) and falls\n * back to the plain route line with a single console warning if WebGL\n * setup fails.\n */\n setRouteEffect(\n effect: RouteEffectName | null,\n options: SetRouteEffectOptions = {},\n ): void {\n this.effectExplicit = true;\n const { geometry, ...flowOptions } = options;\n this.effectName = effect;\n this.effectOptions = flowOptions;\n if (geometry) this.effectGeometry = geometry;\n // Options are baked into the layer at creation; rebuild it.\n this.removeEffectLayer();\n this.applyRouteEffect();\n }\n\n /**\n * Attach the active route effect to a route line (or detach it with\n * `null`). `RouteLayer` calls this on every `draw()`/`clear()`, so apps\n * normally never do - pass `geometry` to {@link setRouteEffect} for\n * routes drawn outside a RouteLayer.\n */\n setRouteEffectGeometry(geometry: RouteGeometry | null): void {\n this.effectGeometry = geometry ?? undefined;\n if (\n geometry &&\n this.effectLayer &&\n this.map.getLayer(this.effectLayerId())\n ) {\n this.effectLayer.setGeometry(geometry);\n return;\n }\n this.applyRouteEffect();\n }\n\n private effectLayerId(): string {\n return this.effectOptions.id ?? DEFAULT_EFFECT_LAYER_ID;\n }\n\n private removeEffectLayer(): void {\n const id = this.effectLayerId();\n if (this.map.getLayer(id)) this.map.removeLayer(id);\n this.effectLayer = undefined;\n }\n\n /** Reconcile the effect state with the map: install, update or remove. */\n private applyRouteEffect(): void {\n const id = this.effectLayerId();\n if (this.effectName === null || this.effectGeometry === undefined) {\n this.removeEffectLayer();\n return;\n }\n if (!this.map.isStyleLoaded()) {\n this.map.once(\"load\", () => this.applyRouteEffect());\n return;\n }\n if (this.effectLayer && this.map.getLayer(id)) {\n this.effectLayer.setGeometry(this.effectGeometry);\n return;\n }\n if (this.map.getLayer(id)) this.map.removeLayer(id);\n this.effectLayer = createRouteEffect(this.effectName, this.effectGeometry, {\n ...this.effectOptions,\n id,\n });\n this.map.addLayer(this.effectLayer);\n }\n\n /**\n * Toggle 3D building extrusions at runtime — the live equivalent of\n * compiling the style with `buildings_3d: true` (see `Theme`): adds or\n * removes the `building-3d` fill-extrusion layer and hands the flat\n * `building` footprint layer off at zoom 15. The extrusion takes its\n * colour from the current `building` fill, so it follows the theme.\n * Idempotent; safe to call before the style has loaded (it applies on\n * load). Requires the MapMap skeleton's `building` layer — on a custom\n * style without one this throws rather than guessing.\n *\n * Mobile note: leave 3D off in native navigation views for now\n * (maplibre-native#4107 — fill-extrusion memory at street zooms).\n */\n setBuildings3d(enabled: boolean): void {\n if (!this.map.isStyleLoaded()) {\n this.map.once(\"load\", () => this.setBuildings3d(enabled));\n return;\n }\n if (enabled === (this.map.getLayer(\"building-3d\") !== undefined)) return;\n const building = this.map.getLayer(\"building\");\n if (!building) {\n throw new Error(\n 'setBuildings3d needs the MapMap skeleton \"building\" layer; ' +\n \"the current style does not have one\",\n );\n }\n const minzoom = building.minzoom ?? 13;\n if (enabled) {\n const colour =\n this.map.getPaintProperty(\"building\", \"fill-color\") ?? \"#e0d6c4\";\n this.map.addLayer(\n buildings3dLayer(colour) as unknown as LayerSpecification,\n buildings3dBeforeId(this.map),\n );\n this.map.setLayerZoomRange(\"building\", minzoom, BUILDINGS_3D_MINZOOM);\n } else {\n this.map.removeLayer(\"building-3d\");\n // 24 is the style-spec default maxzoom, i.e. \"uncapped\".\n this.map.setLayerZoomRange(\"building\", minzoom, 24);\n }\n }\n\n /** Resolves once the style and first tiles are loaded. */\n whenReady(): Promise<void> {\n return new Promise((resolve) => {\n if (this.map.loaded()) {\n resolve();\n return;\n }\n this.map.once(\"load\", () => resolve());\n });\n }\n\n /** Remove the map and release its WebGL context. */\n destroy(): void {\n this.map.remove();\n }\n}\n\n/** Functional alias for {@link MapMapMap}, mirroring the Mapbox `new Map` feel. */\nexport function createMap(options: MapMapOptions): MapMapMap {\n return new MapMapMap(options);\n}\n\n/**\n * Where the runtime `building-3d` layer goes: the same place the compiler\n * puts it — directly above the base map (after `boundary`), below extras\n * and labels. On a custom style without the skeleton's `boundary` layer,\n * fall back to just below the first symbol layer; `undefined` (append on\n * top) only if there are no symbol layers either.\n */\nfunction buildings3dBeforeId(map: MlMap): string | undefined {\n const layers = map.getStyle().layers ?? [];\n const boundary = layers.findIndex((l) => l.id === \"boundary\");\n if (boundary >= 0) return layers[boundary + 1]?.id;\n return layers.find((l) => l.type === \"symbol\")?.id;\n}\n\n/**\n * The MapMap Studio Theme document behind a `style` option, if that is what\n * it is. An object without a `version` field is a Theme; a full MapLibre\n * StyleSpecification always carries `version: 8`.\n */\nfunction themeOf(style: MapMapOptions[\"style\"]): Theme | undefined {\n if (typeof style === \"object\" && style !== null && !(\"version\" in style)) {\n return style as Theme;\n }\n return undefined;\n}\n\nfunction resolveStyle(\n style: MapMapOptions[\"style\"],\n territoryTilesUrl: string | undefined,\n): StyleSpecification | string {\n if (style === undefined || style === \"light\" || style === \"dark\") {\n return buildStyle({\n theme: style ?? \"light\",\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n const theme = themeOf(style);\n if (theme) {\n return buildStyle({\n theme,\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n return style as StyleSpecification | string;\n}\n","/**\n * OSRM request assembly and response parsing - pure, browser-free logic.\n *\n * The MapMap gateway exposes `GET /route/v1/{profile}/{coordinates}` speaking\n * the OSRM HTTP API v1, with truck vendor extensions (`height`, `width`,\n * `length`, `weight`, `hazmat`, `tunnel_code`). We always request\n * `geometries=geojson` so the route line arrives as a GeoJSON LineString we\n * can hand straight to a MapLibre source.\n */\nimport { formatCoords } from \"./coords.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteGeometry,\n RouteProfile,\n TruckParams,\n} from \"./types.js\";\n\n/** Guidance-related query options. */\nexport interface GuidanceQuery {\n voice?: boolean;\n banner?: boolean;\n language?: string;\n}\n\n/** Build the OSRM query string (without the leading `?`) for a request. */\nexport function buildRouteQuery(truck?: TruckParams, guidance?: GuidanceQuery): string {\n const params = new URLSearchParams({\n geometries: \"geojson\",\n overview: \"full\",\n steps: \"true\",\n });\n if (guidance?.voice) params.set(\"voice_instructions\", \"true\");\n if (guidance?.banner) params.set(\"banner_instructions\", \"true\");\n if (guidance?.language) params.set(\"language\", guidance.language);\n if (truck) {\n if (truck.heightM != null) params.set(\"height\", String(truck.heightM));\n if (truck.widthM != null) params.set(\"width\", String(truck.widthM));\n if (truck.lengthM != null) params.set(\"length\", String(truck.lengthM));\n if (truck.weightT != null) params.set(\"weight\", String(truck.weightT));\n if (truck.hazmat != null) params.set(\"hazmat\", String(truck.hazmat));\n // URLSearchParams encodes the slash in codes like \"B/D\" for us.\n if (truck.tunnelCode != null) params.set(\"tunnel_code\", truck.tunnelCode);\n }\n return params.toString();\n}\n\n/**\n * Build the full OSRM route URL. `baseUrl` is the gateway origin (trailing\n * slashes are trimmed); `points` is the ordered coordinate path.\n */\nexport function buildRouteUrl(\n baseUrl: string,\n profile: RouteProfile,\n points: LngLatLike[],\n truck?: TruckParams,\n guidance?: GuidanceQuery,\n): string {\n const origin = baseUrl.replace(/\\/+$/, \"\");\n const coords = formatCoords(points);\n const query = buildRouteQuery(truck, guidance);\n return `${origin}/route/v1/${encodeURIComponent(profile)}/${coords}?${query}`;\n}\n\n/**\n * Parse an OSRM route response into a {@link ParsedRoute}. Throws with the\n * OSRM `code`/`message` when the response is not `Ok` or carries no route.\n */\nexport function parseOsrmRoute(body: unknown): ParsedRoute {\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"OSRM response was not an object\");\n }\n const obj = body as Record<string, unknown>;\n const code = obj[\"code\"];\n if (code !== \"Ok\") {\n const message = typeof obj[\"message\"] === \"string\" ? obj[\"message\"] : \"\";\n throw new Error(\n `OSRM routing failed: ${String(code)}${message ? ` - ${message}` : \"\"}`,\n );\n }\n\n const routes = obj[\"routes\"];\n if (!Array.isArray(routes) || routes.length === 0) {\n throw new Error(\"OSRM response contained no routes\");\n }\n const route = routes[0] as Record<string, unknown>;\n\n const geometry = parseGeometry(route[\"geometry\"]);\n const distanceM = numberOr(route[\"distance\"], 0);\n const durationS = numberOr(route[\"duration\"], 0);\n\n return { distanceM, durationS, geometry, raw: route };\n}\n\nfunction parseGeometry(geometry: unknown): RouteGeometry {\n if (\n typeof geometry !== \"object\" ||\n geometry === null ||\n (geometry as { type?: unknown }).type !== \"LineString\"\n ) {\n throw new Error(\n \"route geometry was not GeoJSON - request geometries=geojson\",\n );\n }\n const coordinates = (geometry as { coordinates?: unknown }).coordinates;\n if (!Array.isArray(coordinates)) {\n throw new Error(\"route geometry had no coordinates\");\n }\n const positions: [number, number][] = coordinates.map((pos, i) => {\n if (\n !Array.isArray(pos) ||\n typeof pos[0] !== \"number\" ||\n typeof pos[1] !== \"number\"\n ) {\n throw new Error(`route geometry position ${i} is not [lng, lat]`);\n }\n return [pos[0], pos[1]];\n });\n return { type: \"LineString\", coordinates: positions };\n}\n\nfunction numberOr(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}\n","/**\n * RouteLayer - fetch an OSRM route from the MapMap gateway and draw it.\n *\n * The route request/parse logic lives in the pure `osrm` module; this class\n * owns the network call and the MapLibre source/layers (a signal-blue line\n * with a darker casing, matching the brand).\n */\nimport type {\n GeoJSONSource,\n LineLayerSpecification,\n Map as MlMap,\n} from \"maplibre-gl\";\nimport { buildRouteUrl, parseOsrmRoute } from \"./osrm.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteOptions,\n} from \"./types.js\";\nimport { MapMapMap } from \"./map.js\";\nimport type { NavAlertsDesign, NavRouteDesign } from \"./nav-design.js\";\n\n/** MapMap brand signal blue (see website `--signal`). */\nexport const SIGNAL_BLUE = \"#3a86ff\";\nconst CASING_COLOR = \"#1f438a\";\n/** Built-in average-speed corridor tint, used without an alerts design. */\nconst CORRIDOR_COLOR = \"#e05c6c\";\nconst CORRIDOR_OPACITY = 0.55;\n\n/**\n * Runtime overrides for the drawn line, applied over the design or the\n * built-in look. Every field is optional; omitted ones are left alone.\n */\nexport interface RouteLineStyle {\n /** Line colour. */\n color?: string;\n /** Dash pattern in line-widths, or `null` for solid. */\n dash?: number[] | null;\n /** Casing opacity, 0-1. Set 0 to hide the casing entirely. */\n casingOpacity?: number;\n}\n\nexport interface RouteLayerOptions {\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-route\"`. */\n id?: string;\n /**\n * Studio route design (`extra.nav` `route` block). Defaults to the map's\n * `navDesign.route` when given a `MapMapMap` whose theme carried one;\n * without a design the layer keeps its built-in signal-blue look.\n */\n design?: NavRouteDesign;\n /**\n * Studio safety-alert design (`extra.nav` `alerts` block), used for the\n * average-speed corridor highlight drawn by\n * {@link RouteLayer.setAlertCorridors}. Defaults to the map's\n * `navDesign.alerts` when given a `MapMapMap` whose theme carried one.\n */\n alertsDesign?: NavAlertsDesign;\n /**\n * Colour of the already-travelled part of the line once\n * {@link RouteLayer.setProgress} is used (the Google-style \"vanishing\n * route line\"). Defaults to a dimmed grey.\n */\n progressColor?: string;\n /** Casing colour for unselected alternative routes. */\n alternativeCasingColor?: string;\n /** Line colour for unselected alternative routes. */\n alternativeColor?: string;\n /** Colour of the ferry dashes drawn over the selected route. */\n ferryColor?: string;\n}\n\n/** Default colour of the travelled route segment. */\nconst PROGRESS_COLOR = \"#b0b0b0\";\n\n/**\n * Alternative-route and ferry paints. These values match the live map's\n * hand-rolled layers exactly, so a caller replacing those with this class\n * gets a pixel-identical result rather than a redesign.\n */\nconst ALT_CASING_COLOR = \"#5a6b84\";\nconst ALT_LINE_COLOR = \"#aebdd2\";\nconst FERRY_COLOR = \"#eaf1fb\";\n\n/**\n * The manoeuvre-arrow bitmap: a white upward arrow with a dark outline,\n * generated as raw RGBA pixels so no canvas 2D context is needed (works in\n * workers and test environments alike). Rotated per-manoeuvre via\n * `icon-rotate`.\n */\nfunction arrowImage(): { width: number; height: number; data: Uint8Array } {\n const size = 24;\n const data = new Uint8Array(size * size * 4);\n const head = 13; // rows 2..head form the triangular head\n const put = (x: number, y: number, edge: boolean): void => {\n const i = (y * size + x) * 4;\n const v = edge ? 31 : 255; // dark outline, white fill\n data[i] = v;\n data[i + 1] = v;\n data[i + 2] = edge ? 58 : 255;\n data[i + 3] = 255;\n };\n for (let y = 2; y < head; y++) {\n // Head: width grows with y; edge pixels darken to outline the shape.\n const half = Math.round(((y - 2) / (head - 3)) * 9);\n for (let x = 11 - half; x <= 12 + half; x++) {\n put(x, y, x === 11 - half || x === 12 + half || y === 2);\n }\n }\n for (let y = head; y < 22; y++) {\n // Shaft: constant width 6, outlined.\n for (let x = 9; x <= 14; x++) {\n put(x, y, x === 9 || x === 14 || y === 21);\n }\n }\n return { width: size, height: size, data };\n}\n\n/** Draws MapMap routes on a MapLibre map. */\nexport class RouteLayer {\n private readonly map: MlMap;\n /** The owning MapMapMap, when built from one - fed each drawn route so\n * an armed route effect (`setRouteEffect`) attaches automatically. */\n private readonly owner: MapMapMap | undefined;\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly casingLayerId: string;\n private readonly lineLayerId: string;\n private readonly maneuverSourceId: string;\n private readonly maneuverLayerId: string;\n private readonly arrowImageId: string;\n private readonly corridorSourceId: string;\n private readonly corridorLayerId: string;\n private readonly design: NavRouteDesign | undefined;\n private alertsDesign: NavAlertsDesign | undefined;\n private readonly progressColor: string;\n private readonly altSourceId: string;\n private readonly altCasingLayerId: string;\n private readonly altLineLayerId: string;\n private readonly ferrySourceId: string;\n private readonly ferryLayerId: string;\n private readonly altCasingColor: string;\n private readonly altColor: string;\n private readonly ferryColor: string;\n private lastRoute: ParsedRoute | undefined;\n /** Unselected alternatives, drawn beneath the selected route. */\n private alternatives: ParsedRoute[] = [];\n /** Ferry legs of the selected route, drawn as dashes over its line. */\n private ferrySegments: [number, number][][] = [];\n private selectHandler: ((index: number) => void) | undefined;\n /** Runtime paint override, re-applied after every style reload. */\n private lineStyle: RouteLineStyle | undefined;\n private progress = 0;\n private maneuver: { lngLat: [number, number]; bearingDeg: number } | undefined;\n private corridors: [number, number][][] = [];\n\n constructor(map: MapMapMap | MlMap, options: RouteLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.owner = map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n this.design = options.design ?? map.navDesign?.route;\n this.alertsDesign = options.alertsDesign ?? map.navDesign?.alerts;\n } else {\n this.map = map;\n if (!options.baseUrl) {\n throw new Error(\"RouteLayer needs a baseUrl when given a raw MapLibre map\");\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.design = options.design;\n this.alertsDesign = options.alertsDesign;\n }\n const id = options.id ?? \"mapmap-route\";\n this.sourceId = `${id}-src`;\n this.casingLayerId = `${id}-casing`;\n this.lineLayerId = `${id}-line`;\n this.maneuverSourceId = `${id}-maneuver-src`;\n this.maneuverLayerId = `${id}-maneuver`;\n this.arrowImageId = `${id}-arrow`;\n this.corridorSourceId = `${id}-corridor-src`;\n this.corridorLayerId = `${id}-corridor`;\n this.altSourceId = `${id}-alt-src`;\n this.altCasingLayerId = `${id}-alt-casing`;\n this.altLineLayerId = `${id}-alt-line`;\n this.ferrySourceId = `${id}-ferry-src`;\n this.ferryLayerId = `${id}-ferry`;\n this.progressColor = options.progressColor ?? PROGRESS_COLOR;\n this.altCasingColor = options.alternativeCasingColor ?? ALT_CASING_COLOR;\n this.altColor = options.alternativeColor ?? ALT_LINE_COLOR;\n this.ferryColor = options.ferryColor ?? FERRY_COLOR;\n // MapLibre wipes runtime sources/layers on every setStyle (e.g. a\n // light/dark theme swap), so re-install the route after each style\n // load — the same pattern the playground uses. This also completes a\n // draw() that arrived before the initial style finished loading.\n this.map.on(\"style.load\", this.handleStyleLoad);\n }\n\n private readonly handleStyleLoad = (): void => {\n // Alternatives first: they must sit beneath the selected route, and\n // MapLibre has no \"insert below\" without a beforeId, so installing\n // them before the main line is the ordering that needs no beforeId.\n this.installAlternatives();\n if (this.lastRoute) this.install(this.lastRoute);\n else this.installManeuver();\n this.installCorridors();\n this.installFerry();\n };\n\n /**\n * Route from `from` to `to` (with optional intermediate `via` points passed\n * through `options` is not supported here - pass a coordinate list to\n * {@link routePath} for that), draw the line, and return the parsed route.\n */\n async route(\n from: LngLatLike,\n to: LngLatLike,\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n return this.routePath([from, to], options);\n }\n\n /** Route through an ordered list of coordinates and draw the result. */\n async routePath(\n points: LngLatLike[],\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n const url = buildRouteUrl(\n this.baseUrl,\n options.profile ?? \"driving\",\n points,\n options.truck,\n { voice: options.voice, banner: options.banner, language: options.language },\n );\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(url, { headers });\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n const obj =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n // Only OSRM-shaped error bodies (with a \"code\") belong to the routing\n // engine; anything else (e.g. the gateway's RFC 9457 problem+json for\n // 401/429) is reported with its status and title/detail instead of\n // being misattributed as an OSRM failure.\n if (typeof obj?.[\"code\"] !== \"string\") {\n const context = [obj?.[\"title\"], obj?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `route request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n }\n const parsed = parseOsrmRoute(body);\n this.draw(parsed);\n return parsed;\n }\n\n /** The most recently drawn route, if any. */\n get current(): ParsedRoute | undefined {\n return this.lastRoute;\n }\n\n /**\n * Draw (or update) a parsed route's line on the map. Safe to call before\n * the style has loaded: the route is stored and installed on the next\n * `style.load` instead of throwing MapLibre's \"Style is not done loading\".\n */\n draw(route: ParsedRoute): void {\n this.lastRoute = route;\n if (this.map.isStyleLoaded()) this.install(route);\n // else: installed by handleStyleLoad.\n // Attach any armed route effect (map.setRouteEffect) to this line -\n // after install, so the effect's custom layer lands above the line.\n this.owner?.setRouteEffectGeometry(route.geometry);\n }\n\n /** Add-or-update the source and layers for a route on the current style. */\n private install(route: ParsedRoute): void {\n const data = {\n type: \"Feature\" as const,\n properties: {},\n geometry: route.geometry,\n };\n\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n // lineMetrics powers the progress gradient (line-progress requires it).\n this.map.addSource(this.sourceId, { type: \"geojson\", data, lineMetrics: true });\n }\n\n if (this.map.getLayer(this.casingLayerId) && this.map.getLayer(this.lineLayerId)) {\n this.applyProgress();\n this.applyLineStyle();\n this.installManeuver();\n return;\n }\n\n // With a Studio design the paints follow the Studio preview exactly\n // (constant width, casing = width + 4, shared opacity — see\n // syncNavOverlay in the Studio client); without one they keep the\n // built-in zoom-interpolated signal-blue look, unchanged.\n const casing: LineLayerSpecification = {\n id: this.casingLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.casingColor,\n \"line-width\": this.design.casingWidth ?? this.design.width + 4,\n \"line-opacity\": this.design.casingOpacity ?? this.design.opacity,\n }\n : {\n \"line-color\": CASING_COLOR,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 6, 16, 12],\n },\n };\n const line: LineLayerSpecification = {\n id: this.lineLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.color,\n \"line-width\": this.design.width,\n \"line-opacity\": this.design.opacity,\n ...(this.design.dash ? { \"line-dasharray\": this.design.dash } : {}),\n }\n : {\n \"line-color\": SIGNAL_BLUE,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 3, 16, 8],\n },\n };\n\n if (!this.map.getLayer(this.casingLayerId)) this.map.addLayer(casing);\n if (!this.map.getLayer(this.lineLayerId)) this.map.addLayer(line);\n this.applyProgress();\n this.applyLineStyle();\n this.installManeuver();\n }\n\n /**\n * Draw a bare line from coordinates, without a parsed OSRM route.\n *\n * {@link RouteLayer.draw} expects a {@link ParsedRoute} because it is\n * normally fed by {@link RouteLayer.route}. Callers that already have\n * geometry and nothing else — an agent tool result, a stored polyline,\n * a hand-built preview — had to invent a `ParsedRoute` with zeroed\n * distance and duration that `draw` never reads. This is that path,\n * named honestly.\n */\n drawGeometry(coordinates: [number, number][]): void {\n this.draw({\n distanceM: 0,\n durationS: 0,\n geometry: { type: \"LineString\", coordinates },\n raw: {},\n });\n }\n\n /**\n * Draw a set of routes: one selected, the rest as dimmer alternatives\n * beneath it. Offering alternatives is table stakes for a navigation UI,\n * and the selected route keeps every feature of {@link RouteLayer.draw}\n * (progress, manoeuvre arrow, corridors, route effects).\n *\n * Pass the index of the route to select; out-of-range values clamp to the\n * first route. Calling with a single route is equivalent to `draw`, and\n * calling with an empty array clears everything.\n */\n drawAlternatives(routes: ParsedRoute[], selectedIndex = 0): void {\n if (routes.length === 0) {\n this.clear();\n return;\n }\n const index = selectedIndex >= 0 && selectedIndex < routes.length ? selectedIndex : 0;\n this.alternatives = routes.filter((_, i) => i !== index);\n this.altOriginalIndices = routes.map((_, i) => i).filter((i) => i !== index);\n // Alternatives are installed first so they land beneath the selected\n // route's casing without needing a beforeId.\n this.installAlternatives();\n this.draw(routes[index]!);\n }\n\n /** Which alternatives are currently drawn, in the order given. */\n get alternativeRoutes(): readonly ParsedRoute[] {\n return this.alternatives;\n }\n\n /**\n * Register a click handler for the alternative lines. The index is the\n * position within the array last passed to\n * {@link RouteLayer.drawAlternatives}, so a caller can re-issue that call\n * with the new selection. Passing `undefined` removes the handler.\n */\n onSelectAlternative(handler: ((index: number) => void) | undefined): void {\n this.selectHandler = handler;\n }\n\n /**\n * Draw ferry legs of the selected route as dashes over its line, so water\n * crossings do not read as driving.\n *\n * Supplied as explicit geometries rather than derived from the route,\n * because `line-dasharray` cannot be data-driven: a ferry leg needs its\n * own layer, and only the caller knows which parts of their route are\n * ferries.\n */\n setFerrySegments(segments: [number, number][][]): void {\n this.ferrySegments = segments;\n if (this.map.isStyleLoaded()) this.installFerry();\n }\n\n /** Remove the ferry dashes. */\n clearFerrySegments(): void {\n this.ferrySegments = [];\n if (this.map.getLayer(this.ferryLayerId)) this.map.removeLayer(this.ferryLayerId);\n if (this.map.getSource(this.ferrySourceId)) this.map.removeSource(this.ferrySourceId);\n }\n\n /** Add-or-update the alternative-route source and its two layers. */\n private installAlternatives(): void {\n if (this.alternatives.length === 0) {\n this.removeAlternativeLayers();\n return;\n }\n if (!this.map.isStyleLoaded()) return; // handleStyleLoad retries.\n const data = {\n type: \"FeatureCollection\" as const,\n features: this.alternatives.map((route, i) => ({\n type: \"Feature\" as const,\n properties: { index: i },\n geometry: route.geometry,\n })),\n };\n const existing = this.map.getSource(this.altSourceId) as GeoJSONSource | undefined;\n if (existing) existing.setData(data);\n else this.map.addSource(this.altSourceId, { type: \"geojson\", data });\n\n // Below the selected route. Without a beforeId these would append on\n // top whenever the selected route was drawn first, which reads as the\n // alternatives being the chosen one.\n const below = this.map.getLayer(this.casingLayerId) ? this.casingLayerId : undefined;\n if (!this.map.getLayer(this.altCasingLayerId)) {\n this.map.addLayer({\n id: this.altCasingLayerId,\n type: \"line\",\n source: this.altSourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": this.altCasingColor,\n \"line-width\": 7,\n \"line-opacity\": 0.55,\n },\n } as LineLayerSpecification, below);\n }\n if (!this.map.getLayer(this.altLineLayerId)) {\n this.map.addLayer({\n id: this.altLineLayerId,\n type: \"line\",\n source: this.altSourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": this.altColor,\n \"line-width\": 4,\n \"line-opacity\": 0.9,\n },\n } as LineLayerSpecification, below);\n this.map.on(\"click\", this.altLineLayerId, this.handleAlternativeClick);\n }\n }\n\n private readonly handleAlternativeClick = (event: {\n features?: Array<{ properties?: Record<string, unknown> | null }>;\n }): void => {\n if (!this.selectHandler) return;\n const raw = event.features?.[0]?.properties?.[\"index\"];\n const position = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isInteger(position)) return;\n // `index` is the position among the alternatives; the caller thinks in\n // positions within the array they passed, so translate before calling.\n const original = this.altOriginalIndices[position];\n if (original !== undefined) this.selectHandler(original);\n };\n\n /** Original array position of each drawn alternative, by its own index. */\n private altOriginalIndices: number[] = [];\n\n private removeAlternativeLayers(): void {\n if (this.map.getLayer(this.altLineLayerId)) {\n this.map.off(\"click\", this.altLineLayerId, this.handleAlternativeClick);\n this.map.removeLayer(this.altLineLayerId);\n }\n if (this.map.getLayer(this.altCasingLayerId)) this.map.removeLayer(this.altCasingLayerId);\n if (this.map.getSource(this.altSourceId)) this.map.removeSource(this.altSourceId);\n }\n\n /** Add-or-update the ferry-dash overlay above the selected route. */\n private installFerry(): void {\n if (this.ferrySegments.length === 0) {\n this.clearFerrySegments();\n return;\n }\n if (!this.map.isStyleLoaded()) return; // handleStyleLoad retries.\n const data = {\n type: \"FeatureCollection\" as const,\n features: this.ferrySegments.map((coordinates) => ({\n type: \"Feature\" as const,\n properties: {},\n geometry: { type: \"LineString\" as const, coordinates },\n })),\n };\n const existing = this.map.getSource(this.ferrySourceId) as GeoJSONSource | undefined;\n if (existing) existing.setData(data);\n else this.map.addSource(this.ferrySourceId, { type: \"geojson\", data });\n if (!this.map.getLayer(this.ferryLayerId)) {\n this.map.addLayer({\n id: this.ferryLayerId,\n type: \"line\",\n source: this.ferrySourceId,\n layout: { \"line-cap\": \"butt\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": this.ferryColor,\n \"line-width\": 2.5,\n \"line-dasharray\": [1.2, 1.6],\n },\n } as LineLayerSpecification);\n }\n }\n\n /**\n * Override the drawn line's paint at runtime, over whatever the design or\n * the built-in look set.\n *\n * Route styling is not always static: a route can be provisional, or a\n * straight-line approximation that must not be mistaken for a surveyed\n * one. That is a paint change on a route already drawn, so it belongs\n * here rather than in the constructor's design.\n *\n * Overrides survive style reloads. Pass `{}` to clear them.\n */\n setLineStyle(style: RouteLineStyle): void {\n this.lineStyle = Object.keys(style).length > 0 ? style : undefined;\n this.applyLineStyle();\n }\n\n /** Apply any runtime override; a no-op when the layers are absent. */\n private applyLineStyle(): void {\n const style = this.lineStyle;\n if (!style) return;\n if (this.map.getLayer(this.lineLayerId)) {\n if (style.color !== undefined) {\n this.map.setPaintProperty(this.lineLayerId, \"line-color\", style.color);\n }\n if (style.dash !== undefined) {\n // MapLibre has no \"unset\"; [1, 0] is the documented solid pattern.\n this.map.setPaintProperty(\n this.lineLayerId,\n \"line-dasharray\",\n style.dash ?? [1, 0],\n );\n }\n }\n if (style.casingOpacity !== undefined && this.map.getLayer(this.casingLayerId)) {\n this.map.setPaintProperty(this.casingLayerId, \"line-opacity\", style.casingOpacity);\n }\n }\n\n /**\n * Sets how much of the route has been travelled, as a fraction in `[0, 1]`\n * of the line's length. The travelled part dims to `progressColor` (the\n * \"vanishing route line\"); `0` restores the untinted line. The value is\n * remembered across {@link draw} calls and style swaps. Pair with the\n * guidance module's distance-remaining to derive the fraction.\n */\n setProgress(fraction: number): void {\n this.progress = Math.min(1, Math.max(0, fraction));\n if (this.map.getLayer(this.lineLayerId)) this.applyProgress();\n }\n\n /** Applies the current progress fraction to the line layer's gradient. */\n private applyProgress(): void {\n const routeColor = this.design?.color ?? SIGNAL_BLUE;\n // A `step` on line-progress: travelled colour up to the fraction, the\n // route colour beyond it. line-progress only evaluates >= 0, so at 0 the\n // gradient is removed instead (also keeps non-progress usage identical\n // to the pre-progress behaviour).\n const gradient =\n this.progress > 0\n ? [\"step\", [\"line-progress\"], this.progressColor, this.progress, routeColor]\n : undefined;\n this.map.setPaintProperty(this.lineLayerId, \"line-gradient\", gradient);\n }\n\n /**\n * Shows (or moves) the upcoming-manoeuvre arrow: a small map-aligned\n * arrow at `lngLat` rotated to `bearingDeg` (clockwise from north).\n * Survives style swaps until {@link clearManeuver}.\n */\n setManeuver(lngLat: [number, number], bearingDeg: number): void {\n this.maneuver = { lngLat, bearingDeg };\n if (this.map.isStyleLoaded()) this.installManeuver();\n }\n\n /** Hides the manoeuvre arrow. */\n clearManeuver(): void {\n this.maneuver = undefined;\n if (this.map.getLayer(this.maneuverLayerId)) this.map.removeLayer(this.maneuverLayerId);\n if (this.map.getSource(this.maneuverSourceId)) this.map.removeSource(this.maneuverSourceId);\n }\n\n /** Add-or-update the manoeuvre arrow source/layer for the current style. */\n private installManeuver(): void {\n if (!this.maneuver) return;\n const data = {\n type: \"Feature\" as const,\n properties: { bearing: this.maneuver.bearingDeg },\n geometry: { type: \"Point\" as const, coordinates: this.maneuver.lngLat },\n };\n const source = this.map.getSource(this.maneuverSourceId) as GeoJSONSource | undefined;\n if (source) {\n source.setData(data);\n } else {\n this.map.addSource(this.maneuverSourceId, { type: \"geojson\", data });\n }\n // setStyle also wipes runtime images, so re-add alongside the layer.\n if (!this.map.hasImage(this.arrowImageId)) {\n this.map.addImage(this.arrowImageId, arrowImage());\n }\n if (!this.map.getLayer(this.maneuverLayerId)) {\n this.map.addLayer({\n id: this.maneuverLayerId,\n type: \"symbol\",\n source: this.maneuverSourceId,\n layout: {\n \"icon-image\": this.arrowImageId,\n \"icon-rotate\": [\"get\", \"bearing\"],\n \"icon-rotation-alignment\": \"map\",\n \"icon-allow-overlap\": true,\n \"icon-ignore-placement\": true,\n \"icon-size\": [\"interpolate\", [\"linear\"], [\"zoom\"], 12, 0.7, 18, 1.4],\n },\n });\n } else {\n this.map.setLayoutProperty(this.maneuverLayerId, \"icon-rotate\", [\"get\", \"bearing\"]);\n }\n }\n\n /**\n * Highlights average-speed enforcement corridors on the route line.\n *\n * A corridor is a stretch of the route between an entry and an exit\n * camera, so it is a property of the LINE, not a point alert: drawing it\n * as a tinted overlay above the route is what makes \"you are inside a\n * section check right now\" readable at a glance, and it is the only part\n * of the alert design that persists rather than firing once.\n *\n * Pass the corridor geometries (arrays of `[lng, lat]` along the route)\n * and, optionally, a Studio alerts design for the colour and opacity;\n * without one the layer uses the design carried by the owning map, then\n * a built-in tint. An empty array clears the highlight. Survives style\n * swaps like the route itself.\n */\n setAlertCorridors(\n corridors: readonly (readonly [number, number])[][],\n design?: NavAlertsDesign,\n ): void {\n if (design) this.alertsDesign = design;\n this.corridors = corridors.map((line) => line.map((p) => [p[0], p[1]] as [number, number]));\n if (this.corridors.length === 0) {\n this.clearAlertCorridors();\n return;\n }\n if (this.map.isStyleLoaded()) this.installCorridors();\n }\n\n /** Removes the corridor highlight (the route line itself is untouched). */\n clearAlertCorridors(): void {\n this.corridors = [];\n if (this.map.getLayer(this.corridorLayerId)) this.map.removeLayer(this.corridorLayerId);\n if (this.map.getSource(this.corridorSourceId)) this.map.removeSource(this.corridorSourceId);\n }\n\n /** Add-or-update the corridor source/layer for the current style. */\n private installCorridors(): void {\n if (this.corridors.length === 0) return;\n const data = {\n type: \"FeatureCollection\" as const,\n features: this.corridors.map((coordinates) => ({\n type: \"Feature\" as const,\n properties: {},\n geometry: { type: \"LineString\" as const, coordinates },\n })),\n };\n const source = this.map.getSource(this.corridorSourceId) as GeoJSONSource | undefined;\n if (source) {\n source.setData(data);\n } else {\n this.map.addSource(this.corridorSourceId, { type: \"geojson\", data });\n }\n const design = this.alertsDesign;\n const color = design?.corridorColor ?? CORRIDOR_COLOR;\n const opacity = design?.corridorOpacity ?? CORRIDOR_OPACITY;\n // Slightly wider than the route line so the tint reads as a highlight\n // around it rather than as a second, competing route.\n const width = (this.design?.width ?? 4.5) + 3;\n if (!this.map.getLayer(this.corridorLayerId)) {\n this.map.addLayer({\n id: this.corridorLayerId,\n type: \"line\",\n source: this.corridorSourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: {\n \"line-color\": color,\n \"line-width\": width,\n \"line-opacity\": opacity,\n },\n });\n } else {\n this.map.setPaintProperty(this.corridorLayerId, \"line-color\", color);\n this.map.setPaintProperty(this.corridorLayerId, \"line-opacity\", opacity);\n this.map.setPaintProperty(this.corridorLayerId, \"line-width\", width);\n }\n }\n\n /** Remove the route's layers and source from the map. */\n clear(): void {\n this.clearManeuver();\n this.clearAlertCorridors();\n this.clearFerrySegments();\n this.alternatives = [];\n this.altOriginalIndices = [];\n this.removeAlternativeLayers();\n for (const layerId of [this.lineLayerId, this.casingLayerId]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n this.lastRoute = undefined;\n // The route is gone; take any route effect with it.\n this.owner?.setRouteEffectGeometry(null);\n this.progress = 0;\n }\n\n /**\n * Remove the route and detach the layer's `style.load` listener. Call\n * when disposing of the layer (the map itself is left untouched).\n */\n destroy(): void {\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.clear();\n }\n}\n","/**\n * WCAG relative-luminance contrast, and the legibility gate for the\n * safety-alert chip.\n *\n * WHY THIS IS A SAFETY CHECK, NOT A TASTE CHECK: NHTSA's visual-manual\n * driver-distraction guidelines are built around single glances of under\n * two seconds away from the road. An alert chip whose text does not\n * resolve inside one such glance either costs the driver a second glance\n * or is not read at all, so a low-contrast colour pair is a defect in the\n * alert, not a stylistic preference. Studio therefore warns on a failing\n * pair rather than silently accepting it.\n *\n * The threshold is WCAG 2.x AA for large text (3:1) raised to the\n * body-text floor (4.5:1) - a chip is glanced at, not read at leisure, and\n * the guidance surface already renders at banner sizes.\n *\n * DELIBERATELY NOT the Rust `sn_style::contrast` helper (nor the\n * `check_style_contrast` MCP tool): the web SDK does not link Rust, and\n * Studio needs this in the browser as the customer drags a colour picker.\n * Same formula (WCAG 2.x `(L1 + 0.05) / (L2 + 0.05)` over sRGB\n * relative luminance), independently implemented and unit-tested.\n *\n * LOCKSTEP: mirrors the contrast helpers in `website/lib/studio-nav.ts`.\n */\n\nimport type { NavAlertsDesign } from \"./nav-design.js\";\n\n/** Minimum acceptable contrast ratio for alert-chip text on its background. */\nexport const ALERT_CONTRAST_MIN = 4.5;\n\n/**\n * Parses a CSS hex colour (`#rgb`, `#rrggbb`, `#rgba`, `#rrggbbaa`) into\n * 0-255 sRGB channels. Alpha is accepted and ignored - the chip composites\n * over an opaque background, so its alpha does not describe what the\n * driver sees. Returns `undefined` for any other notation (named colours,\n * `rgb()`, gradients): unparseable means \"cannot judge\", never \"fails\".\n */\nexport function parseHexColor(value: unknown): [number, number, number] | undefined {\n if (typeof value !== \"string\") return undefined;\n const hex = value.trim().replace(/^#/, \"\");\n if (!/^[0-9a-f]+$/i.test(hex)) return undefined;\n // #rgb shorthand: each digit doubles (`#f0a` -> `#ff00aa`).\n const expanded =\n hex.length === 3 || hex.length === 4\n ? hex\n .slice(0, 3)\n .split(\"\")\n .map((c) => c + c)\n .join(\"\")\n : hex.length === 6 || hex.length === 8\n ? hex.slice(0, 6)\n : undefined;\n if (expanded === undefined) return undefined;\n return [\n parseInt(expanded.slice(0, 2), 16),\n parseInt(expanded.slice(2, 4), 16),\n parseInt(expanded.slice(4, 6), 16),\n ];\n}\n\n/** WCAG 2.x relative luminance of an sRGB triple (channels 0-255). */\nexport function relativeLuminance(rgb: readonly [number, number, number]): number {\n const [r, g, b] = rgb.map((channel) => {\n const c = channel / 255;\n return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n }) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * WCAG 2.x contrast ratio between two hex colours, from 1 (identical) to\n * 21 (black on white). Order-independent. Returns `undefined` when either\n * colour cannot be parsed, so callers can distinguish \"not judgeable\" from\n * \"fails\".\n */\nexport function contrastRatio(a: unknown, b: unknown): number | undefined {\n const rgbA = parseHexColor(a);\n const rgbB = parseHexColor(b);\n if (!rgbA || !rgbB) return undefined;\n const lumA = relativeLuminance(rgbA);\n const lumB = relativeLuminance(rgbB);\n const lighter = Math.max(lumA, lumB);\n const darker = Math.min(lumA, lumB);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/** A chip colour pair that falls below {@link ALERT_CONTRAST_MIN}. */\nexport interface AlertContrastIssue {\n /** Which chip state the pair belongs to. */\n state: \"calm\" | \"escalated\";\n /** The text colour of the failing pair. */\n textColor: string;\n /** The background colour of the failing pair. */\n background: string;\n /** The measured ratio, rounded to 2 dp. */\n ratio: number;\n /** The floor it failed to clear. */\n minimum: number;\n}\n\n/**\n * Every chip colour pair in `design` that fails the contrast floor, in\n * state order. An empty array means both states are legible (or, for\n * colours this module cannot parse, not judgeable - those are skipped\n * rather than reported as failures).\n *\n * Advisory by design: the parser stays lenient and never rejects a theme\n * on contrast. Studio surfaces these as warnings next to the pickers so a\n * designer sees the problem while choosing, which is the only moment the\n * warning can actually change the outcome.\n */\nexport function alertContrastIssues(design: NavAlertsDesign): AlertContrastIssue[] {\n const pairs: readonly (readonly [\"calm\" | \"escalated\", string, string])[] = [\n [\"calm\", design.textColor, design.background],\n [\"escalated\", design.escalatedTextColor, design.escalatedBackground],\n ];\n const issues: AlertContrastIssue[] = [];\n for (const [state, textColor, background] of pairs) {\n const ratio = contrastRatio(textColor, background);\n if (ratio === undefined || ratio >= ALERT_CONTRAST_MIN) continue;\n issues.push({\n state,\n textColor,\n background,\n ratio: Math.round(ratio * 100) / 100,\n minimum: ALERT_CONTRAST_MIN,\n });\n }\n return issues;\n}\n","/**\n * PositionPuck - the current-position marker, styled by a Studio design.\n *\n * A MapLibre `Marker`-based puck: a coloured dot with an optional heading\n * arrow, or a custom image (`https:`/`data:` URI, data payloads capped at\n * 64 KB - the same cap Studio enforces on upload) that replaces both and\n * falls back to the built-in dot if it fails to load. The marker survives\n * `setStyle` on its own (markers are DOM overlays, not style layers), so\n * no `style.load` re-install is needed.\n *\n * LOCKSTEP: the element structure and styling mirror `createPuckElement` /\n * `stylePuckElement` in the Studio client\n * (`website/app/studio/StudioClient.tsx`), so a theme's puck renders here\n * exactly as Studio previews it.\n *\n * Like `MapMapMap` (see map.ts), this module imports the SDK's bundled\n * maplibre-gl for the `Marker` constructor - a purely structural typing\n * (the `LogoControl` pattern) is not possible because a Marker must be\n * constructed, not just duck-typed.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type { Map as MlMap, Marker } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { defaultNavDesign, type NavPuckDesign } from \"./nav-design.js\";\n\n/** Maximum accepted `data:` puck-image payload (matches Studio's upload cap). */\nexport const MAX_PUCK_IMAGE_BYTES = 64 * 1024;\n\n/**\n * Approximate decoded byte size of a `data:` URI payload (base64 payloads\n * decode to 3/4 of their character count; other payloads are counted as-is,\n * an upper bound for percent-encoded text).\n */\nfunction dataUriBytes(uri: string): number {\n const comma = uri.indexOf(\",\");\n const payload = comma === -1 ? \"\" : uri.slice(comma + 1);\n const meta = comma === -1 ? uri : uri.slice(0, comma);\n return /;base64$/i.test(meta) || /;base64;/i.test(meta)\n ? Math.floor((payload.length * 3) / 4)\n : payload.length;\n}\n\n/** The design's image URL, or `undefined` when unusable (built-in puck). */\nfunction effectiveImageUrl(design: NavPuckDesign): string | undefined {\n const url = design.imageUrl?.trim();\n if (!url) return undefined;\n if (/^data:/i.test(url) && dataUriBytes(url) > MAX_PUCK_IMAGE_BYTES) {\n return undefined;\n }\n return url;\n}\n\n/**\n * The signed shortest-arc rotation from `fromDeg` to `toDeg`, in degrees.\n * Always in `(-180, 180]`, so a heading tween never spins the long way\n * round the compass (350° -> 10° is +20°, not -340°).\n */\nexport function shortestArcDeg(fromDeg: number, toDeg: number): number {\n const raw = (((toDeg - fromDeg) % 360) + 360) % 360;\n return raw > 180 ? raw - 360 : raw;\n}\n\n/** Options for {@link PositionPuck}. */\nexport interface PositionPuckOptions {\n /**\n * Animate between fixes instead of snapping (default `true`). Position\n * lerps linearly and heading tweens along the shortest arc, over a\n * duration adapted to the observed fix interval (like the\n * `NavigationCamera` glide, so puck and camera arrive together). Falls\n * back to instant placement where `requestAnimationFrame` is missing.\n */\n interpolate?: boolean;\n /** Test seam: clock override, defaults to `Date.now`. */\n now?: () => number;\n /** Test seam: frame scheduler override, defaults to rAF. */\n requestFrame?: (callback: () => void) => number;\n /** Test seam: frame canceller override, defaults to cancelAnimationFrame. */\n cancelFrame?: (handle: number) => void;\n}\n\n/** Longest tween between fixes, ms (also the camera's default glide). */\nconst MAX_TWEEN_MS = 900;\n/** Shortest tween worth animating, ms; below this the move is instant. */\nconst MIN_TWEEN_MS = 100;\n\n/** A current-position puck marker for MapMap maps. */\nexport class PositionPuck {\n /** The puck's root DOM element (the Marker element). */\n readonly element: HTMLElement;\n private readonly map: MlMap;\n private readonly marker: Marker;\n private readonly design: NavPuckDesign;\n private added = false;\n private readonly interpolate: boolean;\n private readonly now: () => number;\n private readonly requestFrame?: (callback: () => void) => number;\n private readonly cancelFrame?: (handle: number) => void;\n private frameHandle: number | undefined;\n /** The position/heading currently rendered on the marker. */\n private rendered: { lat: number; lon: number; heading: number } | undefined;\n private lastFixAt: number | undefined;\n\n /**\n * Creates the puck (not yet on the map - it appears on the first\n * {@link setLocation}). The design defaults to the map's\n * `navDesign.puck` when given a `MapMapMap` whose theme carried an\n * `extra.nav` block, then to the built-in blue puck.\n */\n constructor(map: MapMapMap | MlMap, design?: NavPuckDesign, options?: PositionPuckOptions) {\n this.map = map instanceof MapMapMap ? map.map : map;\n this.design =\n design ??\n (map instanceof MapMapMap ? map.navDesign?.puck : undefined) ??\n defaultNavDesign().puck;\n this.element = createPuckElement();\n stylePuckElement(this.element, this.design);\n this.interpolate = options?.interpolate ?? true;\n this.now = options?.now ?? Date.now;\n const g = globalThis as {\n requestAnimationFrame?: (cb: FrameRequestCallback) => number;\n cancelAnimationFrame?: (handle: number) => void;\n };\n this.requestFrame =\n options?.requestFrame ??\n (g.requestAnimationFrame ? (cb) => g.requestAnimationFrame!(() => cb()) : undefined);\n this.cancelFrame =\n options?.cancelFrame ?? (g.cancelAnimationFrame ? (h) => g.cancelAnimationFrame!(h) : undefined);\n // Map-aligned rotation/pitch: the puck lies flat on the map and its\n // heading rotates with the camera bearing, as in the Studio preview.\n this.marker = new maplibregl.Marker({\n element: this.element,\n rotationAlignment: \"map\",\n pitchAlignment: \"map\",\n });\n }\n\n /**\n * Moves the puck (adding it to the map on the first call). `headingDeg`\n * rotates the whole element - arrow or custom image - clockwise from\n * north; omit it to keep the previous heading.\n *\n * With interpolation on (the default) every call after the first glides\n * from the currently rendered position - a fix arriving mid-tween\n * retargets smoothly rather than jumping.\n */\n setLocation(location: { lat: number; lon: number }, headingDeg?: number): void {\n const first = !this.added;\n const nowMs = this.now();\n const interval = this.lastFixAt === undefined ? MAX_TWEEN_MS : nowMs - this.lastFixAt;\n this.lastFixAt = nowMs;\n this.cancelTween();\n const from = this.rendered;\n const target = {\n lat: location.lat,\n lon: location.lon,\n heading: headingDeg ?? from?.heading ?? 0,\n };\n const duration = Math.min(MAX_TWEEN_MS, interval);\n if (first || !this.interpolate || !this.requestFrame || !from || duration < MIN_TWEEN_MS) {\n this.render(target);\n } else {\n this.tween(from, target, nowMs, duration);\n }\n if (first) {\n this.marker.addTo(this.map);\n this.added = true;\n }\n }\n\n /** Removes the puck from the map (cancelling any tween). `setLocation` re-adds it. */\n remove(): void {\n this.cancelTween();\n this.marker.remove();\n this.added = false;\n }\n\n /** Applies a position/heading to the marker immediately. */\n private render(state: { lat: number; lon: number; heading: number }): void {\n this.marker.setLngLat([state.lon, state.lat]);\n this.marker.setRotation(state.heading);\n this.rendered = state;\n }\n\n /** Runs a linear position lerp + shortest-arc heading tween via rAF. */\n private tween(\n from: { lat: number; lon: number; heading: number },\n to: { lat: number; lon: number; heading: number },\n startedAt: number,\n duration: number,\n ): void {\n const headingDelta = shortestArcDeg(from.heading, to.heading);\n const step = (): void => {\n const t = Math.min(1, (this.now() - startedAt) / duration);\n this.render({\n lat: from.lat + (to.lat - from.lat) * t,\n lon: from.lon + (to.lon - from.lon) * t,\n heading: from.heading + headingDelta * t,\n });\n if (t < 1) {\n this.frameHandle = this.requestFrame!(step);\n } else {\n this.frameHandle = undefined;\n // Land exactly on the target heading (mod-360 of the tween end).\n this.render(to);\n }\n };\n this.frameHandle = this.requestFrame!(step);\n }\n\n /** Cancels an in-flight tween, leaving the marker where it rendered last. */\n private cancelTween(): void {\n if (this.frameHandle !== undefined) {\n this.cancelFrame?.(this.frameHandle);\n this.frameHandle = undefined;\n }\n }\n}\n\n/**\n * The puck element: a dot plus an optional heading-arrow triangle, and a\n * (hidden by default) custom-image slot that replaces both when the design\n * carries an `imageUrl`. LOCKSTEP with Studio's `createPuckElement`.\n */\nfunction createPuckElement(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"PositionPuck requires a DOM environment\");\n const el = doc.createElement(\"div\");\n el.className = \"mapmap-puck\";\n el.style.position = \"relative\";\n const arrow = doc.createElement(\"div\");\n arrow.dataset[\"part\"] = \"arrow\";\n const dot = doc.createElement(\"div\");\n dot.dataset[\"part\"] = \"dot\";\n const img = doc.createElement(\"img\");\n img.dataset[\"part\"] = \"image\";\n img.alt = \"\";\n img.draggable = false;\n img.style.display = \"none\";\n el.append(arrow, dot, img);\n return el;\n}\n\n/**\n * Applies a puck design to the element. LOCKSTEP with Studio's\n * `stylePuckElement`: same sizes, colours, shadows and image fallback (a\n * URL that fails to load is remembered on the element and the built-in\n * puck shows instead).\n */\nfunction stylePuckElement(el: HTMLElement, puck: NavPuckDesign): void {\n const dot = el.querySelector<HTMLElement>(\"[data-part='dot']\");\n const arrow = el.querySelector<HTMLElement>(\"[data-part='arrow']\");\n const img = el.querySelector<HTMLImageElement>(\"[data-part='image']\");\n if (!dot || !arrow || !img) return;\n const s = puck.size;\n el.style.width = `${s}px`;\n el.style.height = `${s}px`;\n const url = effectiveImageUrl(puck) ?? \"\";\n if (url !== \"\" && el.dataset[\"imageFailed\"] !== url) {\n if (img.getAttribute(\"src\") !== url) {\n img.onerror = () => {\n el.dataset[\"imageFailed\"] = url;\n img.removeAttribute(\"src\");\n stylePuckElement(el, puck);\n };\n img.src = url;\n }\n img.style.cssText =\n `display:block;position:absolute;inset:0;width:${s}px;height:${s}px;` +\n \"object-fit:contain;filter:drop-shadow(0 1px 4px rgba(0,0,0,0.5))\";\n dot.style.cssText = \"display:none\";\n arrow.style.cssText = \"display:none\";\n return;\n }\n img.onerror = null;\n if (img.getAttribute(\"src\") !== null) img.removeAttribute(\"src\");\n img.style.cssText = \"display:none\";\n dot.style.cssText =\n `position:absolute;inset:0;border-radius:50%;background:${puck.color};` +\n \"border:2px solid #ffffff;box-shadow:0 1px 6px rgba(0,0,0,0.45)\";\n arrow.style.cssText = puck.headingArrow\n ? `position:absolute;left:50%;top:${(-s * 0.55).toFixed(1)}px;transform:translateX(-50%);` +\n `width:0;height:0;border-left:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-right:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-bottom:${(s * 0.6).toFixed(1)}px solid ${puck.color}`\n : \"display:none\";\n}\n","/**\n * Auto day/night theme switching from sun position.\n *\n * A dependency-free solar calculator (the standard sunrise equation, as\n * published at https://en.wikipedia.org/wiki/Sunrise_equation, itself a\n * restatement of the NOAA solar calculation details,\n * https://gml.noaa.gov/grad/solcalc/calcdetails.html) plus a small\n * scheduler that flips between light and dark at sunrise/sunset. Nothing\n * here touches a map: pair {@link ThemeScheduler} with\n * `MapMapMap.setStyle(\"light\" | \"dark\")` (or any other callback) in the\n * app. Territory packages already ship paired light/dark styles, so the\n * switch works offline too.\n */\n\n/** Sun-times result: either both events, or a polar day/night marker. */\nexport type SunTimes = { sunrise: Date; sunset: Date } | \"polarDay\" | \"polarNight\";\n\nconst DEG = Math.PI / 180;\n/** Milliseconds per day. */\nconst DAY_MS = 86_400_000;\n/** Julian date of the Unix epoch. */\nconst JULIAN_EPOCH = 2_440_587.5;\n/** Julian date of the J2000 epoch. */\nconst J2000 = 2_451_545;\n\n/** Converts a Julian date to a JS `Date`. */\nfunction fromJulian(julian: number): Date {\n return new Date((julian - JULIAN_EPOCH) * DAY_MS);\n}\n\n/**\n * Sunrise and sunset (standard -0.833° horizon: refraction + solar disc)\n * for the civil day containing `date` (UTC) at `lat`/`lng`, or a polar\n * marker when the sun never crosses the horizon that day.\n */\nexport function sunTimes(date: Date, lat: number, lng: number): SunTimes {\n // Days since J2000, rounded to the nearest civil day at the longitude.\n const julianDay = Math.ceil(date.getTime() / DAY_MS + JULIAN_EPOCH - J2000 - 0.0009 + lng / 360);\n const meanSolarTime = julianDay + 0.0009 - lng / 360;\n const meanAnomalyDeg = (357.5291 + 0.98560028 * meanSolarTime) % 360;\n const m = meanAnomalyDeg * DEG;\n const centreDeg = 1.9148 * Math.sin(m) + 0.02 * Math.sin(2 * m) + 0.0003 * Math.sin(3 * m);\n const eclipticLngDeg = (meanAnomalyDeg + centreDeg + 180 + 102.9372) % 360;\n const l = eclipticLngDeg * DEG;\n const transit = J2000 + meanSolarTime + 0.0053 * Math.sin(m) - 0.0069 * Math.sin(2 * l);\n const sinDeclination = Math.sin(l) * Math.sin(23.4397 * DEG);\n const cosDeclination = Math.cos(Math.asin(sinDeclination));\n const cosHourAngle =\n (Math.sin(-0.833 * DEG) - Math.sin(lat * DEG) * sinDeclination) /\n (Math.cos(lat * DEG) * cosDeclination);\n if (cosHourAngle < -1) return \"polarDay\";\n if (cosHourAngle > 1) return \"polarNight\";\n const hourAngleDeg = Math.acos(cosHourAngle) / DEG;\n return {\n sunrise: fromJulian(transit - hourAngleDeg / 360),\n sunset: fromJulian(transit + hourAngleDeg / 360),\n };\n}\n\n/** The theme the sun dictates at `date` for `lat`/`lng`. */\nexport function resolveTheme(date: Date, lat: number, lng: number): \"light\" | \"dark\" {\n const times = sunTimes(date, lat, lng);\n if (times === \"polarDay\") return \"light\";\n if (times === \"polarNight\") return \"dark\";\n return date >= times.sunrise && date < times.sunset ? \"light\" : \"dark\";\n}\n\n/** Options for {@link ThemeScheduler}. */\nexport interface ThemeSchedulerOptions {\n /** Latitude used for the solar calculation. */\n lat: number;\n /** Longitude used for the solar calculation. */\n lng: number;\n /** Called (immediately on construction, then at each sunrise) for light. */\n onLight: () => void;\n /** Called (immediately on construction, then at each sunset) for dark. */\n onDark: () => void;\n /** Test seam: clock override, defaults to `Date.now`. */\n now?: () => number;\n /** Test seam: timer override, defaults to `setTimeout`. */\n setTimeoutFn?: (callback: () => void, ms: number) => ReturnType<typeof setTimeout>;\n /** Test seam: timer canceller, defaults to `clearTimeout`. */\n clearTimeoutFn?: (handle: ReturnType<typeof setTimeout>) => void;\n}\n\n/** Re-check interval under polar day/night, where no flip is scheduled. */\nconst POLAR_RECHECK_MS = 6 * 3_600_000;\n/** Margin added past a boundary so the re-evaluation lands beyond it. */\nconst BOUNDARY_MARGIN_MS = 1_000;\n\n/**\n * Applies the sun-appropriate theme now and at every subsequent\n * sunrise/sunset until {@link dispose}. No OSS map SDK ships this\n * out of the box; pair with the OS dark-mode signal in the app if the\n * user's system preference should win instead.\n */\nexport class ThemeScheduler {\n private lat: number;\n private lng: number;\n private readonly onLight: () => void;\n private readonly onDark: () => void;\n private readonly now: () => number;\n private readonly setTimeoutFn: (cb: () => void, ms: number) => ReturnType<typeof setTimeout>;\n private readonly clearTimeoutFn: (handle: ReturnType<typeof setTimeout>) => void;\n private handle: ReturnType<typeof setTimeout> | undefined;\n private applied: \"light\" | \"dark\" | undefined;\n private disposed = false;\n\n constructor(options: ThemeSchedulerOptions) {\n this.lat = options.lat;\n this.lng = options.lng;\n this.onLight = options.onLight;\n this.onDark = options.onDark;\n this.now = options.now ?? Date.now;\n this.setTimeoutFn = options.setTimeoutFn ?? ((cb, ms) => setTimeout(cb, ms));\n this.clearTimeoutFn = options.clearTimeoutFn ?? ((h) => clearTimeout(h));\n this.evaluate();\n }\n\n /** The theme most recently applied, if any. */\n get current(): \"light\" | \"dark\" | undefined {\n return this.applied;\n }\n\n /** Moves the observer (e.g. a new GPS fix region) and re-evaluates. */\n setPosition(lat: number, lng: number): void {\n this.lat = lat;\n this.lng = lng;\n this.evaluate();\n }\n\n /** Stops all future flips. */\n dispose(): void {\n this.disposed = true;\n if (this.handle !== undefined) this.clearTimeoutFn(this.handle);\n this.handle = undefined;\n }\n\n /** Applies the theme for now and arms the timer for the next boundary. */\n private evaluate(): void {\n if (this.disposed) return;\n if (this.handle !== undefined) {\n this.clearTimeoutFn(this.handle);\n this.handle = undefined;\n }\n const nowDate = new Date(this.now());\n const theme = resolveTheme(nowDate, this.lat, this.lng);\n if (theme !== this.applied) {\n this.applied = theme;\n (theme === \"light\" ? this.onLight : this.onDark)();\n }\n const delay = this.nextBoundaryDelay(nowDate);\n this.handle = this.setTimeoutFn(() => this.evaluate(), delay);\n }\n\n /** Milliseconds until the next sunrise/sunset (or the polar re-check). */\n private nextBoundaryDelay(nowDate: Date): number {\n const nowMs = nowDate.getTime();\n // Today's events, then tomorrow's: the next boundary is the earliest\n // event strictly in the future.\n for (const dayOffset of [0, 1]) {\n const times = sunTimes(new Date(nowMs + dayOffset * DAY_MS), this.lat, this.lng);\n if (times === \"polarDay\" || times === \"polarNight\") continue;\n for (const event of [times.sunrise, times.sunset]) {\n const delta = event.getTime() - nowMs;\n if (delta > 0) return delta + BOUNDARY_MARGIN_MS;\n }\n }\n return POLAR_RECHECK_MS;\n }\n}\n","/**\n * Runtime label-language switching.\n *\n * MapMap tiles carry OpenMapTiles multilingual `name:*` fields\n * (https://openmaptiles.org/schema/), so a map can switch label language\n * without new tiles: rewrite each symbol layer's `text-field` to prefer\n * `name:{language}`. `setMapLanguage(map, \"de\")` does exactly that for\n * every layer whose text-field reads name fields (other text — road refs,\n * house numbers — is left untouched). Pass `null` to restore the compiled\n * style's default (`name:en` first).\n *\n * Server-side, themes can bake a language in with `theme.language`; this\n * helper is the client-side equivalent for user-facing toggles. For\n * right-to-left scripts (Arabic, Hebrew) also install MapLibre's RTL text\n * plugin in the app (`maplibregl.setRTLTextPlugin(...)`) — the SDK does\n * not fetch remote scripts on your behalf.\n */\nimport type { Map as MlMap } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\n\n/** ISO 639 primary subtag plus optional region/script subtag, e.g. `pt-BR`. */\nconst LANGUAGE_TAG = /^[a-z]{2,3}(-[A-Za-z0-9]{2,4})?$/;\n\n/**\n * The `text-field` expression for labels in `language` — the requested\n * language first, the Latin transliteration second, the local name last.\n * `null` yields the compiled default (`name:en`, then `name`).\n */\nexport function languageTextField(language: string | null): unknown {\n if (language === null) {\n return [\"coalesce\", [\"get\", \"name:en\"], [\"get\", \"name\"]];\n }\n return [\n \"coalesce\",\n [\"get\", `name:${language}`],\n [\"get\", \"name:latin\"],\n [\"get\", \"name\"],\n ];\n}\n\n/**\n * True when a layer's `text-field` reads `name`/`name:*` properties —\n * i.e. it is a place/POI/road-name label whose language can switch.\n * Fields reading other properties (`ref` shields, house numbers) are not.\n */\nexport function isNameTextField(textField: unknown): boolean {\n if (typeof textField === \"string\") {\n // Token syntax: \"{name}\", \"{name:en} ({name:latin})\", …\n return /\\{name(?::[A-Za-z0-9-]+)?\\}/.test(textField);\n }\n if (Array.isArray(textField)) {\n if (\n textField.length === 2 &&\n textField[0] === \"get\" &&\n typeof textField[1] === \"string\"\n ) {\n return textField[1] === \"name\" || textField[1].startsWith(\"name:\");\n }\n return textField.some((part) => isNameTextField(part));\n }\n return false;\n}\n\n/**\n * Switches every name-label layer of the map's current style to\n * `language` (`null` restores the style's default). Returns the ids of\n * the layers it rewrote. Throws on a malformed language tag. Reapply\n * after `setStyle` — a style swap resets label languages.\n */\nexport function setMapLanguage(\n map: MapMapMap | MlMap,\n language: string | null,\n): string[] {\n if (language !== null && !LANGUAGE_TAG.test(language)) {\n throw new Error(\n `invalid language tag ${JSON.stringify(language)}; use e.g. \"de\", \"pt-BR\", \"zh-Hans\"`,\n );\n }\n const ml = map instanceof MapMapMap ? map.map : map;\n const layers = ml.getStyle()?.layers ?? [];\n const changed: string[] = [];\n for (const layer of layers) {\n if (layer.type !== \"symbol\") continue;\n const textField = (layer.layout as Record<string, unknown> | undefined)?.[\n \"text-field\"\n ];\n if (textField === undefined || !isNameTextField(textField)) continue;\n ml.setLayoutProperty(layer.id, \"text-field\", languageTextField(language));\n changed.push(layer.id);\n }\n return changed;\n}\n","/**\n * Probe batch upload - the browser side of opt-in aggregate collection.\n *\n * The wasm nav core (`@mapmap/core` `GuidanceSession`) accumulates aggregates\n * on-device and hands back the exact body to POST via `finishProbeJson()`;\n * this helper delivers it to the gateway's `POST /v1/probe`, with the same\n * status handling and retry policy as the mobile SDKs. Aggregates only - the\n * core is architecturally incapable of emitting a trajectory.\n *\n * Consent is the caller's responsibility: only upload for a key whose operator\n * has set `probe_opt_in`, and - in a browser - only with the user's opt-in\n * (ePrivacy/PECR) consent. See `docs/PROBE-SDK-INTEGRATION.md`.\n *\n * @example\n * ```ts\n * const body = session.finishProbeJson(arrived, Date.now());\n * if (body) void uploadProbeBatch(\"https://api.mapmap.ai\", apiKey, body);\n * ```\n */\n\n/** The outcome of an upload attempt. */\nexport type ProbeUploadOutcome =\n | \"accepted\" // 202 - stored\n | \"refused\" // 403 - key not opted in; not retried\n | \"notEnabled\" // 501 - server collection off (SN_PROBE_DIR unset); not retried\n | \"rejected\" // 400/other 4xx - malformed; not retried\n | \"gaveUp\"; // network error or 5xx after exhausting retries\n\n/** Options for {@link uploadProbeBatch}. All optional. */\nexport interface UploadProbeOptions {\n /** Injectable fetch (defaults to the global). */\n fetch?: typeof fetch;\n /** Total attempts including the first (default 4). */\n maxAttempts?: number;\n /** Attempt number → delay before the next try, ms (default `attempt*1000`). */\n backoffMs?: (attempt: number) => number;\n /** Injectable delay, for deterministic tests (default `setTimeout`). */\n sleep?: (ms: number) => Promise<void>;\n /** Abort signal forwarded to fetch. */\n signal?: AbortSignal;\n}\n\n/** The `/v1/probe` endpoint for a gateway origin (trailing slashes trimmed). */\nexport function buildProbeUrl(baseUrl: string): string {\n return `${baseUrl.replace(/\\/+$/, \"\")}/v1/probe`;\n}\n\n/**\n * POST one probe body to `{baseUrl}/v1/probe` with a bearer key. Transient\n * failures (network or `5xx`) are retried with bounded backoff; permanent ones\n * (`400`/`403`/`501`) are not. Resolves with the terminal outcome and never\n * rejects, so a fire-and-forget `void uploadProbeBatch(...)` is safe.\n *\n * @param body the string returned by `GuidanceSession.finishProbeJson()`.\n */\nexport async function uploadProbeBatch(\n baseUrl: string,\n apiKey: string,\n body: string,\n options: UploadProbeOptions = {},\n): Promise<ProbeUploadOutcome> {\n const doFetch = options.fetch ?? globalThis.fetch;\n const maxAttempts = options.maxAttempts ?? 4;\n const backoffMs = options.backoffMs ?? ((attempt) => attempt * 1000);\n const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));\n const url = buildProbeUrl(baseUrl);\n\n for (let attempt = 1; ; attempt++) {\n let outcome: ProbeUploadOutcome;\n try {\n const response = await doFetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body,\n signal: options.signal,\n });\n outcome = classifyStatus(response.status);\n } catch {\n outcome = \"gaveUp\";\n }\n\n if (outcome === \"gaveUp\" && attempt < maxAttempts) {\n await sleep(backoffMs(attempt));\n continue;\n }\n return outcome;\n }\n}\n\nfunction classifyStatus(status: number): ProbeUploadOutcome {\n if (status === 202) return \"accepted\";\n if (status === 403) return \"refused\";\n if (status === 501) return \"notEnabled\";\n if (status >= 500 && status <= 599) return \"gaveUp\";\n return \"rejected\";\n}\n","/**\n * PlacesLayer - drop your own places (store locations, depots, POIs) onto a\n * MapMap map: the store-finder use case.\n *\n * A GeoJSON source plus MapLibre layers, following the RouteLayer pattern:\n * native clustering (`cluster: true` on the source) with count badges,\n * click-to-expand clusters, a typed `onPlaceClick` callback and an optional\n * built-in popup, plus pure `nearest()` (haversine) and gateway-backed\n * `nearestByDriveTime()` (`POST /matrix`) helpers for \"which branch is\n * closest?\".\n *\n * Like RouteLayer, the layer survives `setStyle` (light/dark theme swaps):\n * places are re-installed on every `style.load`.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n CircleLayerSpecification,\n ExpressionSpecification,\n GeoJSONSource,\n MapLayerMouseEvent,\n Map as MlMap,\n Popup,\n SymbolLayerSpecification,\n} from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { SIGNAL_BLUE } from \"./route.js\";\n\n/** Mean Earth radius in metres (IUGG), as used by turf and PostGIS. */\nconst EARTH_RADIUS_M = 6371008.8;\n/** Font stack for cluster-count badges; ships with the MapMap default styles. */\nconst CLUSTER_TEXT_FONT = \"MapMap Sans Regular\";\n\n/** One place to show on the map - a store, depot, branch, POI. */\nexport interface Place {\n /** Stable unique id, e.g. your store number. */\n id: string;\n /** Display name. */\n name: string;\n /** Latitude, degrees. */\n lat: number;\n /** Longitude, degrees. */\n lon: number;\n /**\n * Arbitrary extra data (opening hours, phone, …). Every key is copied\n * verbatim onto the top level of the GeoJSON feature's `properties`,\n * alongside the reserved `id`, `name` and `__mapmapIndex` keys (which win\n * on collision) - so scalar values are directly addressable from a\n * data-driven `color` expression, e.g. `[\"get\", \"category\"]`. MapLibre\n * JSON-stringifies nested objects/arrays at render time, so keep anything\n * you want to style on as a top-level string/number/boolean. The whole\n * object also comes back on the place handed to `onPlaceClick` / `popup`.\n */\n properties?: Record<string, unknown>;\n}\n\n/** A GeoJSON Point feature, as accepted in a {@link PlacesFeatureCollection}. */\nexport interface PlacePointFeature {\n type: \"Feature\";\n id?: string | number;\n geometry: { type: \"Point\"; coordinates: number[] };\n properties?: Record<string, unknown> | null;\n}\n\n/**\n * A plain GeoJSON FeatureCollection of Points, accepted anywhere a `Place[]`\n * is (structurally compatible with `@types/geojson`'s\n * `FeatureCollection<Point>`). See {@link placesFromGeoJSON} for how ids and\n * names are derived.\n */\nexport interface PlacesFeatureCollection {\n type: \"FeatureCollection\";\n features: PlacePointFeature[];\n}\n\n/** Either input shape for {@link PlacesLayer} / `setPlaces`. */\nexport type PlacesInput = Place[] | PlacesFeatureCollection;\n\n/** A place with its straight-line distance attached (see `nearest`). */\nexport type PlaceWithDistance = Place & {\n /** Straight-line (haversine) distance from the origin, metres. */\n distanceM: number;\n};\n\n/** A place with gateway drive time attached (see `nearestByDriveTime`). */\nexport type PlaceWithDriveTime = Place & {\n /** Drive time from the origin, seconds. */\n durationS: number;\n /** Driven distance from the origin, metres (`null` when not returned). */\n distanceM: number | null;\n};\n\n/** A custom pin image for unclustered places. */\nexport interface PlacesIcon {\n /** Image URL (any format `Map#loadImage` accepts, e.g. PNG). */\n url: string;\n /** MapLibre `icon-size` scale factor. Defaults to `1`. */\n size?: number;\n}\n\n/** Options for {@link PlacesLayer.nearestByDriveTime}. */\nexport interface NearestByDriveTimeOptions {\n /** How many places to return. Defaults to `1`. */\n n?: number;\n /**\n * Gateway costing model, e.g. `\"auto\"` (default) or `\"truck\"` (Premium\n * price class - see `POST /matrix` in the API docs).\n */\n costing?: string;\n /**\n * Valhalla-style costing options forwarded verbatim, e.g.\n * `{ truck: { height: 4.0 } }`.\n */\n costingOptions?: Record<string, unknown>;\n}\n\nexport interface PlacesLayerOptions {\n /** Initial places. Also settable later via {@link PlacesLayer.setPlaces}. */\n places?: PlacesInput;\n /** Cluster nearby places into count badges. Defaults to `true`. */\n cluster?: boolean;\n /** Cluster radius in pixels. Defaults to MapLibre's `50`. */\n clusterRadius?: number;\n /** Max zoom to cluster at. Defaults to MapLibre's `14`. */\n clusterMaxZoom?: number;\n /**\n * Pin colour: a CSS colour string, or a MapLibre expression evaluated\n * against each feature's `properties` for per-category pins, e.g.\n * `[\"match\", [\"get\", \"category\"], \"food\", \"#e63946\", \"#3a86ff\"]` (see\n * {@link Place.properties} for what an expression can `get`). Defaults to\n * MapMap signal blue (`#3a86ff`). Only styles the default circle pins -\n * ignored with a custom `icon`. A cluster mixes categories, so an\n * expression never applies to clusters: they use `clusterColor`.\n */\n color?: string | ExpressionSpecification;\n /**\n * Cluster circle colour. Defaults to `color` when that is a plain string,\n * else to MapMap signal blue (a cluster mixes categories, so a\n * data-driven `color` expression cannot apply to it).\n */\n clusterColor?: string;\n /**\n * Custom pin image for unclustered places (a symbol layer instead of the\n * default circle). If the image fails to load, the circle look is used.\n */\n icon?: PlacesIcon;\n /**\n * Fit the map to the places the first time they are set. Defaults to\n * `false` (the map view is left alone).\n */\n fitBounds?: boolean;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-places\"`. */\n id?: string;\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Called when an individual (unclustered) place is clicked. */\n onPlaceClick?: (place: Place, lngLat: { lng: number; lat: number }) => void;\n /**\n * Built-in popup: return HTML (a string is set with `setHTML`, an element\n * with `setDOMContent`) and a `maplibregl.Popup` opens at the place on\n * click. Omit for no popup.\n */\n popup?: (place: Place) => string | HTMLElement;\n}\n\n/** The generated MapLibre source/layer ids (see {@link PlacesLayer.ids}). */\nexport interface PlacesLayerIds {\n /** The GeoJSON source id. */\n source: string;\n /** The unclustered-points layer id (circle, or symbol with `icon`). */\n points: string;\n /** The cluster circles layer id (only installed with `cluster: true`). */\n clusters: string;\n /** The cluster count badge layer id (only installed with `cluster: true`). */\n clusterCounts: string;\n}\n\n/** Options for {@link PlacesLayer.select}. */\nexport interface PlacesSelectOptions {\n /** Open the layer's configured `popup` at the place. Defaults to `true`. */\n popup?: boolean;\n /** Ease the camera to the place. Defaults to `true`. */\n flyTo?: boolean;\n /** Zoom for the camera move (with `flyTo`). Keeps the current zoom if omitted. */\n zoom?: number;\n}\n\n/**\n * Normalise a GeoJSON FeatureCollection of Points to `Place[]`. The id comes\n * from `feature.id`, then `properties.id`, then the feature index; the name\n * from `properties.name` (else `\"\"`). Non-Point features are skipped.\n */\nexport function placesFromGeoJSON(\n collection: PlacesFeatureCollection,\n): Place[] {\n const places: Place[] = [];\n collection.features.forEach((feature, index) => {\n if (feature.geometry?.type !== \"Point\") return;\n const [lon, lat] = feature.geometry.coordinates;\n if (typeof lon !== \"number\" || typeof lat !== \"number\") {\n throw new Error(`place feature ${index} has no [lon, lat] coordinates`);\n }\n const props = feature.properties ?? {};\n const rawId = feature.id ?? props[\"id\"];\n const place: Place = {\n id:\n typeof rawId === \"string\" || typeof rawId === \"number\"\n ? String(rawId)\n : String(index),\n name: typeof props[\"name\"] === \"string\" ? props[\"name\"] : \"\",\n lat,\n lon,\n };\n if (feature.properties) place.properties = feature.properties;\n places.push(place);\n });\n return places;\n}\n\n/** Straight-line (haversine) distance between two points, metres. */\nexport function haversineDistanceM(\n a: { lat: number; lon: number },\n b: { lat: number; lon: number },\n): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b.lat - a.lat);\n const dLon = rad(b.lon - a.lon);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/** The GeoJSON built for the source; one Point feature per place. */\ninterface PlacesSourceData {\n type: \"FeatureCollection\";\n features: {\n type: \"Feature\";\n geometry: { type: \"Point\"; coordinates: [number, number] };\n properties: Record<string, unknown>;\n }[];\n}\n\n/** Draws customer places on a MapLibre map, with clustering and popups. */\nexport class PlacesLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string | undefined;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly clustersLayerId: string;\n private readonly clusterCountLayerId: string;\n private readonly pointsLayerId: string;\n private readonly iconImageId: string;\n private readonly cluster: boolean;\n private readonly clusterRadius: number | undefined;\n private readonly clusterMaxZoom: number | undefined;\n private readonly color: string | ExpressionSpecification;\n private readonly clusterColor: string;\n private readonly icon: PlacesIcon | undefined;\n private readonly wantFitBounds: boolean;\n private readonly onPlaceClick:\n | ((place: Place, lngLat: { lng: number; lat: number }) => void)\n | undefined;\n private readonly popupFn:\n | ((place: Place) => string | HTMLElement)\n | undefined;\n private places: Place[] = [];\n private data: PlacesSourceData | undefined;\n private popup: Popup | undefined;\n private fitted = false;\n private destroyed = false;\n\n constructor(map: MapMapMap | MlMap, options: PlacesLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n } else {\n this.map = map;\n this.baseUrl = options.baseUrl?.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n const id = options.id ?? \"mapmap-places\";\n this.sourceId = `${id}-src`;\n this.clustersLayerId = `${id}-clusters`;\n this.clusterCountLayerId = `${id}-cluster-count`;\n this.pointsLayerId = `${id}-points`;\n this.iconImageId = `${id}-icon`;\n this.cluster = options.cluster ?? true;\n this.clusterRadius = options.clusterRadius;\n this.clusterMaxZoom = options.clusterMaxZoom;\n this.color = options.color ?? SIGNAL_BLUE;\n this.clusterColor =\n options.clusterColor ??\n (typeof this.color === \"string\" ? this.color : SIGNAL_BLUE);\n this.icon = options.icon;\n this.wantFitBounds = options.fitBounds ?? false;\n this.onPlaceClick = options.onPlaceClick;\n this.popupFn = options.popup;\n\n // Same lifecycle as RouteLayer: runtime sources/layers are wiped on\n // every setStyle (theme swap), so re-install on each style.load - which\n // also completes a setPlaces that arrived before the style had loaded.\n this.map.on(\"style.load\", this.handleStyleLoad);\n // Delegated layer events survive layer re-installation (they are bound\n // to the layer id, not the layer object), so bind them once here.\n this.map.on(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.on(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.on(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.on(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n\n if (options.places) this.setPlaces(options.places);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.data) this.install(this.data);\n };\n\n private readonly handleMouseEnter = (): void => {\n this.map.getCanvas().style.cursor = \"pointer\";\n };\n\n private readonly handleMouseLeave = (): void => {\n this.map.getCanvas().style.cursor = \"\";\n };\n\n private readonly handlePlaceClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const index: unknown = feature.properties?.[\"__mapmapIndex\"];\n if (typeof index !== \"number\") return;\n const place = this.places[index];\n if (!place) return;\n this.onPlaceClick?.(place, { lng: e.lngLat.lng, lat: e.lngLat.lat });\n if (this.popupFn) this.openPopup(place);\n };\n\n private readonly handleClusterClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const clusterId: unknown = feature.properties?.[\"cluster_id\"];\n if (typeof clusterId !== \"number\") return;\n const source = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (!source) return;\n const geometry = feature.geometry;\n if (geometry.type !== \"Point\") return;\n const [lng, lat] = geometry.coordinates;\n if (typeof lng !== \"number\" || typeof lat !== \"number\") return;\n void source\n .getClusterExpansionZoom(clusterId)\n .then((zoom) => {\n if (!this.destroyed) this.map.easeTo({ center: [lng, lat], zoom });\n })\n .catch(() => {\n /* cluster no longer in the source (data changed mid-flight) */\n });\n };\n\n /**\n * Replace the layer's places - a `Place[]` or a GeoJSON FeatureCollection\n * of Points. Never silently drops an update: once the source exists the\n * data is applied immediately, even while `isStyleLoaded()` is transiently\n * `false` mid-render (search-as-you-type just works); calls made before\n * the source has first been installed are stashed - the latest one wins -\n * and installed on the next `style.load`. With `fitBounds: true` the\n * first non-empty set also fits the map view.\n */\n setPlaces(places: PlacesInput): void {\n this.places = Array.isArray(places) ? places : placesFromGeoJSON(places);\n this.data = {\n type: \"FeatureCollection\",\n features: this.places.map((place, index) => ({\n type: \"Feature\",\n geometry: { type: \"Point\", coordinates: [place.lon, place.lat] },\n properties: {\n ...place.properties,\n id: place.id,\n name: place.name,\n __mapmapIndex: index,\n },\n })),\n };\n if (this.wantFitBounds && !this.fitted && this.places.length > 0) {\n this.fitted = true;\n this.map.fitBounds(boundsOf(this.places), { padding: 48, maxZoom: 15 });\n }\n const source = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (source) {\n // setData on an existing source is safe even while isStyleLoaded()\n // is transiently false (tiles/cluster work in flight) - never drop\n // an update once the source is installed.\n source.setData(this.data);\n } else if (this.map.isStyleLoaded()) {\n this.install(this.data);\n }\n // else: kept in this.data (latest call wins) until handleStyleLoad.\n }\n\n /** The layer's current places (normalised to `Place[]`). */\n get current(): Place[] {\n return this.places;\n }\n\n /**\n * The generated MapLibre source/layer ids - public API for escape-hatch\n * styling (`map.setPaintProperty`, `queryRenderedFeatures`, …) beyond the\n * layer's options. Stable for the layer's lifetime, derived from the `id`\n * option (default `\"mapmap-places\"`). The cluster ids are only installed\n * on the map with `cluster: true` (the default), and `points` is a circle\n * layer by default or a symbol layer once a custom `icon` has loaded.\n */\n get ids(): PlacesLayerIds {\n return {\n source: this.sourceId,\n points: this.pointsLayerId,\n clusters: this.clustersLayerId,\n clusterCounts: this.clusterCountLayerId,\n };\n }\n\n /**\n * Programmatically select a place by id - list-to-map sync for a store\n * finder's results list. Opens the layer's configured `popup` at the\n * place (`popup: false` to skip, no-op without a `popup` option) and\n * eases the camera to it (`flyTo: false` to skip; `zoom` to also zoom).\n * Returns the selected place, or `undefined` for an unknown id (in which\n * case nothing happens). Does NOT invoke `onPlaceClick` - a programmatic\n * selection is not a user click.\n */\n select(id: string, options: PlacesSelectOptions = {}): Place | undefined {\n const place = this.places.find((p) => p.id === id);\n if (!place) return undefined;\n if (options.flyTo ?? true) {\n this.map.easeTo({\n center: [place.lon, place.lat],\n ...(options.zoom !== undefined ? { zoom: options.zoom } : {}),\n });\n }\n if (options.popup ?? true) this.openPopup(place);\n return place;\n }\n\n /** Close the popup opened by {@link select} or a place click, if any. */\n deselect(): void {\n this.popup?.remove();\n this.popup = undefined;\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by straight-line\n * (haversine) distance, each with `distanceM` attached. Pure and instant -\n * no network. For road-network answers use {@link nearestByDriveTime}.\n */\n nearest(origin: { lat: number; lon: number }, n = 1): PlaceWithDistance[] {\n return this.places\n .map((place) => ({ ...place, distanceM: haversineDistanceM(origin, place) }))\n .sort((a, b) => a.distanceM - b.distanceM)\n .slice(0, Math.max(0, n));\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by drive time, via the\n * gateway's `POST /matrix` (one source, all places as targets). Resolves\n * to places sorted by `durationS` ascending, with the driven `distanceM`\n * attached; unreachable places (`null` duration) are dropped. Needs the\n * gateway `baseUrl`/`apiKey` - picked up from a `MapMapMap` automatically,\n * or pass them as layer options.\n */\n async nearestByDriveTime(\n origin: { lat: number; lon: number },\n options: NearestByDriveTimeOptions = {},\n ): Promise<PlaceWithDriveTime[]> {\n if (!this.baseUrl) {\n throw new Error(\n \"PlacesLayer needs a baseUrl (or a MapMapMap) for nearestByDriveTime\",\n );\n }\n if (this.places.length === 0) return [];\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n const body: Record<string, unknown> = {\n sources: [{ lat: origin.lat, lon: origin.lon }],\n targets: this.places.map((p) => ({ lat: p.lat, lon: p.lon })),\n costing: options.costing ?? \"auto\",\n };\n if (options.costingOptions) body[\"costing_options\"] = options.costingOptions;\n\n const response = await fetch(`${this.baseUrl}/matrix`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n const payload: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `matrix request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n const { durations, distances } = matrixRows(payload);\n\n const reachable: PlaceWithDriveTime[] = [];\n this.places.forEach((place, index) => {\n const durationS = durations[index];\n if (typeof durationS !== \"number\") return; // null = unreachable\n const distanceM = distances?.[index];\n reachable.push({\n ...place,\n durationS,\n distanceM: typeof distanceM === \"number\" ? distanceM : null,\n });\n });\n reachable.sort((a, b) => a.durationS - b.durationS);\n return reachable.slice(0, Math.max(0, options.n ?? 1));\n }\n\n /** Add-or-update the source and layers on the current style. */\n private install(data: PlacesSourceData): void {\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n this.map.addSource(this.sourceId, {\n type: \"geojson\",\n data,\n cluster: this.cluster,\n ...(this.cluster && this.clusterRadius !== undefined\n ? { clusterRadius: this.clusterRadius }\n : {}),\n ...(this.cluster && this.clusterMaxZoom !== undefined\n ? { clusterMaxZoom: this.clusterMaxZoom }\n : {}),\n });\n }\n\n if (this.cluster) this.installClusterLayers();\n this.installPointsLayer();\n }\n\n /** Cluster circles (sized by count) and the count badge on top. */\n private installClusterLayers(): void {\n if (!this.map.getLayer(this.clustersLayerId)) {\n const clusters: CircleLayerSpecification = {\n id: this.clustersLayerId,\n type: \"circle\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n paint: {\n \"circle-color\": this.clusterColor,\n \"circle-opacity\": 0.9,\n \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 16, 25, 20, 100, 26],\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(clusters);\n }\n if (!this.map.getLayer(this.clusterCountLayerId)) {\n const count: SymbolLayerSpecification = {\n id: this.clusterCountLayerId,\n type: \"symbol\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n layout: {\n \"text-field\": [\"get\", \"point_count_abbreviated\"],\n \"text-font\": [CLUSTER_TEXT_FONT],\n \"text-size\": 12,\n },\n paint: { \"text-color\": \"#ffffff\" },\n };\n this.map.addLayer(count);\n }\n }\n\n /**\n * The unclustered-places layer: a circle pin by default, or a symbol\n * layer once the custom `icon` image has loaded (falling back to the\n * circle look if it fails, like PositionPuck's image fallback).\n */\n private installPointsLayer(): void {\n if (this.map.getLayer(this.pointsLayerId)) return;\n if (!this.icon) {\n this.addCirclePointsLayer();\n return;\n }\n if (this.map.hasImage(this.iconImageId)) {\n this.addIconPointsLayer();\n return;\n }\n void this.map\n .loadImage(this.icon.url)\n .then((image) => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n if (!this.map.hasImage(this.iconImageId)) {\n this.map.addImage(this.iconImageId, image.data);\n }\n this.addIconPointsLayer();\n })\n .catch(() => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n this.addCirclePointsLayer();\n });\n }\n\n private addCirclePointsLayer(): void {\n const points: CircleLayerSpecification = {\n id: this.pointsLayerId,\n type: \"circle\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n paint: {\n \"circle-color\": this.color,\n \"circle-radius\": 7,\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(points);\n }\n\n private addIconPointsLayer(): void {\n const points: SymbolLayerSpecification = {\n id: this.pointsLayerId,\n type: \"symbol\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n layout: {\n \"icon-image\": this.iconImageId,\n \"icon-size\": this.icon?.size ?? 1,\n \"icon-allow-overlap\": true,\n },\n };\n this.map.addLayer(points);\n }\n\n /** Open the built-in popup for a place, replacing any previous one. */\n private openPopup(place: Place): void {\n if (!this.popupFn) return;\n const content = this.popupFn(place);\n const popup = new maplibregl.Popup({ offset: 12 }).setLngLat([\n place.lon,\n place.lat,\n ]);\n if (typeof content === \"string\") popup.setHTML(content);\n else popup.setDOMContent(content);\n this.popup?.remove();\n this.popup = popup.addTo(this.map);\n }\n\n /** Remove the places' layers, source, image and popup from the map. */\n clear(): void {\n this.popup?.remove();\n this.popup = undefined;\n for (const layerId of [\n this.pointsLayerId,\n this.clusterCountLayerId,\n this.clustersLayerId,\n ]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n if (this.map.hasImage(this.iconImageId)) {\n this.map.removeImage(this.iconImageId);\n }\n this.places = [];\n this.data = undefined;\n }\n\n /**\n * Remove the places and detach every listener (style.load, clicks,\n * hovers). Call when disposing of the layer (the map is left untouched).\n */\n destroy(): void {\n this.destroyed = true;\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.map.off(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.off(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.off(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.off(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n this.clear();\n }\n}\n\n/** Bounding box of a non-empty place list, as MapLibre `fitBounds` corners. */\nfunction boundsOf(\n places: Place[],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const { lon, lat } of places) {\n if (lon < minLng) minLng = lon;\n if (lat < minLat) minLat = lat;\n if (lon > maxLng) maxLng = lon;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n/**\n * Pull the origin's rows out of a `POST /matrix` response\n * (`{\"durations\": [[…]], \"distances\": [[…]]}`, row-major, one row here\n * because we send a single source). Throws on anything else.\n */\nfunction matrixRows(payload: unknown): {\n durations: (number | null)[];\n distances: (number | null)[] | undefined;\n} {\n if (typeof payload !== \"object\" || payload === null) {\n throw new Error(\"matrix returned a non-object response\");\n }\n const obj = payload as Record<string, unknown>;\n const durations = firstRow(obj[\"durations\"]);\n if (!durations) {\n throw new Error(\"matrix response has no durations row\");\n }\n return { durations, distances: firstRow(obj[\"distances\"]) };\n}\n\n/** The first row of a row-major `(number | null)[][]`, if that is the shape. */\nfunction firstRow(value: unknown): (number | null)[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const row: unknown = value[0];\n if (!Array.isArray(row)) return undefined;\n return row.map((cell: unknown) =>\n typeof cell === \"number\" && Number.isFinite(cell) ? cell : null,\n );\n}\n","/**\n * NavigationCamera - the turnkey chase-cam for turn-by-turn navigation.\n *\n * Packages the Google-Maps-style follow camera on top of MapLibre's native\n * camera: per-fix `easeTo` with linear easing (continuous glide, no\n * rubber-banding), course-up bearing, a tilted pitch preset, and a\n * screen-offset that anchors the puck low-centre so the camera looks ahead.\n * User gestures (drag, rotate, pitch, zoom) switch the camera to `\"free\"`\n * mode; it auto-recentres after a configurable idle period. An `overview()`\n * mode fits the whole route top-down, and `resume()` returns to the chase\n * cam at the last known fix.\n *\n * Like `RouteLayer`, the class holds only a structural handle on the map\n * (`easeTo`, `fitBounds`, `stop`, events, container) so it is unit-testable\n * against a fake without a WebGL context.\n *\n * Globe projection note: {@link NavigationCamera.isSupported} returns\n * `false` when the map runs the globe (or vertical-perspective) projection.\n * At navigation zooms globe renders much like mercator, but the pixel-offset\n * anchor maths and the top-down overview framing assume a mercator camera;\n * switch the map to mercator (`map.setProjection({ type: \"mercator\" })`)\n * before navigating, or accept an unanchored follow.\n */\nimport type { Map as MlMap } from \"maplibre-gl\";\nimport { unwrapLngs } from \"./coords.js\";\nimport { MapMapMap } from \"./map.js\";\nimport type { PositionPuck } from \"./puck.js\";\nimport type { ParsedRoute, RouteGeometry } from \"./types.js\";\n\n/** A GPS fix to follow. */\nexport interface CameraFix {\n lat: number;\n lon: number;\n}\n\n/** The camera's current behaviour. */\nexport type NavigationCameraMode = \"follow\" | \"overview\" | \"free\";\n\nexport interface NavigationCameraOptions {\n /**\n * Camera tilt in degrees, clamped to 0-85. Default `60` - MapLibre's\n * non-experimental ceiling; values above 60 may show rendering artefacts\n * and flatten DOM-marker pucks. When the requested pitch exceeds the\n * map's `maxPitch`, the limit is raised to match.\n *\n * Precedence: this option > the Studio design's `camera.pitch` (when the\n * map is a `MapMapMap` whose theme carried `extra.nav.camera`) > the\n * built-in default.\n */\n pitch?: number;\n /**\n * Follow-mode zoom. Default `17`. Same precedence as `pitch`: option >\n * Studio design `camera.zoom` > built-in default.\n */\n zoom?: number;\n /**\n * Where the fix (and puck) sits vertically on screen, as a fraction of\n * the container height from the top, clamped to 0-1. Default `0.72` -\n * the puck rides low so the camera looks up the road ahead.\n */\n anchorY?: number;\n /**\n * Ease duration per {@link NavigationCamera.follow} call, milliseconds.\n * Default `900`, and always capped by the observed fix interval so a\n * fast fix cadence never queues up lagging animations.\n */\n easeMs?: number;\n /**\n * Idle time after the last user gesture before the camera recentres\n * itself back to follow mode, milliseconds. Default `6000`; `0` disables\n * auto-recentre (the app must call {@link NavigationCamera.resume}).\n */\n autoRecentreMs?: number;\n}\n\n/** The map-interaction events that hand the camera to the user. */\nconst INTERACTION_EVENTS = [\n \"dragstart\",\n \"rotatestart\",\n \"pitchstart\",\n \"zoomstart\",\n] as const;\n\nconst DEFAULT_PITCH = 60;\nconst DEFAULT_ZOOM = 17;\nconst DEFAULT_ANCHOR_Y = 0.72;\nconst DEFAULT_EASE_MS = 900;\nconst DEFAULT_AUTO_RECENTRE_MS = 6000;\n/** Screen padding around the route in overview mode, pixels. */\nconst OVERVIEW_PADDING_PX = 48;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Anything with a `PositionPuck`-shaped `setLocation` can be co-driven. */\ntype CoDrivenPuck = Pick<PositionPuck, \"setLocation\">;\n\n/** A follow-mode chase camera for MapMap maps. */\nexport class NavigationCamera {\n private readonly m: MlMap;\n private readonly pitch: number;\n private readonly zoom: number;\n private readonly anchorY: number;\n private readonly easeMs: number;\n private readonly autoRecentreMs: number;\n\n private currentMode: NavigationCameraMode = \"follow\";\n private puck: CoDrivenPuck | undefined;\n private lastFix: CameraFix | undefined;\n private lastCourse: number | undefined;\n private lastFixAt: number | undefined;\n private lastRoute: RouteGeometry | undefined;\n private recentreTimer: ReturnType<typeof setTimeout> | undefined;\n private destroyed = false;\n\n // Bound once so `off` in destroy() removes exactly what `on` added.\n private readonly onInteraction = (ev?: { originalEvent?: unknown }): void => {\n // Camera-driven moves (our own easeTo/fitBounds) fire the same events\n // without an `originalEvent`; only real user gestures carry one.\n if (!ev?.originalEvent || this.destroyed) return;\n this.currentMode = \"free\";\n this.m.stop();\n this.scheduleRecentre();\n };\n\n /**\n * `false` when the map runs the globe (or vertical-perspective)\n * projection, whose camera geometry breaks the low-anchor offset maths\n * and top-down overview framing. Switch to mercator for navigation.\n */\n static isSupported(map: MapMapMap | MlMap): boolean {\n const m = map instanceof MapMapMap ? map.map : map;\n const projection = (\n m as { getProjection?: () => unknown }\n ).getProjection?.();\n return !usesGlobe(projection);\n }\n\n constructor(map: MapMapMap | MlMap, options: NavigationCameraOptions = {}) {\n this.m = map instanceof MapMapMap ? map.map : map;\n // A MapMapMap built from a Studio theme may carry `extra.nav.camera`;\n // its pitch/zoom become the option defaults. Precedence: explicit\n // option > design > built-in default.\n const design = map instanceof MapMapMap ? map.navDesign?.camera : undefined;\n this.pitch = clamp(options.pitch ?? design?.pitch ?? DEFAULT_PITCH, 0, 85);\n this.zoom = options.zoom ?? design?.zoom ?? DEFAULT_ZOOM;\n this.anchorY = clamp(options.anchorY ?? DEFAULT_ANCHOR_Y, 0, 1);\n this.easeMs = Math.max(0, options.easeMs ?? DEFAULT_EASE_MS);\n this.autoRecentreMs = Math.max(\n 0,\n options.autoRecentreMs ?? DEFAULT_AUTO_RECENTRE_MS,\n );\n\n // A pitch preset above the map's ceiling would be silently clamped by\n // MapLibre; raise the ceiling to honour the preset (never lower it).\n if (this.pitch > this.m.getMaxPitch()) this.m.setMaxPitch(this.pitch);\n\n for (const event of INTERACTION_EVENTS) {\n this.m.on(event, this.onInteraction);\n }\n }\n\n /** The camera's current behaviour: `\"follow\"`, `\"overview\"` or `\"free\"`. */\n get mode(): NavigationCameraMode {\n return this.currentMode;\n }\n\n /**\n * Co-drive a {@link PositionPuck}: every {@link follow} call also\n * `setLocation`s the puck, so camera and puck never diverge.\n */\n attachPuck(puck: CoDrivenPuck): void {\n this.puck = puck;\n }\n\n /**\n * Glide the camera to a fix, course-up when `courseDeg` is given\n * (bearing is left unchanged when it is `undefined`). Each call eases\n * with linear timing over `easeMs` capped by the observed fix interval,\n * and interrupts the previous ease (no queue buildup). The fix and an\n * attached puck are always updated, but the camera only moves in\n * `\"follow\"` mode - `\"free\"` and `\"overview\"` record the fix for\n * {@link resume}.\n */\n follow(fix: CameraFix, courseDeg?: number): void {\n const now = Date.now();\n const interval =\n this.lastFixAt === undefined\n ? this.easeMs\n : Math.max(0, now - this.lastFixAt);\n this.lastFixAt = now;\n this.lastFix = fix;\n if (courseDeg !== undefined) this.lastCourse = courseDeg;\n this.puck?.setLocation(fix, courseDeg);\n if (this.currentMode !== \"follow\") return;\n this.easeToFix(fix, courseDeg, Math.min(this.easeMs, interval));\n }\n\n /**\n * Fit the route top-down (pitch 0, north-up). Pass the route geometry on\n * the first call; later calls reuse the last geometry given. A no-op\n * when no geometry has ever been provided.\n */\n overview(routeGeometry?: RouteGeometry): void {\n if (routeGeometry) this.lastRoute = routeGeometry;\n const route = this.lastRoute;\n if (!route || route.coordinates.length === 0) return;\n this.clearRecentreTimer();\n this.currentMode = \"overview\";\n this.m.fitBounds(boundsOf(route.coordinates), {\n padding: OVERVIEW_PADDING_PX,\n pitch: 0,\n bearing: 0,\n duration: this.easeMs,\n essential: true,\n });\n }\n\n /**\n * Return to follow mode, gliding back to the last fix (with its last\n * known course) when one has been recorded.\n */\n resume(): void {\n this.clearRecentreTimer();\n this.currentMode = \"follow\";\n if (this.lastFix) {\n this.easeToFix(this.lastFix, this.lastCourse, this.easeMs);\n }\n }\n\n /** Remove the map listeners and cancel any pending auto-recentre. */\n destroy(): void {\n this.destroyed = true;\n this.clearRecentreTimer();\n for (const event of INTERACTION_EVENTS) {\n this.m.off(event, this.onInteraction);\n }\n }\n\n private easeToFix(\n fix: CameraFix,\n courseDeg: number | undefined,\n duration: number,\n ): void {\n this.m.easeTo({\n center: [fix.lon, fix.lat],\n ...(courseDeg !== undefined ? { bearing: courseDeg } : {}),\n pitch: this.pitch,\n zoom: this.zoom,\n offset: [0, this.anchorOffsetY()],\n duration,\n easing: (t: number) => t,\n // Interrupt semantics: `essential` easings run even under\n // prefers-reduced-motion, and each new easeTo cancels the previous\n // one, so a fast fix cadence glides instead of queueing.\n essential: true,\n });\n }\n\n /**\n * The pixel offset that renders the followed fix at `anchorY` of the\n * container height: `(anchorY - 0.5) * height` (0.5 is the natural\n * centre; positive y moves the puck down the screen).\n */\n private anchorOffsetY(): number {\n const height = this.m.getContainer().clientHeight;\n return (this.anchorY - 0.5) * height;\n }\n\n private scheduleRecentre(): void {\n this.clearRecentreTimer();\n if (this.autoRecentreMs === 0) return;\n this.recentreTimer = setTimeout(() => {\n this.recentreTimer = undefined;\n if (this.currentMode === \"free\") this.resume();\n }, this.autoRecentreMs);\n }\n\n private clearRecentreTimer(): void {\n if (this.recentreTimer !== undefined) {\n clearTimeout(this.recentreTimer);\n this.recentreTimer = undefined;\n }\n }\n}\n\n/** South-west / north-east bounds of a coordinate list. */\nfunction boundsOf(\n coordinates: [number, number][],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const [lng, lat] of coordinates) {\n if (lng < minLng) minLng = lng;\n if (lng > maxLng) maxLng = lng;\n if (lat < minLat) minLat = lat;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n// ---------------------------------------------------------------------------\n// camera.flythrough() - cinematic route replay + scrollytelling binder.\n// ---------------------------------------------------------------------------\n\n/** Mean Earth radius in metres (IUGG), matching places.ts. */\nconst FLYTHROUGH_EARTH_RADIUS_M = 6371008.8;\n\n/** Straight-line (haversine) distance between two `[lng, lat]`s, metres. */\nfunction flythroughDistanceM(a: [number, number], b: [number, number]): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b[1] - a[1]);\n const dLon = rad(b[0] - a[0]);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a[1])) * Math.cos(rad(b[1])) * Math.sin(dLon / 2) ** 2;\n return 2 * FLYTHROUGH_EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/**\n * Initial great-circle bearing from `a` to `b`, degrees clockwise from\n * north, normalised to `[0, 360)`.\n */\nexport function bearingBetween(\n a: [number, number],\n b: [number, number],\n): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLon = rad(b[0] - a[0]);\n const latA = rad(a[1]);\n const latB = rad(b[1]);\n const y = Math.sin(dLon) * Math.cos(latB);\n const x =\n Math.cos(latA) * Math.sin(latB) -\n Math.sin(latA) * Math.cos(latB) * Math.cos(dLon);\n const deg = (Math.atan2(y, x) * 180) / Math.PI;\n return (deg + 360) % 360;\n}\n\n/**\n * The signed shortest-arc rotation from bearing `from` to bearing `to`,\n * in `(-180, 180]` degrees - the slerp-style delta the flythrough eases\n * along so the chase cam never spins the long way round.\n */\nexport function shortestArcDelta(from: number, to: number): number {\n const delta = (((to - from) % 360) + 540) % 360 - 180;\n return delta === -180 ? 180 : delta;\n}\n\n/** A camera pose along a flythrough: where to look from, and which way. */\nexport interface FlythroughPose {\n /** Camera target on the route, `[lng, lat]`. */\n center: [number, number];\n /** Chase-cam bearing: towards a point `lookAheadM` up the road. */\n bearing: number;\n}\n\n/**\n * Precomputed arc-length sampler over a route line: maps progress\n * `t` (0-1 of total route distance) to a {@link FlythroughPose}. Pure -\n * shared by {@link flythroughPose} (tests) and the controller (per frame,\n * without recomputing cumulative distances).\n */\nclass PoseSampler {\n private readonly points: [number, number][];\n private readonly cumulative: number[];\n readonly totalM: number;\n\n constructor(coordinates: [number, number][]) {\n // Unwrap longitudes onto a continuous range first, so a route that\n // crosses the antimeridian interpolates across the real gap instead\n // of sweeping the camera around the world.\n const unwrapped = unwrapLngs(coordinates);\n // Consecutive duplicates carry no direction; drop them once here.\n this.points = unwrapped.filter(\n (p, i) =>\n i === 0 ||\n p[0] !== unwrapped[i - 1]![0] ||\n p[1] !== unwrapped[i - 1]![1],\n );\n if (this.points.length < 2) {\n throw new Error(\n \"flythrough needs a route with at least two distinct coordinates\",\n );\n }\n this.cumulative = [0];\n for (let i = 1; i < this.points.length; i++) {\n this.cumulative.push(\n this.cumulative[i - 1]! +\n flythroughDistanceM(this.points[i - 1]!, this.points[i]!),\n );\n }\n this.totalM = this.cumulative[this.cumulative.length - 1]!;\n }\n\n /** The interpolated point `distanceM` along the route (clamped). */\n pointAt(distanceM: number): [number, number] {\n const d = Math.min(this.totalM, Math.max(0, distanceM));\n // Linear scan is fine: callers advance monotonically and routes are\n // a few thousand points at most.\n let i = 1;\n while (i < this.cumulative.length - 1 && this.cumulative[i]! < d) i++;\n const before = this.cumulative[i - 1]!;\n const span = this.cumulative[i]! - before;\n const f = span > 0 ? (d - before) / span : 0;\n const a = this.points[i - 1]!;\n const b = this.points[i]!;\n return [a[0] + (b[0] - a[0]) * f, a[1] + (b[1] - a[1]) * f];\n }\n\n /** The pose at progress `t` (clamped 0-1), chasing `lookAheadM` ahead. */\n poseAt(t: number, lookAheadM: number): FlythroughPose {\n const d = Math.min(1, Math.max(0, t)) * this.totalM;\n const center = this.pointAt(d);\n let target = this.pointAt(d + Math.max(1, lookAheadM));\n if (target[0] === center[0] && target[1] === center[1]) {\n // At (or past) the end the look-ahead collapses onto the centre;\n // hold the final segment's direction instead of a degenerate\n // zero-length bearing.\n const last = this.points[this.points.length - 1]!;\n const prev = this.points[this.points.length - 2]!;\n return { center, bearing: bearingBetween(prev, last) };\n }\n return { center, bearing: bearingBetween(center, target) };\n }\n}\n\n/**\n * The camera pose at progress `t` (0-1) along a route: the interpolated\n * point that fraction of the total distance along the line, with a\n * chase-cam bearing towards the point `lookAheadM` further on. Pure -\n * exported for tests and for apps that drive the camera themselves.\n */\nexport function flythroughPose(\n coordinates: [number, number][],\n t: number,\n lookAheadM = 200,\n): FlythroughPose {\n return new PoseSampler(coordinates).poseAt(t, lookAheadM);\n}\n\nexport interface FlythroughOptions {\n /**\n * Camera tilt in degrees, clamped 0-85. Default `60` (the cinematic\n * chase look; see {@link NavigationCameraOptions.pitch} for caveats\n * above 60).\n */\n pitch?: number;\n /** Camera zoom held through the replay. Default `16`. */\n zoom?: number;\n /**\n * Total replay duration in milliseconds. Default `20000`. Ignored when\n * `speedMps` is given.\n */\n durationMs?: number;\n /**\n * Replay ground speed in metres/second along the route - the duration\n * becomes `routeLength / speedMps`. Wins over `durationMs`.\n */\n speedMps?: number;\n /**\n * How far up the road the chase cam looks to derive its bearing,\n * metres. Default `200`; larger = calmer bearing on wiggly roads.\n */\n lookAheadM?: number;\n /**\n * Bearing smoothing rate per second (the fraction of the remaining\n * shortest-arc turn closed each second). Default `3`; higher = snappier.\n */\n bearingEase?: number;\n}\n\n/** The handle a {@link flythrough} returns. */\nexport interface FlythroughController {\n /** Start (or resume) the replay. Restarts from 0 when it had finished. */\n play(): void;\n /** Freeze the replay where it is. */\n pause(): void;\n /** Pause and rewind to the start (the camera jumps to the start pose). */\n stop(): void;\n /** Scrub to progress `t` (0-1, clamped) and apply the pose immediately. */\n seek(t: number): void;\n /** Playback-rate multiplier (`1` = real duration, `2` = double). */\n speed: number;\n /** Current progress, 0-1. */\n readonly progress: number;\n /** Whether the replay is currently advancing. */\n readonly playing: boolean;\n /** Subscribe to progress updates; returns the unsubscribe function. */\n onProgress(listener: (t: number) => void): () => void;\n /** Pause and detach everything. The controller is dead afterwards. */\n destroy(): void;\n}\n\n/** One animation frame, with a cancel handle; setTimeout fallback in Node. */\nfunction scheduleFrame(cb: (timestampMs: number) => void): () => void {\n if (typeof requestAnimationFrame === \"function\") {\n const handle = requestAnimationFrame(cb);\n return () => cancelAnimationFrame(handle);\n }\n const handle = setTimeout(() => cb(Date.now()), 16);\n return () => clearTimeout(handle);\n}\n\n/**\n * Cinematic route replay: fly the camera along a route line with a\n * chase-cam bearing (eased along the shortest arc, so junctions glide\n * instead of spinning), at a configurable pitch/zoom/speed. Returns a\n * transport-style controller; nothing moves until `play()` or `seek()`.\n *\n * ```ts\n * const route = await routes.route(from, to);\n * const replay = flythrough(map, route, { pitch: 60, durationMs: 15000 });\n * replay.onProgress((t) => scrubber.value = String(t));\n * replay.play();\n * ```\n *\n * Drives the camera with `jumpTo` once per animation frame (the standard\n * MapLibre scrub pattern). Runs under any projection; on globe the ride is\n * unanchored but valid. Accepts a `ParsedRoute` (from `RouteLayer`) or a\n * bare GeoJSON LineString geometry.\n */\nexport function flythrough(\n map: MapMapMap | MlMap,\n route: RouteGeometry | ParsedRoute,\n options: FlythroughOptions = {},\n): FlythroughController {\n const m = map instanceof MapMapMap ? map.map : map;\n const geometry = \"geometry\" in route ? route.geometry : route;\n const sampler = new PoseSampler(geometry.coordinates);\n const pitch = clamp(options.pitch ?? 60, 0, 85);\n const zoom = options.zoom ?? 16;\n const lookAheadM = options.lookAheadM ?? 200;\n const bearingEase = Math.max(0, options.bearingEase ?? 3);\n const durationMs =\n options.speedMps !== undefined && options.speedMps > 0\n ? (sampler.totalM / options.speedMps) * 1000\n : Math.max(1, options.durationMs ?? 20_000);\n\n let t = 0;\n let rate = 1;\n let playing = false;\n let destroyed = false;\n let bearing: number | undefined;\n let lastFrameTs: number | undefined;\n let cancelFrame: (() => void) | undefined;\n const listeners = new Set<(t: number) => void>();\n\n const applyPose = (dtS: number): void => {\n const pose = sampler.poseAt(t, lookAheadM);\n // Ease the bearing along the shortest arc: close a time-scaled\n // fraction of the remaining turn each frame (frame-rate independent).\n bearing =\n bearing === undefined\n ? pose.bearing\n : bearing +\n shortestArcDelta(bearing, pose.bearing) *\n Math.min(1, bearingEase * dtS);\n m.jumpTo({ center: pose.center, bearing, pitch, zoom });\n for (const listener of listeners) listener(t);\n };\n\n const frame = (timestampMs: number): void => {\n if (!playing || destroyed) return;\n const dtS =\n lastFrameTs === undefined ? 0 : Math.max(0, timestampMs - lastFrameTs) / 1000;\n lastFrameTs = timestampMs;\n t = Math.min(1, t + (dtS * 1000 * rate) / durationMs);\n applyPose(dtS || 1 / 60);\n if (t >= 1) {\n playing = false;\n return;\n }\n cancelFrame = scheduleFrame(frame);\n };\n\n const pause = (): void => {\n playing = false;\n cancelFrame?.();\n cancelFrame = undefined;\n lastFrameTs = undefined;\n };\n\n return {\n play(): void {\n if (destroyed || playing) return;\n if (t >= 1) t = 0; // replay from the top once finished\n playing = true;\n lastFrameTs = undefined;\n cancelFrame = scheduleFrame(frame);\n },\n pause,\n stop(): void {\n if (destroyed) return;\n pause();\n t = 0;\n bearing = undefined; // next pose snaps rather than unwinding the arc\n applyPose(1 / 60);\n },\n seek(to: number): void {\n if (destroyed) return;\n t = Math.min(1, Math.max(0, to));\n bearing = undefined; // a scrub snaps on-heading rather than easing there\n applyPose(1 / 60);\n },\n get speed(): number {\n return rate;\n },\n set speed(value: number) {\n if (Number.isFinite(value) && value > 0) rate = value;\n },\n get progress(): number {\n return t;\n },\n get playing(): boolean {\n return playing;\n },\n onProgress(listener: (progress: number) => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n destroy(): void {\n destroyed = true;\n pause();\n listeners.clear();\n },\n };\n}\n\n/** Anything scrollable the binder accepts: an element or the window. */\ntype ScrollTarget = Pick<\n HTMLElement,\n \"addEventListener\" | \"removeEventListener\"\n> &\n Partial<\n Pick<HTMLElement, \"scrollTop\" | \"scrollHeight\" | \"clientHeight\"> &\n Pick<Window, \"scrollY\" | \"innerHeight\" | \"document\">\n >;\n\n/**\n * Scrollytelling: bind a flythrough to a scroll position, so scrolling a\n * story column scrubs the camera along the route. The binder pauses the\n * controller (scroll owns the timeline) and seeks it to the scrolled\n * fraction - immediately on bind, then on every scroll. Returns the\n * unbind function.\n *\n * ```ts\n * const replay = flythrough(map, route);\n * const unbind = bindFlythroughToScroll(replay, document.querySelector(\"#story\")!);\n * ```\n */\nexport function bindFlythroughToScroll(\n controller: FlythroughController,\n target: HTMLElement | Window = window,\n): () => void {\n const t = target as ScrollTarget;\n const fraction = (): number => {\n if (typeof t.scrollTop === \"number\") {\n // An element: how far through its own scrollable height.\n const max = (t.scrollHeight ?? 0) - (t.clientHeight ?? 0);\n return max > 0 ? t.scrollTop / max : 0;\n }\n // The window: how far through the document.\n const doc = t.document?.documentElement;\n const max = (doc?.scrollHeight ?? 0) - (t.innerHeight ?? 0);\n return max > 0 ? (t.scrollY ?? 0) / max : 0;\n };\n const onScroll = (): void => {\n controller.pause();\n controller.seek(Math.min(1, Math.max(0, fraction())));\n };\n t.addEventListener(\"scroll\", onScroll, { passive: true });\n onScroll();\n return () => t.removeEventListener(\"scroll\", onScroll);\n}\n\n/**\n * Whether a `getProjection()` result names the globe. MapLibre v5 returns\n * `{ type }` where `type` is `\"globe\"`, `\"mercator\"`,\n * `\"vertical-perspective\"` or a style expression that can evaluate to any\n * of them; any mention of globe/vertical-perspective counts as globe.\n */\nfunction usesGlobe(projection: unknown): boolean {\n if (projection === null || projection === undefined) return false;\n if (typeof projection === \"string\") {\n return projection === \"globe\" || projection === \"vertical-perspective\";\n }\n if (Array.isArray(projection)) return projection.some(usesGlobe);\n if (typeof projection === \"object\") {\n return Object.values(projection).some(usesGlobe);\n }\n return false;\n}\n","/**\n * IsochroneLayer - walkability rings (reachability contours) on a MapMap\n * map, backed by the gateway's live `POST /isochrone` endpoint (Valhalla\n * isochrone; see docs/API.md).\n *\n * One call - `showReachability({ origin, mode: \"walk\", minutes: [5, 10, 15] })` -\n * renders concentric reachability rings: graduated-opacity fills (nearest\n * ring strongest), contour outlines, and \"N min\" labels along each\n * contour. The estate-agent / store-catchment / \"how walkable is this\n * flat?\" view in one line.\n *\n * Follows the RouteLayer pattern: gateway base URL/key picked up from a\n * `MapMapMap` automatically, layers survive `setStyle` theme swaps via\n * re-installation on `style.load`, and `clear()`/`destroy()` tidy up.\n */\nimport type {\n DataDrivenPropertyValueSpecification,\n FillLayerSpecification,\n GeoJSONSource,\n LineLayerSpecification,\n Map as MlMap,\n SymbolLayerSpecification,\n} from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { SIGNAL_BLUE } from \"./route.js\";\nimport { toLngLat } from \"./coords.js\";\nimport type { LngLatLike } from \"./types.js\";\n\n/**\n * Travel mode for the rings. The friendly names map onto gateway costings\n * (`walk` → `pedestrian`, `cycle` → `bicycle`, `drive` → `auto`); any\n * other string is passed through as a raw Valhalla costing (e.g.\n * `\"truck\"`, `\"motor_scooter\"`).\n */\nexport type ReachabilityMode =\n | \"walk\"\n | \"cycle\"\n | \"drive\"\n | \"truck\"\n | (string & {});\n\nconst MODE_TO_COSTING: Record<string, string> = {\n walk: \"pedestrian\",\n cycle: \"bicycle\",\n drive: \"auto\",\n};\n\nexport interface ShowReachabilityOptions {\n /** Where the rings radiate from. */\n origin: LngLatLike;\n /** Travel mode. Defaults to `\"walk\"` - these are walkability rings. */\n mode?: ReachabilityMode;\n /** Ring contours in minutes, e.g. `[5, 10, 15]`. At least one. */\n minutes: number[];\n /** Ring colour. Defaults to MapMap signal blue. */\n color?: string;\n /**\n * Valhalla-style costing options forwarded verbatim, e.g.\n * `{ pedestrian: { use_lit: 1.0 } }`.\n */\n costingOptions?: Record<string, unknown>;\n}\n\nexport interface IsochroneLayerOptions {\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-isochrone\"`. */\n id?: string;\n}\n\n/** The GeoJSON FeatureCollection the gateway returns, passed through. */\nexport interface IsochroneFeatureCollection {\n type: \"FeatureCollection\";\n features: {\n type: \"Feature\";\n geometry: { type: string; coordinates: unknown };\n properties?: Record<string, unknown> | null;\n }[];\n}\n\n/** Renders reachability rings from the gateway's `POST /isochrone`. */\nexport class IsochroneLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly fillLayerId: string;\n private readonly lineLayerId: string;\n private readonly labelLayerId: string;\n private lastData: IsochroneFeatureCollection | undefined;\n private lastMinutes: number[] = [];\n private lastColor: string = SIGNAL_BLUE;\n\n constructor(map: MapMapMap | MlMap, options: IsochroneLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n } else {\n this.map = map;\n if (!options.baseUrl) {\n throw new Error(\n \"IsochroneLayer needs a baseUrl when given a raw MapLibre map\",\n );\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n const id = options.id ?? \"mapmap-isochrone\";\n this.sourceId = `${id}-src`;\n this.fillLayerId = `${id}-fill`;\n this.lineLayerId = `${id}-line`;\n this.labelLayerId = `${id}-label`;\n // RouteLayer lifecycle: runtime sources/layers are wiped on every\n // setStyle (theme swap), so re-install on each style.load - which also\n // completes a show() that arrived before the style finished loading.\n this.map.on(\"style.load\", this.handleStyleLoad);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.lastData) this.install(this.lastData);\n };\n\n /**\n * Fetch and render reachability rings. Returns the GeoJSON\n * FeatureCollection the gateway produced (each feature carries a\n * `contour` property in minutes), for callers who also want the raw\n * shapes. Replaces any rings already shown by this layer.\n */\n async showReachability(\n options: ShowReachabilityOptions,\n ): Promise<IsochroneFeatureCollection> {\n if (options.minutes.length === 0) {\n throw new Error(\n \"showReachability needs at least one contour in minutes, e.g. { minutes: [5, 10, 15] }\",\n );\n }\n const [lon, lat] = toLngLat(options.origin);\n const mode = options.mode ?? \"walk\";\n const body: Record<string, unknown> = {\n locations: [{ lat, lon }],\n costing: MODE_TO_COSTING[mode] ?? mode,\n // Largest first so smaller (nearer) rings paint on top.\n contours: [...options.minutes]\n .sort((a, b) => b - a)\n .map((time) => ({ time })),\n polygons: true,\n };\n if (options.costingOptions) body[\"costing_options\"] = options.costingOptions;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(`${this.baseUrl}/isochrone`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n const payload: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `isochrone request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n if (\n typeof payload !== \"object\" ||\n payload === null ||\n (payload as Record<string, unknown>)[\"type\"] !== \"FeatureCollection\"\n ) {\n throw new Error(\"isochrone returned no FeatureCollection\");\n }\n const collection = payload as IsochroneFeatureCollection;\n this.lastMinutes = [...options.minutes].sort((a, b) => a - b);\n this.lastColor = options.color ?? SIGNAL_BLUE;\n this.draw(collection);\n return collection;\n }\n\n /** The most recently drawn rings, if any. */\n get current(): IsochroneFeatureCollection | undefined {\n return this.lastData;\n }\n\n /** Draw (or update) a ring collection. Safe before the style has loaded. */\n private draw(collection: IsochroneFeatureCollection): void {\n this.lastData = collection;\n if (!this.map.isStyleLoaded()) return; // installed by handleStyleLoad\n this.install(collection);\n }\n\n /** Add-or-update the source and ring layers on the current style. */\n private install(collection: IsochroneFeatureCollection): void {\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(collection as never);\n } else {\n this.map.addSource(this.sourceId, {\n type: \"geojson\",\n data: collection as never,\n });\n }\n if (this.map.getLayer(this.fillLayerId)) {\n // Re-shown with a different colour/contours: refresh the paints.\n this.map.setPaintProperty(\n this.fillLayerId,\n \"fill-color\",\n this.lastColor,\n );\n this.map.setPaintProperty(\n this.fillLayerId,\n \"fill-opacity\",\n this.fillOpacity(),\n );\n this.map.setPaintProperty(this.lineLayerId, \"line-color\", this.lastColor);\n this.map.setPaintProperty(this.labelLayerId, \"text-color\", this.lastColor);\n return;\n }\n\n // Valhalla polygons are full disks (not donuts), so translucent fills\n // naturally stack: near the origin every ring overlaps and the tint\n // reads strongest, fading towards the outermost contour. The graduated\n // per-ring opacity reinforces that.\n const fill: FillLayerSpecification = {\n id: this.fillLayerId,\n type: \"fill\",\n source: this.sourceId,\n paint: {\n \"fill-color\": this.lastColor,\n \"fill-opacity\": this.fillOpacity(),\n },\n };\n const line: LineLayerSpecification = {\n id: this.lineLayerId,\n type: \"line\",\n source: this.sourceId,\n paint: {\n \"line-color\": this.lastColor,\n \"line-width\": 1.5,\n \"line-opacity\": 0.8,\n },\n };\n const label: SymbolLayerSpecification = {\n id: this.labelLayerId,\n type: \"symbol\",\n source: this.sourceId,\n layout: {\n \"symbol-placement\": \"line\",\n \"text-field\": [\n \"concat\",\n [\"to-string\", [\"get\", \"contour\"]],\n \" min\",\n ],\n // Ships with the MapMap default styles (see places.ts).\n \"text-font\": [\"Noto Sans Regular\"],\n \"text-size\": 11,\n },\n paint: {\n \"text-color\": this.lastColor,\n \"text-halo-color\": \"#ffffff\",\n \"text-halo-width\": 1.2,\n },\n };\n this.map.addLayer(fill);\n this.map.addLayer(line);\n this.map.addLayer(label);\n }\n\n /**\n * Graduated fill opacity: the nearest contour (fewest minutes) is the\n * most opaque, the farthest the faintest, interpolated on each\n * feature's `contour` property. With one contour it is a constant.\n */\n private fillOpacity(): DataDrivenPropertyValueSpecification<number> {\n const min = this.lastMinutes[0] ?? 0;\n const max = this.lastMinutes[this.lastMinutes.length - 1] ?? 0;\n if (this.lastMinutes.length < 2 || min === max) return 0.18;\n return [\n \"interpolate\",\n [\"linear\"],\n [\"get\", \"contour\"],\n min,\n 0.28,\n max,\n 0.08,\n ] as unknown as DataDrivenPropertyValueSpecification<number>;\n }\n\n /** Remove the rings' layers and source from the map. */\n clear(): void {\n for (const layerId of [\n this.labelLayerId,\n this.lineLayerId,\n this.fillLayerId,\n ]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n this.lastData = undefined;\n }\n\n /** Remove the rings and detach the layer's `style.load` listener. */\n destroy(): void {\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.clear();\n }\n}\n","/**\n * AdrCheck - optional helper for the gateway's `POST /adr/check` endpoint.\n *\n * The ADR 8.6.4 tunnel compliance engine, exposed directly. No MapLibre\n * dependency; just a typed fetch wrapper.\n */\nimport type { AdrCheckRequest, AdrCheckResult } from \"./types.js\";\n\n/**\n * Builds the exact wire body the gateway deserialises\n * (`sn-gateway` `routes/adr.rs` → `sn_adr::AdrVehicleProfile`):\n * `{\"adr\": {\"dimensions\": {…}, \"tunnel_code\"?, \"hazmat\"}, \"tunnel_category\"}`.\n * Unset dimensions default to the EU 96/53/EC artic maximums, mirroring\n * `TruckDimensions::default()`. Exported for contract tests.\n */\nexport function buildAdrCheckBody(request: AdrCheckRequest): Record<string, unknown> {\n const dims = request.dimensions ?? {};\n const adr: Record<string, unknown> = {\n dimensions: {\n height_m: dims.heightM ?? 4.0,\n width_m: dims.widthM ?? 2.55,\n length_m: dims.lengthM ?? 16.5,\n gross_weight_t: dims.grossWeightT ?? 40.0,\n axle_load_t: dims.axleLoadT ?? null,\n axle_count: dims.axleCount ?? null,\n },\n hazmat: request.hazmat,\n };\n // Omitted entirely when unknown: the gateway reads a missing tunnel_code\n // as \"dangerous goods of unknown code\" (conservative code-B fallback).\n if (request.tunnelCode !== undefined) adr[\"tunnel_code\"] = request.tunnelCode;\n return { adr, tunnel_category: request.tunnelCategory };\n}\n\nexport interface AdrCheckOptions {\n /** Gateway base URL, e.g. `https://api.mapmap.ai`. */\n baseUrl: string;\n /** Gateway API key (`snk_…`). */\n apiKey?: string;\n}\n\n/** Calls `POST /adr/check` and returns the parsed compliance decision. */\nexport class AdrCheck {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n\n constructor(options: AdrCheckOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n async check(request: AdrCheckRequest): Promise<AdrCheckResult> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(`${this.baseUrl}/adr/check`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(buildAdrCheckBody(request)),\n });\n\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `ADR check failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"ADR check returned a non-object response\");\n }\n const obj = body as Record<string, unknown>;\n const result: AdrCheckResult = {\n status: typeof obj[\"status\"] === \"string\" ? obj[\"status\"] : \"unknown\",\n raw: obj,\n };\n if (typeof obj[\"reason\"] === \"string\") result.reason = obj[\"reason\"];\n return result;\n }\n}\n","/**\n * Turn-by-turn guidance helpers: voice + banner instructions and lanes.\n *\n * The gateway's OSRM endpoint returns Mapbox-shaped `voiceInstructions`\n * (plain + SSML announcements with distance triggers) and\n * `bannerInstructions` (primary line with a maneuver glyph, lane\n * sub-banners) on each step when requested with\n * `voice: true` / `banner: true` route options. This module extracts them\n * from a parsed route, renders a banner as a DOM element, and speaks\n * announcements through the browser's `SpeechSynthesis`.\n *\n * Everything except {@link GuidanceBanner} and {@link speak} is pure and\n * covered by unit tests.\n */\n\nimport {\n NAV_CAMERA_KINDS,\n navAlertLeadDistanceM,\n navAlertSoundUrl,\n navCameraKind,\n type NavAlertsDesign,\n type NavAlertAudioMode,\n type NavBannerDesign,\n type NavCameraKind,\n} from \"./nav-design.js\";\nimport { directionIcons, iconNameForStep } from \"./direction-icons.js\";\nimport type { ParsedRoute } from \"./types.js\";\n\n/**\n * One complete CSS colour value and nothing else.\n *\n * Every alternative is anchored `^…$`, which is the whole point: a check\n * that merely looks for a `rgb(` prefix and a trailing `)` accepts\n * `rgb(0,0,0) url(https://evil.example/beacon.png)`, because the value it\n * is spliced into (`background`) legally takes `<color> || <image>`. The\n * interior character class excludes `(`, `)` and `;`, so neither a nested\n * `url()` nor a second declaration can survive; one level of nesting is\n * allowed so `color-mix()` and `var()` fallbacks still parse.\n *\n * Deliberately wider than the palette's `isCssColour`: named colours,\n * `transparent`, `currentColor`, `var(--token)`, `oklch()` and\n * `color-mix()` are all legal here and are used by real themes, so\n * rejecting them would silently repaint a customer's banner.\n */\nconst CSS_COLOUR =\n /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color|color-mix|var)\\((?:[\\w\\s.,%/#-]|\\([\\w\\s.,%/#-]*\\))*\\)$/i;\n\n/**\n * A theme-derived colour string, safe to interpolate into `style.cssText`.\n *\n * Nav-design colours are parsed leniently (`nav-design.ts` only checks the\n * value is a non-empty string), so a hostile or third-party theme could\n * otherwise smuggle extra CSS declarations — a tracking `background-image`\n * beacon or a clickjacking overlay — through the banner/alert-chip pills.\n * Anything that is not one complete colour falls back to the built-in\n * value rather than reaching the DOM.\n */\nfunction safeColour(value: string, fallback: string): string {\n const v = value.trim();\n // Explicit belt-and-braces: these can never appear in a colour, and\n // keeping the guard here means loosening CSS_COLOUR later cannot quietly\n // reopen a breakout.\n if (v === \"\" || /[;{}]|url\\(|\\/\\*/i.test(v)) return fallback;\n if (v.startsWith(\"#\")) {\n return /^[0-9a-fA-F]+$/.test(v.slice(1)) && [3, 4, 6, 8].includes(v.length - 1)\n ? v\n : fallback;\n }\n // A bare keyword: named colours, `transparent`, `currentColor`.\n if (/^[a-zA-Z][a-zA-Z-]*$/.test(v)) return v;\n return CSS_COLOUR.test(v) ? v : fallback;\n}\n\n/** A spoken instruction with its trigger distance before the maneuver. */\nexport interface VoiceInstruction {\n /** Metres before the end of the step at which to announce. */\n distanceAlongGeometry: number;\n /** Plain text for speech synthesis. */\n announcement: string;\n /** SSML form, preferred by engines that support it. */\n ssmlAnnouncement?: string;\n}\n\n/** One lane entry of a banner lane diagram. */\nexport interface LaneIndication {\n /** Turn directions this lane allows (OSRM indication strings). */\n directions: string[];\n /**\n * Whether the lane can be used for the maneuver. `undefined` means\n * unknown, not unusable — banner components omit the flag for\n * non-recommended lanes (see {@link bannerLanes}).\n */\n valid?: boolean;\n /** Whether guidance recommends this lane. */\n active?: boolean;\n}\n\n/** A typed fragment of banner content. */\nexport interface BannerComponent {\n type: string;\n text: string;\n directions?: string[];\n active?: boolean;\n}\n\n/** One banner line. */\nexport interface BannerContent {\n text: string;\n type?: string;\n modifier?: string;\n components?: BannerComponent[];\n}\n\n/** The visual banner shown while travelling a step. */\nexport interface BannerInstruction {\n distanceAlongGeometry: number;\n primary: BannerContent;\n secondary?: BannerContent;\n sub?: BannerContent;\n}\n\n/** Guidance data for one step of the route. */\nexport interface StepGuidance {\n /** Step index within the flattened route. */\n stepIndex: number;\n /** Step length in metres. */\n distanceM: number;\n /**\n * Written instruction for the step's upcoming maneuver. Taken from\n * `maneuver.instruction` when a server emits it (Mapbox-style); the\n * MapMap gateway does not, so it falls back to the step's final voice\n * announcement (the pre-transition instruction) and then to the banner\n * primary text. Undefined only when the step carries no guidance at all.\n */\n instruction?: string;\n /** Spoken announcements, ordered by descending trigger distance. */\n voice: VoiceInstruction[];\n /** Visual banners for the upcoming maneuver. */\n banners: BannerInstruction[];\n /**\n * OSRM travel mode of the step (`driving`, `ferry`, …) where the server\n * emits it. Pass the guidance entry as {@link GuidanceBanner.update}'s\n * second argument so ferry legs render the ferry icon.\n */\n mode?: string;\n /**\n * `left`/`right` where the server emits it (the MapMap gateway sets it on\n * u-turn steps), so u-turn icons point the correct way in left-hand-traffic\n * regions.\n */\n drivingSide?: string;\n}\n\n/**\n * Extracts per-step guidance from a parsed route (requires the route to\n * have been requested with `steps: true` and voice/banner enabled).\n * Steps without instructions yield empty arrays, never holes.\n */\nexport function extractGuidance(route: ParsedRoute): StepGuidance[] {\n const legs = (route.raw[\"legs\"] as Record<string, unknown>[] | undefined) ?? [];\n const out: StepGuidance[] = [];\n let index = 0;\n for (const leg of legs) {\n const steps = (leg[\"steps\"] as Record<string, unknown>[] | undefined) ?? [];\n for (const step of steps) {\n const voice = (step[\"voiceInstructions\"] as VoiceInstruction[] | undefined) ?? [];\n const banners = (step[\"bannerInstructions\"] as BannerInstruction[] | undefined) ?? [];\n const guidance: StepGuidance = {\n stepIndex: index,\n distanceM: Number(step[\"distance\"] ?? 0),\n instruction: stepInstruction(step, voice, banners),\n voice,\n banners,\n };\n if (typeof step[\"mode\"] === \"string\") guidance.mode = step[\"mode\"];\n if (typeof step[\"driving_side\"] === \"string\") {\n guidance.drivingSide = step[\"driving_side\"];\n }\n out.push(guidance);\n index += 1;\n }\n }\n return out;\n}\n\n/**\n * The written instruction for a step. The gateway's OSRM translation\n * (`sn-valhalla` `osrm.rs`) emits no `maneuver.instruction`; the written\n * text lives in the voice announcements (the last one is the pre-transition\n * instruction, e.g. \"Turn right onto High Street\") and in the banner\n * primary text. Prefer `maneuver.instruction` when a server does emit it.\n */\nfunction stepInstruction(\n step: Record<string, unknown>,\n voice: VoiceInstruction[],\n banners: BannerInstruction[],\n): string | undefined {\n const maneuver = step[\"maneuver\"] as Record<string, unknown> | undefined;\n const fromManeuver = maneuver?.[\"instruction\"];\n if (typeof fromManeuver === \"string\" && fromManeuver.length > 0) {\n return fromManeuver;\n }\n const lastVoice = voice[voice.length - 1];\n if (\n typeof lastVoice?.announcement === \"string\" &&\n lastVoice.announcement.length > 0\n ) {\n return lastVoice.announcement;\n }\n const bannerText = banners[0]?.primary?.text;\n if (typeof bannerText === \"string\" && bannerText.length > 0) {\n return bannerText;\n }\n return undefined;\n}\n\n/** Named XML entities the gateway's `xml_escape` (and standard SSML) emit. */\nconst XML_ENTITIES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \""\": '\"',\n \"'\": \"'\",\n};\n\n/**\n * Strips SSML tags down to speakable plain text. Entities are decoded in a\n * single pass (never re-scanning already-decoded output), so text whose\n * literal content looks like an entity — e.g. `&lt;`, the gateway's\n * escape of a literal `<` — round-trips correctly. Decodes the five\n * named XML entities plus decimal numeric references (`'`).\n */\nexport function ssmlToText(ssml: string): string {\n return ssml\n .replace(/<[^>]+>/g, \"\")\n .replace(/&(?:amp|lt|gt|quot|apos);|&#(\\d+);/g, (entity, decimal: string | undefined) => {\n if (decimal === undefined) return XML_ENTITIES[entity] ?? entity;\n // Range-check before decoding: a code point above U+10FFFF makes\n // `String.fromCodePoint` throw a RangeError, which would abort voice\n // guidance if a compromised gateway returned such a reference. Leave\n // an out-of-range entity untouched rather than throwing.\n const n = Number(decimal);\n return n <= 0x10ffff ? String.fromCodePoint(n) : entity;\n })\n .trim();\n}\n\n/**\n * Lane entries of a banner's sub line, if it carries a lane diagram.\n *\n * Banner lane components only carry `active` (the recommended lane) — the\n * gateway drops the per-lane `valid` flag from banners, keeping it in the\n * raw route's `intersections[].lanes`. An active lane is by definition\n * usable, so `valid` is `true` for active lanes and *unknown* (undefined,\n * never `false`) for the rest: a non-recommended lane may still be legal.\n * Read `route.raw` `legs[].steps[].intersections[].lanes` for the full\n * `valid` set.\n */\nexport function bannerLanes(banner: BannerInstruction): LaneIndication[] {\n const components = banner.sub?.components ?? [];\n return components\n .filter((c) => c.type === \"lane\")\n .map((c) => {\n const lane: LaneIndication = { directions: c.directions ?? [] };\n if (c.active !== undefined) lane.active = c.active;\n if (c.active === true) lane.valid = true;\n return lane;\n });\n}\n\n/**\n * Unicode arrow for a lane/maneuver direction (OSRM indication strings).\n * A text-only fallback; sprite-based lane icons ship with the map assets.\n */\nexport function directionArrow(direction: string): string {\n switch (direction) {\n case \"left\":\n return \"←\";\n case \"right\":\n return \"→\";\n case \"straight\":\n case \"none\":\n return \"↑\";\n case \"slight left\":\n return \"↖\";\n case \"slight right\":\n return \"↗\";\n case \"sharp left\":\n return \"↙\";\n case \"sharp right\":\n return \"↘\";\n case \"uturn\":\n return \"↶\";\n case \"merge to left\":\n return \"⬅\";\n case \"merge to right\":\n return \"➡\";\n default:\n return \"•\";\n }\n}\n\n/** Options for {@link speak}. */\nexport interface SpeakOptions {\n /** BCP 47 language for the utterance, e.g. `en-GB`. */\n lang?: string;\n /** Speech rate (0.1–10, default 1). */\n rate?: number;\n}\n\n/**\n * Speaks a voice instruction through the browser's `SpeechSynthesis`.\n * Prefers the SSML body's text (browsers do not accept raw SSML). Returns\n * false when speech synthesis is unavailable (e.g. non-browser contexts).\n * De-duplication is the caller's responsibility: speak each instruction\n * once as its trigger distance is crossed.\n */\nexport function speak(instruction: VoiceInstruction, options: SpeakOptions = {}): boolean {\n const synth = (globalThis as { speechSynthesis?: SpeechSynthesis }).speechSynthesis;\n const Utterance = (\n globalThis as {\n SpeechSynthesisUtterance?: typeof SpeechSynthesisUtterance;\n }\n ).SpeechSynthesisUtterance;\n if (!synth || !Utterance) return false;\n const text = instruction.ssmlAnnouncement\n ? ssmlToText(instruction.ssmlAnnouncement)\n : instruction.announcement;\n const utterance = new Utterance(text);\n if (options.lang) utterance.lang = options.lang;\n if (options.rate) utterance.rate = options.rate;\n synth.speak(utterance);\n return true;\n}\n\n/**\n * A minimal DOM banner: primary text with a maneuver icon from the platform\n * direction set (the same `direction-icons` glyphs the MapMap apps use —\n * ferry, roundabouts, forks, ramps and all), plus an optional lane row.\n * Style with the `mapmap-banner` / `mapmap-banner-lanes` /\n * `mapmap-banner-icon` classes, pass a Studio design (`extra.nav` `banner`\n * block, e.g. `map.navDesign?.banner`) to match a Studio theme, or read\n * {@link StepGuidance} yourself for fully custom UI. The icon's secondary\n * shapes retheme via the `--mm-icon-secondary` CSS custom property.\n */\nexport class GuidanceBanner {\n /** The banner root element; attach it wherever your UI needs it. */\n readonly element: HTMLElement;\n private readonly design: NavBannerDesign | undefined;\n\n constructor(container?: HTMLElement, design?: NavBannerDesign) {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"GuidanceBanner requires a DOM environment\");\n this.design = design;\n this.element = doc.createElement(\"div\");\n this.element.className = \"mapmap-banner\";\n // With a design, the derived metrics follow the Studio preview exactly\n // (gap = padding × 1.2, horizontal padding = padding × 1.4, arrow at\n // fontSize × 1.4, height set = min-height with contents vertically\n // centred, unset = auto). Without one the built-in look is unchanged.\n this.element.style.cssText = design\n ? \"display:none;align-items:center;box-sizing:border-box;\" +\n `gap:${Math.round((design.padding ?? 10) * 1.2)}px;` +\n `padding:${design.padding ?? 10}px ${Math.round((design.padding ?? 10) * 1.4)}px;` +\n `background:${safeColour(design.background, \"#101418\")};` +\n `color:${safeColour(design.textColor, \"#ffffff\")};` +\n `border-radius:${design.cornerRadius ?? 10}px;` +\n `max-width:${design.maxWidth ?? 340}px;` +\n (design.height !== undefined ? `min-height:${design.height}px;` : \"\") +\n `font:600 ${design.fontSize}px/1.3 system-ui,sans-serif`\n : \"display:none;gap:12px;align-items:center;padding:10px 14px;\" +\n \"background:#101418;color:#fff;border-radius:10px;\" +\n \"font:600 16px/1.3 system-ui,sans-serif\";\n container?.appendChild(this.element);\n }\n\n /**\n * Renders a banner instruction (or hides the element with `null`).\n *\n * `step` is optional icon context — pass the step's {@link StepGuidance}\n * (or any `{ mode, drivingSide }`) so ferry legs render the ferry glyph\n * and u-turns point the correct way in left-hand-traffic regions.\n */\n update(\n banner: BannerInstruction | null,\n step?: Pick<StepGuidance, \"mode\" | \"drivingSide\">,\n ): void {\n if (!banner) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n const doc = this.element.ownerDocument;\n this.element.style.display = \"flex\";\n\n // Manoeuvre glyph from the platform direction set. Safe innerHTML: the\n // markup is generated build-time constants keyed by a typed name —\n // never request or user input.\n const iconSize = this.design ? Math.round(this.design.fontSize * 1.4) : 22;\n const icon = doc.createElement(\"span\");\n icon.className = \"mapmap-banner-icon\";\n icon.setAttribute(\"aria-hidden\", \"true\");\n icon.style.cssText = `flex:none;display:inline-flex;width:${iconSize}px;height:${iconSize}px`;\n icon.innerHTML =\n directionIcons[\n iconNameForStep({\n maneuver: { type: banner.primary.type, modifier: banner.primary.modifier },\n mode: step?.mode,\n driving_side: step?.drivingSide,\n })\n ];\n // The generated SVGs carry fixed 20px width/height attributes; scale\n // them to the span so the design's font size drives the glyph size.\n const svg = icon.firstElementChild;\n if (svg) {\n svg.setAttribute(\"width\", \"100%\");\n svg.setAttribute(\"height\", \"100%\");\n }\n\n const text = doc.createElement(\"span\");\n text.textContent = banner.primary.text;\n\n const children: HTMLElement[] = [icon, text];\n\n const lanes = this.design?.showLanes === false ? [] : bannerLanes(banner);\n if (lanes.length > 0) {\n const laneRow = doc.createElement(\"span\");\n laneRow.className = \"mapmap-banner-lanes\";\n if (this.design) {\n // Studio preview semantics: letter-spacing scales with the padding\n // token, and each lane dims unless guidance recommends it.\n const spacing = Math.max(2, Math.round((this.design.padding ?? 10) * 0.4));\n laneRow.style.cssText = `margin-left:auto;letter-spacing:${spacing}px;white-space:nowrap`;\n for (const lane of lanes) {\n const glyph = doc.createElement(\"span\");\n glyph.textContent = directionArrow(lane.directions[0] ?? \"none\");\n glyph.style.opacity = lane.active ? \"0.95\" : \"0.35\";\n laneRow.appendChild(glyph);\n }\n } else {\n laneRow.style.cssText = \"margin-left:auto;letter-spacing:4px\";\n laneRow.textContent = lanes\n .map((lane) => directionArrow(lane.directions[0] ?? \"none\"))\n .join(\"\");\n laneRow.style.opacity = \"0.9\";\n }\n children.push(laneRow);\n }\n\n this.element.replaceChildren(...children);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Safety-camera alerts\n// ---------------------------------------------------------------------------\n\n/**\n * One camera alert to present. `kind` is normalised through\n * {@link navCameraKind}, so a raw gateway value (`\"redlight\"`) is accepted.\n *\n * JURISDICTION: whether a camera reaches you at all is decided server-side\n * before the response leaves the gateway. Nothing in this module can widen\n * that; it styles what the policy already permitted.\n */\nexport interface CameraAlert {\n /** Camera regime; wire values are normalised. */\n kind: NavCameraKind | string;\n /** Enforced limit in km/h, when known. */\n limitKph?: number;\n /** Metres to the camera, when known. */\n distanceM?: number;\n}\n\n/**\n * What a host should actually do with an alert, given the design and\n * whether the driver is currently over the limit.\n *\n * The rule this encodes, and the reason it is a pure function rather than\n * scattered branches in a renderer: the VISUAL alert is unconditional and\n * calm, and AUDIO is the escalation channel. A driver within the limit\n * still sees the chip; only the sound waits for speeding.\n */\nexport interface AlertPresentation {\n /** Whether to show the chip at all. */\n visible: boolean;\n /** Whether the chip should render in its escalated state. */\n escalated: boolean;\n /** Whether audio should fire now. */\n audible: boolean;\n /** Which audio channel to use when `audible`. */\n audioMode: NavAlertAudioMode;\n /**\n * The earcon to play for THIS state: the design's calm sound, or its\n * escalated variant when `escalated`. Always set (even when `audible` is\n * false) so a host can pre-load it; play it only when `audible`.\n */\n soundUrl: string;\n /** Metres of lead this design guarantees before the camera. */\n leadDistanceM: number;\n}\n\n/**\n * Resolves a design plus live state into what to present.\n *\n * Escalation is by INTENSITY, not identity: `escalated` restyles the same\n * chip and re-uses the same earcon motif more insistently. It never swaps\n * in a different icon or a different sound - kind is carried by the icon\n * and by speech, urgency by timbre, and mixing the two channels is how\n * drivers end up unable to tell \"a camera\" from \"you are speeding\".\n */\nexport function alertPresentation(\n design: NavAlertsDesign,\n alert: CameraAlert,\n state: { speeding?: boolean } = {},\n): AlertPresentation {\n const kind = navCameraKind(alert.kind);\n const rules = design.kinds[kind];\n const speeding = state.speeding === true;\n const audible =\n rules.audioMode !== \"off\" &&\n rules.alertWhileDriving &&\n (rules.alertMode === \"always\" || (rules.alertMode === \"whenSpeeding\" && speeding));\n return {\n visible: rules.alertWhileDriving,\n escalated: speeding,\n audible,\n audioMode: rules.audioMode,\n soundUrl: alertSoundUrl(design, speeding),\n leadDistanceM: navAlertLeadDistanceM(design.leadDistance),\n };\n}\n\n/**\n * The earcon URL for a design in the calm or escalated state.\n *\n * A design-level `alertSoundUrl` / `escalatedSoundUrl` override wins;\n * otherwise the chosen built-in resolves against the hosted earcon\n * library. There is deliberately no per-kind sound: kind travels in the\n * icon and in speech, urgency travels in timbre.\n */\nexport function alertSoundUrl(design: NavAlertsDesign, escalated: boolean): string {\n const override = escalated ? design.escalatedSoundUrl : design.alertSoundUrl;\n if (override !== undefined) return override;\n return navAlertSoundUrl(escalated ? design.escalatedSound : design.alertSound);\n}\n\n/** Whether the map is being browsed or actively navigated. */\nexport type MapDisplayMode = \"browse\" | \"navigating\";\n\n/**\n * Whether a kind's pin should be drawn on the map in the given mode.\n *\n * Browsing and navigating are separate switches because they are separate\n * decisions - the market warns with or without a planned route, so a\n * design that shows a camera on the planning map is not thereby committed\n * to a cluttered driving map, nor the reverse.\n */\nexport function cameraShownOnMap(\n design: NavAlertsDesign,\n kind: NavCameraKind | string,\n mode: MapDisplayMode = \"browse\",\n): boolean {\n const rules = design.kinds[navCameraKind(kind)];\n return mode === \"navigating\" ? rules.showOnMapWhileNavigating : rules.showOnMap;\n}\n\n/**\n * The camera kinds a style should draw in the given mode, in the canonical\n * kind order. Feed it straight into a MapLibre `filter` (see\n * {@link cameraSymbolLayer}); an empty array means \"draw nothing\", which\n * a caller must honour by removing or hiding the layer.\n */\nexport function cameraKindsShownOnMap(\n design: NavAlertsDesign,\n mode: MapDisplayMode = \"browse\",\n): NavCameraKind[] {\n return NAV_CAMERA_KINDS.filter((kind) => cameraShownOnMap(design, kind, mode));\n}\n\n/**\n * A MapLibre symbol layer that draws camera POIs from the sprite sheet.\n *\n * Additive by design: the style compiler is untouched and ships no camera\n * layer of its own, because cameras arrive as host data (the gateway's\n * `POST /v1/cameras/along`, projected into a GeoJSON source) rather than\n * in the vector tiles. Point this at that source and the sprite icons\n * built from `map-assets/icons/cameras` render at the design's size, zoom\n * floor and per-mode visibility.\n *\n * The features must carry a `kind` property holding one of\n * {@link NAV_CAMERA_KINDS} (or the gateway's `redlight` spelling); an\n * unrecognised value falls back to the `unknown` icon, never to a guess at\n * a specific camera type.\n *\n * @param source GeoJSON source id holding the camera features.\n * @param variant Sprite variant to draw: `\"light\"` icons read on a dark\n * basemap, `\"dark\"` icons on a light one.\n */\nexport function cameraSymbolLayer(\n design: NavAlertsDesign,\n source: string,\n mode: MapDisplayMode = \"browse\",\n variant: \"light\" | \"dark\" = \"dark\",\n id = \"safety-cameras\",\n): Record<string, unknown> {\n const kinds = cameraKindsShownOnMap(design, mode);\n const iconImage: unknown[] = [\"match\", [\"get\", \"kind\"]];\n for (const kind of NAV_CAMERA_KINDS) {\n if (kind === \"unknown\") continue;\n // `red_light` is the design's spelling, `redlight` the gateway's wire\n // spelling — both must land on the same sprite.\n const values = kind === \"red_light\" ? [\"red_light\", \"redlight\"] : [kind];\n iconImage.push(values.length === 1 ? values[0] : values, cameraSpriteName(kind, variant));\n }\n iconImage.push(cameraSpriteName(\"unknown\", variant));\n return {\n id,\n type: \"symbol\",\n source,\n minzoom: design.mapMinZoom,\n filter: [\"in\", [\"get\", \"kind\"], [\"literal\", kinds as string[]]],\n layout: {\n \"icon-image\": iconImage,\n \"icon-size\": design.mapIconSize,\n \"icon-allow-overlap\": true,\n \"icon-ignore-placement\": false,\n },\n };\n}\n\n/**\n * Sprite image id for a camera kind, as built into the published sprite\n * sheet by `map-assets/icons/cameras/generate.mjs`.\n *\n * LOCKSTEP: the file names in `map-assets/sprites/svg/camera-*.svg` are\n * exactly these ids — spreet names each image after its file.\n */\nexport function cameraSpriteName(\n kind: NavCameraKind | string,\n variant: \"light\" | \"dark\" = \"dark\",\n): string {\n const normalised = navCameraKind(kind);\n const slug = normalised === \"red_light\" ? \"redlight\" : normalised.replace(/_/g, \"-\");\n return `camera-${slug}-${variant}`;\n}\n\n/**\n * Human-readable name for a camera kind, used in the chip's text and in\n * the spoken announcement. Kind lives here and in the icon, never in the\n * earcon.\n */\nexport function cameraKindLabel(kind: NavCameraKind | string): string {\n switch (navCameraKind(kind)) {\n case \"fixed\":\n return \"Speed camera\";\n case \"average\":\n return \"Average speed check\";\n case \"red_light\":\n return \"Red light camera\";\n case \"mobile_site\":\n return \"Mobile camera site\";\n default:\n return \"Safety camera\";\n }\n}\n\n/**\n * Single-colour SVG glyphs per camera kind, drawn in `currentColor` so the\n * chip's text token colours them in both states. 24x24 viewBox, no fills\n * that assume a light or dark chip.\n */\nconst ALERT_KIND_GLYPHS: Record<NavCameraKind, string> = {\n fixed:\n '<rect x=\"3\" y=\"8\" width=\"13\" height=\"9\" rx=\"2\"/><circle cx=\"9.5\" cy=\"12.5\" r=\"2.6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"/><path d=\"M16 11.5 21 9v7l-5-2.5z\"/>',\n average:\n '<rect x=\"2\" y=\"9\" width=\"7\" height=\"7\" rx=\"1.6\"/><rect x=\"15\" y=\"9\" width=\"7\" height=\"7\" rx=\"1.6\"/><path d=\"M9.8 12.5h4.4\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\"/><path d=\"M13 10.9l1.9 1.6-1.9 1.6z\"/>',\n red_light:\n '<rect x=\"8\" y=\"2.5\" width=\"8\" height=\"19\" rx=\"2.4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><circle cx=\"12\" cy=\"7\" r=\"1.8\"/><circle cx=\"12\" cy=\"12\" r=\"1.8\" opacity=\"0.45\"/><circle cx=\"12\" cy=\"17\" r=\"1.8\" opacity=\"0.45\"/>',\n mobile_site:\n '<rect x=\"4\" y=\"4.5\" width=\"12\" height=\"8\" rx=\"2\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-dasharray=\"3 2\"/><circle cx=\"10\" cy=\"8.5\" r=\"2.2\"/><path d=\"M10 12.5v3m0 0-4 5m4-5 4 5\" stroke=\"currentColor\" stroke-width=\"1.6\" fill=\"none\"/>',\n unknown:\n '<circle cx=\"12\" cy=\"12\" r=\"9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"/><path d=\"M9.4 9.4a2.7 2.7 0 1 1 3.4 2.6v1.6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\"/><circle cx=\"12.4\" cy=\"16.6\" r=\"1.15\"/>',\n};\n\n/** Frame drawn around the glyph, per curated icon set. */\nconst ALERT_SET_FRAMES: Record<string, string> = {\n european:\n '<circle cx=\"12\" cy=\"12\" r=\"11\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" opacity=\"0.85\"/>',\n us: '<rect x=\"1.4\" y=\"1.4\" width=\"21.2\" height=\"21.2\" rx=\"4.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" opacity=\"0.85\"/>',\n minimal: \"\",\n brand: \"\",\n};\n\n/**\n * The icon for a kind under a design, as a complete inline SVG string.\n *\n * `iconSet` chooses the frame (a European circular plate, a US rounded\n * plate, or no frame); the glyph inside always encodes the KIND, because\n * that is the channel kind is allowed to travel on. `\"brand\"` draws the\n * unframed glyph as its fallback - it expects an `iconUrlOverrides` entry,\n * and {@link alertIconUrl} is what actually resolves one.\n */\nexport function alertIconSvg(design: NavAlertsDesign, kind: NavCameraKind | string): string {\n const normalised = navCameraKind(kind);\n const frame = ALERT_SET_FRAMES[design.iconSet] ?? \"\";\n const glyph = ALERT_KIND_GLYPHS[normalised];\n return `<svg viewBox=\"0 0 24 24\" width=\"100%\" height=\"100%\" fill=\"currentColor\" aria-hidden=\"true\">${frame}${glyph}</svg>`;\n}\n\n/**\n * The override URL for a kind, if the design sets one. Overrides win over\n * `iconSet` for that kind only; every other kind keeps the curated icon.\n */\nexport function alertIconUrl(\n design: NavAlertsDesign,\n kind: NavCameraKind | string,\n): string | undefined {\n return design.iconUrlOverrides?.[navCameraKind(kind)];\n}\n\n/**\n * Template-shaped content for an alert: the fields a head unit can\n * actually render.\n *\n * CarPlay's `CPNavigationAlert` and Android Auto's `Alert` inside a\n * `NavigationTemplate` take a title, a subtitle and an image - the system\n * draws them, and none of the chip's colour, radius or position tokens\n * survive the trip. Hosts targeting a head unit should read this instead\n * of the DOM chip, so styling degrades gracefully rather than being\n * assumed to render.\n */\nexport interface AlertChipContent {\n kind: NavCameraKind;\n /** Primary line, e.g. \"Average speed check\". */\n title: string;\n /** Secondary line: limit and distance when known, else empty. */\n subtitle: string;\n /** Override icon URL when the design sets one for this kind. */\n iconUrl?: string;\n}\n\n/** The text/icon content of an alert chip, free of any styling tokens. */\nexport function alertChipContent(\n design: NavAlertsDesign,\n alert: CameraAlert,\n): AlertChipContent {\n const kind = navCameraKind(alert.kind);\n const parts: string[] = [];\n if (typeof alert.limitKph === \"number\" && Number.isFinite(alert.limitKph)) {\n parts.push(`${Math.round(alert.limitKph)} km/h`);\n }\n if (typeof alert.distanceM === \"number\" && Number.isFinite(alert.distanceM)) {\n const m = Math.max(0, Math.round(alert.distanceM));\n parts.push(m >= 1000 ? `${(m / 1000).toFixed(1)} km` : `${m} m`);\n }\n const iconUrl = alertIconUrl(design, kind);\n return {\n kind,\n title: cameraKindLabel(kind),\n subtitle: parts.join(\" · \"),\n ...(iconUrl !== undefined ? { iconUrl } : {}),\n };\n}\n\n/**\n * The colour a host should paint the SPEED readout, given a design and\n * whether the driver is speeding.\n *\n * Deliberate division of labour: the escalation the driver reads is the\n * speed number turning the escalated colour, while the alert chip stays\n * legible in its own escalated tokens. Colouring the card and leaving the\n * speed untouched puts the urgency on the wrong element - the driver has\n * to act on the speed, so the speed is what changes. Returns `undefined`\n * when calm, meaning \"leave the readout in its normal colour\".\n */\nexport function alertSpeedReadoutColor(\n design: NavAlertsDesign,\n escalated: boolean,\n): string | undefined {\n return escalated ? design.escalatedBackground : undefined;\n}\n\n/** CSS positioning for each constrained chip slot. */\nconst CHIP_SLOT_CSS: Record<string, string> = {\n // Directly above the speed pill: the chip's own bottom margin keeps it\n // clear of the readout rather than overlapping it.\n aboveSpeed: \"align-self:center;margin-bottom:8px;\",\n topLeading: \"align-self:flex-start;\",\n topTrailing: \"align-self:flex-end;\",\n};\n\n/**\n * A minimal DOM safety-alert chip: kind icon, kind label and (when known)\n * the limit and distance, in a calm or escalated state.\n *\n * Style with the `mapmap-alert-chip` class, or pass a Studio design\n * (`extra.nav` `alerts` block, e.g. `map.navDesign?.alerts`) to match a\n * Studio theme. Framework-free and DOM-only, exactly like\n * {@link GuidanceBanner}; head units should read {@link alertChipContent}\n * instead.\n *\n * The chip NEVER overlaps the speed or the limit: its position comes from\n * a constrained slot enum, and `aboveSpeed` reserves its own clearance.\n */\nexport class CameraAlertChip {\n /** The chip root element; attach it wherever your UI needs it. */\n readonly element: HTMLElement;\n private readonly design: NavAlertsDesign | undefined;\n private escalated = false;\n\n constructor(container?: HTMLElement, design?: NavAlertsDesign) {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"CameraAlertChip requires a DOM environment\");\n this.design = design;\n this.element = doc.createElement(\"div\");\n this.element.className = \"mapmap-alert-chip\";\n this.element.setAttribute(\"role\", \"status\");\n if (design) this.element.dataset[\"position\"] = design.chipPosition;\n this.applyStateStyles();\n container?.appendChild(this.element);\n }\n\n /** Whether the chip is currently in its escalated state. */\n get isEscalated(): boolean {\n return this.escalated;\n }\n\n /**\n * Renders an alert (or hides the chip with `null`). `state.speeding`\n * drives the escalated state; the chip itself shows regardless, because\n * the visual alert is unconditional.\n *\n * A kind whose design turns `alertWhileDriving` off hides the chip: the\n * customer chose not to surface that kind while driving.\n */\n update(alert: CameraAlert | null, state: { speeding?: boolean } = {}): void {\n if (!alert) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n const doc = this.element.ownerDocument;\n const design = this.design;\n if (design) {\n const presentation = alertPresentation(design, alert, state);\n if (!presentation.visible) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n this.escalated = presentation.escalated;\n } else {\n this.escalated = state.speeding === true;\n }\n this.applyStateStyles();\n this.element.style.display = \"inline-flex\";\n this.element.dataset[\"state\"] = this.escalated ? \"escalated\" : \"calm\";\n\n const kind = navCameraKind(alert.kind);\n const content = design\n ? alertChipContent(design, alert)\n : { kind, title: cameraKindLabel(kind), subtitle: \"\", iconUrl: undefined };\n\n const icon = doc.createElement(\"span\");\n icon.className = \"mapmap-alert-chip-icon\";\n icon.style.cssText = \"display:inline-flex;width:20px;height:20px;flex:0 0 auto\";\n const overrideUrl = design ? alertIconUrl(design, kind) : undefined;\n if (overrideUrl) {\n const img = doc.createElement(\"img\");\n img.src = overrideUrl;\n img.alt = \"\";\n img.style.cssText = \"width:100%;height:100%;object-fit:contain\";\n icon.appendChild(img);\n } else if (design) {\n icon.innerHTML = alertIconSvg(design, kind);\n }\n\n const text = doc.createElement(\"span\");\n text.textContent = content.title;\n\n const children: HTMLElement[] = [icon, text];\n if (content.subtitle) {\n const detail = doc.createElement(\"span\");\n detail.className = \"mapmap-alert-chip-detail\";\n detail.textContent = content.subtitle;\n detail.style.cssText = \"opacity:0.85;font-weight:500\";\n children.push(detail);\n }\n this.element.replaceChildren(...children);\n }\n\n /** Writes the calm/escalated tokens (and slot) onto the root element. */\n private applyStateStyles(): void {\n const design = this.design;\n const shown = this.element.style.display !== \"none\" ? this.element.style.display : \"none\";\n if (!design) {\n this.element.style.cssText =\n `display:${shown};gap:8px;align-items:center;padding:8px 12px;` +\n `background:${this.escalated ? \"#c0392b\" : \"#101418\"};color:#fff;` +\n \"border-radius:10px;font:600 15px/1.3 system-ui,sans-serif\";\n return;\n }\n const background = this.escalated\n ? safeColour(design.escalatedBackground, \"#c0392b\")\n : safeColour(design.background, \"#101418\");\n const color = this.escalated\n ? safeColour(design.escalatedTextColor, \"#ffffff\")\n : safeColour(design.textColor, \"#ffffff\");\n this.element.style.cssText =\n `display:${shown};gap:8px;align-items:center;box-sizing:border-box;padding:8px 12px;` +\n `background:${background};color:${color};` +\n `border-radius:${design.cornerRadius}px;` +\n (design.outlineWidth > 0\n ? `border:${design.outlineWidth}px solid ${safeColour(design.outlineColor, \"#ffffff\")};`\n : \"\") +\n (CHIP_SLOT_CSS[design.chipPosition] ?? \"\") +\n \"font:600 15px/1.3 system-ui,sans-serif\";\n }\n}\n","/**\n * Spoken turn-by-turn guidance over the browser's `SpeechSynthesis`.\n *\n * {@link VoiceGuidance} consumes the guidance updates emitted by the\n * `@mapmap/core` wasm `GuidanceSession` (`{ state: \"navigating\" | \"arrived\"\n * | \"offRoute\", spoken?, severity?, … }`). The core already schedules each\n * spoken prompt by its trigger distance and repeats it on every update\n * until it is superseded, so the speaking rule is simple: announce each\n * `utteranceId` exactly once, the first time it appears.\n *\n * Severity (derived in the Rust core — see `InstructionSeverity`) maps to\n * prosody and earcons:\n *\n * - `info` — normal manoeuvres: base rate/pitch, no earcon by default;\n * - `warning` — approaching a restriction (toll, ferry): slight pitch\n * lift, warning earcon when configured;\n * - `critical` — prohibitions (ADR tunnel block, gate): pitch and rate\n * lift, pending speech cancelled so the prompt is never queued behind\n * chatter, critical earcon when configured.\n *\n * Off-route updates carry no instruction; they play the warning earcon\n * once per off-route episode (the app recalculates and speech resumes on\n * the new session).\n *\n * Earcons are lazy URLs (see `map-assets/earcons/`, generated by\n * `scripts/generate-earcons.py`) — nothing is bundled with the SDK.\n * Everything no-ops safely where `speechSynthesis` is unavailable\n * (non-browser contexts, some webviews).\n */\n\nimport { ssmlToText } from \"./guidance.js\";\n\n/** Instruction urgency, as emitted by the core (`InstructionSeverity`). */\nexport type GuidanceSeverity = \"info\" | \"warning\" | \"critical\";\n\n/** The spoken prompt of a core guidance update. */\nexport interface GuidanceSpokenPrompt {\n /** Plain text for speech synthesis. */\n text: string;\n /** SSML form; browsers reject raw SSML, so it is stripped to text. */\n ssml?: string | null;\n /** Metres before the manoeuvre at which the core released the prompt. */\n triggerDistanceM: number;\n /** Unique utterance id — the de-duplication key. */\n utteranceId: string;\n}\n\n/** The subset of a core guidance update that {@link VoiceGuidance} reads. */\nexport interface VoiceGuidanceUpdate {\n /** Guidance state, as emitted by the wasm `GuidanceSession`. */\n state: \"navigating\" | \"arrived\" | \"offRoute\";\n /** Spoken prompt currently due (repeated until superseded). */\n spoken?: GuidanceSpokenPrompt | null;\n /** Urgency of the current step's instruction (default `info`). */\n severity?: GuidanceSeverity;\n /** BCP 47 locale of the instruction text, when the payload carries one. */\n voiceLocale?: string;\n}\n\n/** Options for {@link VoiceGuidance}. */\nexport interface VoiceGuidanceOptions {\n /** BCP 47 language for utterances, e.g. `en-GB`. An update's\n * `voiceLocale` takes precedence when present. */\n lang?: string;\n /** Base speech rate (0.1–10, default 1). Critical prompts speak\n * slightly faster than this base. */\n rate?: number;\n /** Volume for speech and earcons, 0–1 (default 1). */\n volume?: number;\n /** Start muted. */\n muted?: boolean;\n /** Severity → earcon audio URL. Absent entries play nothing. */\n earcons?: Partial<Record<GuidanceSeverity, string>>;\n}\n\n/** Speech parameters for one severity level. */\nexport interface SeverityProsody {\n /** Utterance rate. */\n rate: number;\n /** Utterance pitch (0–2, 1 = neutral). */\n pitch: number;\n /** Whether pending speech is cancelled before this prompt. */\n interrupt: boolean;\n}\n\n/**\n * Prosody for a severity level at a base rate. Pure — exported for tests\n * and for custom voice layers that want the same house style.\n */\nexport function severityProsody(\n severity: GuidanceSeverity,\n baseRate = 1,\n): SeverityProsody {\n switch (severity) {\n case \"critical\":\n return { rate: baseRate * 1.1, pitch: 1.2, interrupt: true };\n case \"warning\":\n return { rate: baseRate, pitch: 1.1, interrupt: false };\n default:\n return { rate: baseRate, pitch: 1, interrupt: false };\n }\n}\n\n/** Severities that play their earcon by default (info stays silent so a\n * chime does not precede every routine manoeuvre). */\nconst EARCON_SEVERITIES: readonly GuidanceSeverity[] = [\"warning\", \"critical\"];\n\n/**\n * Speaks core guidance updates through the browser's `SpeechSynthesis`,\n * with severity-aware prosody, optional earcons, and mute/volume\n * controls. Feed every update from the wasm `GuidanceSession` to\n * {@link VoiceGuidance.update}.\n */\nexport class VoiceGuidance {\n private readonly options: VoiceGuidanceOptions;\n private volume: number;\n private mutedState: boolean;\n private lastUtteranceId: string | undefined;\n private offRouteAnnounced = false;\n\n constructor(options: VoiceGuidanceOptions = {}) {\n this.options = options;\n this.volume = clampVolume(options.volume ?? 1);\n this.mutedState = options.muted ?? false;\n }\n\n /** Whether this environment can speak at all. */\n get available(): boolean {\n return synth() !== undefined && utteranceCtor() !== undefined;\n }\n\n /** Whether announcements are currently muted. */\n get muted(): boolean {\n return this.mutedState;\n }\n\n /** Mute announcements (also cancels anything mid-utterance). */\n mute(): void {\n this.mutedState = true;\n synth()?.cancel();\n }\n\n /** Unmute announcements. Prompts seen while muted are not replayed. */\n unmute(): void {\n this.mutedState = false;\n }\n\n /** Set the volume for speech and earcons (clamped to 0–1). */\n setVolume(volume: number): void {\n this.volume = clampVolume(volume);\n }\n\n /**\n * Consume one guidance update. Speaks the update's prompt the first\n * time its `utteranceId` appears; plays the warning earcon once per\n * off-route episode. Safe to call in any environment.\n */\n update(update: VoiceGuidanceUpdate): void {\n if (update.state === \"offRoute\") {\n if (!this.offRouteAnnounced) {\n this.offRouteAnnounced = true;\n this.playEarcon(\"warning\");\n }\n return;\n }\n this.offRouteAnnounced = false;\n const spoken = update.spoken;\n if (!spoken || spoken.utteranceId === this.lastUtteranceId) return;\n // Record before the mute check: prompts seen while muted must not\n // replay, stale, on unmute.\n this.lastUtteranceId = spoken.utteranceId;\n this.speak(spoken, update.severity ?? \"info\", update.voiceLocale);\n }\n\n /** Cancel any speech in progress and forget the de-duplication state. */\n dispose(): void {\n synth()?.cancel();\n this.lastUtteranceId = undefined;\n this.offRouteAnnounced = false;\n }\n\n private speak(\n prompt: GuidanceSpokenPrompt,\n severity: GuidanceSeverity,\n voiceLocale: string | undefined,\n ): void {\n if (this.mutedState) return;\n const synthesis = synth();\n const Utterance = utteranceCtor();\n if (!synthesis || !Utterance) return;\n\n const prosody = severityProsody(severity, this.options.rate ?? 1);\n if (prosody.interrupt) synthesis.cancel();\n if (EARCON_SEVERITIES.includes(severity)) this.playEarcon(severity);\n\n const text = prompt.ssml ? ssmlToText(prompt.ssml) : prompt.text;\n const utterance = new Utterance(text);\n const lang = voiceLocale ?? this.options.lang;\n if (lang) utterance.lang = lang;\n utterance.rate = prosody.rate;\n utterance.pitch = prosody.pitch;\n utterance.volume = this.volume;\n synthesis.speak(utterance);\n }\n\n private playEarcon(severity: GuidanceSeverity): void {\n if (this.mutedState) return;\n const url = this.options.earcons?.[severity];\n if (!url) return;\n const AudioCtor = (globalThis as { Audio?: typeof Audio }).Audio;\n if (!AudioCtor) return;\n const audio = new AudioCtor(url);\n audio.volume = this.volume;\n // Autoplay can be rejected before a user gesture; guidance must\n // never throw over a missing chime.\n void audio.play()?.catch?.(() => {});\n }\n}\n\nfunction synth(): SpeechSynthesis | undefined {\n return (globalThis as { speechSynthesis?: SpeechSynthesis }).speechSynthesis;\n}\n\nfunction utteranceCtor(): typeof SpeechSynthesisUtterance | undefined {\n return (\n globalThis as { SpeechSynthesisUtterance?: typeof SpeechSynthesisUtterance }\n ).SpeechSynthesisUtterance;\n}\n\nfunction clampVolume(volume: number): number {\n if (!Number.isFinite(volume)) return 1;\n return Math.min(1, Math.max(0, volume));\n}\n"]}
|