leaflet-juicy 0.0.0-stage → 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 leaflet-juicy contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,378 @@
1
- # Temporary Holding Version
1
+ # leaflet-juicy
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **Beautiful, lightweight maps for Leaflet.** Vector basemaps with light and dark themes, modern SVG markers, route styles and a familiar `maps.*` API. Free tiles, no API keys.
4
+
5
+ **[Live demo](https://nopinhere.github.io/leaflet-juicy/demo/)** · **[Docs](https://nopinhere.github.io/leaflet-juicy/docs/)** · **[Theme builder](https://nopinhere.github.io/leaflet-juicy/docs/theme-builder.html)**
6
+
7
+ > **Early version (0.0.1).** The API may still change between releases.
8
+
9
+ | Juicy | Juicy Dark | Hybrid |
10
+ |---|---|---|
11
+ | ![Juicy](docs/img/juicy.jpg) | ![Juicy Dark](docs/img/juicy-dark.jpg) | ![Hybrid](docs/img/hybrid.jpg) |
12
+
13
+ ```js
14
+ import { juicyBasemap, juicyMarker } from 'leaflet-juicy';
15
+ import 'leaflet-juicy/style.css';
16
+
17
+ const map = L.map('map', { center: [50.45, 30.52], zoom: 14, zoomSnap: 0.25 });
18
+ juicyBasemap({ theme: 'juicy' }).addTo(map);
19
+ juicyMarker([50.4529, 30.5143], { glyph: 'museum', color: '#1a73e8', label: 'St Sophia' }).addTo(map);
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Why
25
+
26
+ - **Looks modern out of the box.** You get crisp vector rendering, a soft palette, labels with halos and fractional zoom, instead of the grainy default raster look.
27
+ - **Free.** The default tiles come from [OpenFreeMap](https://openfreemap.org): no API key, no request limits, no billing account.
28
+ - **Light.** The whole package is about 14 KB gzipped. The WebGL renderer is downloaded **lazily**, only when a vector basemap is actually shown.
29
+ - **Easy to migrate.** Map styles use the widely known JSON `styles` format (`featureType` / `elementType` / `stylers`). There is also a compatible `maps.Map`, `Marker`, `InfoWindow`… API, so existing code mostly keeps working.
30
+ - **Themable.** Pick colors in the [theme builder](docs/theme-builder.html), export JSON and plug it in. No style-spec knowledge needed.
31
+ - **Still plain Leaflet.** Every Leaflet plugin keeps working. Each wrapper exposes the underlying Leaflet object as `.leaflet`.
32
+
33
+ ## At a glance
34
+
35
+ | | Size (min + gzip) | Loaded |
36
+ |---|---|---|
37
+ | `leaflet-juicy/markers` | **2.2 KB** | always |
38
+ | `leaflet-juicy/basemap` (+ themes, style translator) | **4.7 KB** | always |
39
+ | `leaflet-juicy/routes` | **1.5 KB** | if you import it |
40
+ | `leaflet-juicy/compat` (`maps.*` API, includes markers + basemap) | **12.2 KB** | if you import it |
41
+ | `leaflet-juicy/style.css` | **1.9 KB** | always |
42
+ | MapLibre GL renderer | ~205 KB | **lazily**, on the first `juicyBasemap().addTo(map)` |
43
+ | Base style JSON | ~5 KB | once, cached and shared by every theme switch |
44
+
45
+ For comparison, Leaflet itself is 41 KB gzipped.
46
+
47
+ **Resource-friendly defaults:**
48
+ - Switching themes diffs the style on the same WebGL context. Nothing is re-created.
49
+ - Device pixel ratio is capped at 2.
50
+ - The tile cache is limited to 200 tiles.
51
+ - Hidden layers, 3D extrusions and unused sources are stripped from the style before rendering.
52
+ - Markers are plain DOM: no images, no canvas, no extra requests.
53
+ - Marker animations respect `prefers-reduced-motion`.
54
+
55
+ **Requirements:** Leaflet 1.9.x and an evergreen browser (ES2020, WebGL for vector basemaps).
56
+
57
+ ---
58
+
59
+ ## Install
60
+
61
+ ```bash
62
+ npm i leaflet-juicy leaflet
63
+ # optional, only if you want the renderer bundled instead of loaded from a CDN:
64
+ npm i maplibre-gl @maplibre/maplibre-gl-leaflet
65
+ ```
66
+
67
+ **Without a bundler:**
68
+
69
+ ```html
70
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
71
+ <link rel="stylesheet" href="https://unpkg.com/leaflet-juicy/src/juicy.css">
72
+ <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
73
+ <script type="module">
74
+ import { juicyBasemap, juicyMarker } from 'https://unpkg.com/leaflet-juicy/src/index.js';
75
+ // ...
76
+ </script>
77
+ ```
78
+
79
+ > Leaflet must be available as the global `L`. Leaflet 1.x sets it automatically, even when you import it from a bundler.
80
+
81
+ ---
82
+
83
+ ## Basemap
84
+
85
+ ```js
86
+ const base = juicyBasemap({
87
+ theme: 'juicy', // 'juicy' | 'juicy-dark' | 'hybrid' | 'none' | rules array | { palette } | URL of a theme .json
88
+ palette: { water: '#7fc4f0' }, // color overrides for juicy / juicy-dark
89
+ adjust: { hue: null, saturation: -30, lightness: 0 }, // whole-map tint, -100…100
90
+ show: { pois: false, transit: true }, // pois, transit, buildings, roadLabels, placeLabels, waterLabels
91
+ styles: [], // extra rules applied on top of the theme
92
+ font: 'noto', // 'noto' | 'open-sans' | { glyphs, regular, bold?, italic? }
93
+ language: 'en', // label language: 'en' | 'de' | 'uk' | … | 'local' | null (Latin + local, default)
94
+ extrusions: false, // keep 3D building layers (useless without pitch, so off by default)
95
+ maplibre: {}, // extra MapLibre map options, e.g. { maxTileCacheSize: 100 }
96
+ }).addTo(map);
97
+
98
+ base.setTheme('juicy-dark'); // instant: diffs the style, keeps the WebGL context
99
+ base.setMapStyles(rules);
100
+ base.setFont('open-sans');
101
+ base.setLanguage('local');
102
+ base.update({ theme, styles, font });
103
+
104
+ base.on('rendererload', () => {}); // MapLibre finished loading
105
+ base.on('stylechange', e => e.style); // the MapLibre style that was applied
106
+ base.on('styleerror', e => console.error(e.error));
107
+ ```
108
+
109
+ **Satellite / hybrid:** put any imagery tile layer in a pane under the vector layer, then use the labels-only `hybrid` theme:
110
+
111
+ ```js
112
+ map.createPane('imagery').style.zIndex = 150;
113
+ L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
114
+ { pane: 'imagery', attribution: 'Imagery © Esri' }).addTo(map);
115
+ juicyBasemap({ theme: 'hybrid' }).addTo(map);
116
+ ```
117
+
118
+ ### One JSON config
119
+
120
+ All basemap options are plain JSON, so a whole map look can live in a file. In the demo, the **Custom** tile opens a live theme editor (colors, tone, visibility); its **JSON** view shows exactly this object and downloads it as `juicy.config.json`:
121
+
122
+ ```js
123
+ juicyBasemap(await fetch('/juicy.config.json').then(r => r.json())).addTo(map);
124
+ ```
125
+
126
+ ### Fonts
127
+
128
+ Map labels need glyph files (PBF), so the font is set in two places: one for the map, one for the HTML parts.
129
+
130
+ ```js
131
+ juicyBasemap({ font: 'open-sans' }); // map labels: built-in presets
132
+ juicyBasemap({ font: { // ...or your own glyph server
133
+ glyphs: 'https://example.com/fonts/{fontstack}/{range}.pbf',
134
+ regular: 'Inter Regular', bold: 'Inter Bold', italic: 'Inter Italic',
135
+ } });
136
+ ```
137
+
138
+ ```css
139
+ :root { --jm-font: "Inter", system-ui, sans-serif; } /* markers, info windows, controls */
140
+ ```
141
+
142
+ To generate glyph PBFs from any TTF/OTF, use [font-maker](https://github.com/maplibre/font-maker).
143
+
144
+ ### Lazy loading with a bundler
145
+
146
+ By default the renderer is fetched from unpkg the first time a basemap is added. To ship it from your own bundle as a separate chunk instead:
147
+
148
+ ```js
149
+ import { setMaplibreLoader, loadMaplibre } from 'leaflet-juicy';
150
+
151
+ setMaplibreLoader(async () => {
152
+ await import('maplibre-gl/dist/maplibre-gl.css');
153
+ await import('@maplibre/maplibre-gl-leaflet'); // pulls maplibre-gl in the same async chunk
154
+ });
155
+
156
+ // optional: warm it up while the browser is idle
157
+ requestIdleCallback(() => loadMaplibre());
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Markers
163
+
164
+ Seven built-in variants, all pure CSS/SVG:
165
+
166
+ | `variant` | Looks like | Good for |
167
+ |---|---|---|
168
+ | `glass` (default) | frosted translucent circle with a colored icon | most maps; for many hundreds of markers prefer `dot` or `circle` (`backdrop-filter` costs GPU) |
169
+ | `drop` | classic pin with an icon | general use |
170
+ | `circle` | colored circle with a white ring | dense maps |
171
+ | `poi` | small icon + name next to it | points of interest |
172
+ | `pill` | white pill with a value (rating, price); expands to the name on hover | listings, catalogs |
173
+ | `tile` | rounded square with a tail | app-like UIs |
174
+ | `dot` | 16 px dot, name on hover | hundreds or thousands of points |
175
+
176
+ ```js
177
+ import { juicyMarker, setMarkerDefaults, registerMarkerVariant, GLYPHS } from 'leaflet-juicy/markers';
178
+
179
+ setMarkerDefaults({ variant: 'pill', color: '#1a73e8' }); // global default (built-in default: 'glass')
180
+
181
+ const m = juicyMarker([50.45, 30.52], {
182
+ variant: 'poi', // per-marker override (null = use the default)
183
+ color: '#e37400', // any CSS color
184
+ glyph: 'cafe', // built-in name or an SVG path "d"
185
+ glyphHtml: null, // raw <svg> markup, inserted as-is (trusted input only)
186
+ label: 'Coffee House', // name: shown by poi/dot/pill; used as tooltip otherwise
187
+ text: '4.7', // short value for pill, or a letter inside drop/circle/tile when no glyph
188
+ animate: true, // pop-in (off for re-renders)
189
+ delay: 0, // ms, for staggered animation
190
+ }).addTo(map);
191
+
192
+ m.setVariant('dot'); // switch at runtime
193
+ m.setMarkerOptions({ color: 'red' });
194
+ m.bindPopup('Hello', { className: 'juicy-info' }); // styled popup
195
+ ```
196
+
197
+ Built-in glyphs: `food`, `cafe`, `park`, `museum`, `hotel`, `place`. Bring your own with any SVG path, for example from Material Symbols or Lucide.
198
+
199
+ Custom variant:
200
+
201
+ ```js
202
+ registerMarkerVariant('badge', {
203
+ anchor: 'center', popup: -14,
204
+ render: (o, content) => `<div class="jm-m my-badge" style="background:var(--jm-c)">${content()}</div>`,
205
+ });
206
+ ```
207
+
208
+ **Theming:** set these CSS variables on any ancestor: `--jm-font`, `--jm-surface`, `--jm-text`, `--jm-muted`, `--jm-halo`, `--jm-glass`, `--jm-glass-border`, `--jm-radius`.
209
+
210
+ ## Routes
211
+
212
+ Styled route lines with start, stop and finish markers. The geometry comes from any router (OSRM, Valhalla, GraphHopper, your backend); `juicyRoute` only draws it.
213
+
214
+ | `variant` | Looks like | Good for |
215
+ |---|---|---|
216
+ | `classic` (default) | solid line with a darker casing | driving directions |
217
+ | `walk` | round dotted line | walking and cycling |
218
+ | `progress` | travelled part greyed out, direction arrows and a position puck on the rest | live navigation, deliveries, tracking |
219
+
220
+ ```js
221
+ import { juicyRoute } from 'leaflet-juicy/routes';
222
+
223
+ const route = juicyRoute(latlngs, {
224
+ variant: 'classic', // 'classic' | 'walk' | 'progress'
225
+ color: '#2f7cf6', // casing is derived automatically (or set casingColor)
226
+ stops: [[50.4529, 30.5143]],
227
+ label: '11 min', // plain-text bubble (escaped)
228
+ }).addTo(map);
229
+
230
+ map.fitBounds(route.getBounds());
231
+ route.setVariant('progress').setProgress(0.42); // live tracking: 0..1 of the route length
232
+ ```
233
+
234
+ Demo: [`demo/routes.html`](demo/routes.html). On dark maps, set `--jr-done` (the travelled part color) on any ancestor.
235
+
236
+ ---
237
+
238
+ ## Themes
239
+
240
+ A theme is just an array of style rules:
241
+
242
+ ```js
243
+ [
244
+ { featureType: 'water', elementType: 'geometry', stylers: [{ color: '#9dcbf3' }] },
245
+ { featureType: 'poi', elementType: 'labels', stylers: [{ visibility: 'off' }] },
246
+ { featureType: 'road.highway', elementType: 'geometry.fill', stylers: [{ color: '#ffd36e' }] },
247
+ ]
248
+ ```
249
+
250
+ ### Create your own in the theme builder
251
+
252
+ ![Theme builder](docs/img/theme-builder.jpg)
253
+
254
+ Open [`docs/theme-builder.html`](docs/theme-builder.html) (run `npm run dev`, then go to http://127.0.0.1:8787/docs/theme-builder.html):
255
+
256
+ 1. Start from **Juicy** or **Juicy Dark**.
257
+ 2. Adjust colors with the pickers; the map re-renders live.
258
+ 3. Optionally add raw rules on top, for example to hide POI labels.
259
+ 4. Click **Download .json**, or copy it from **JSON / код**.
260
+
261
+ You can also **import** an existing theme file, or a bare `styles` array from an old project, and keep editing it.
262
+
263
+ For a quicker tweak without leaving the map, the [demo](demo/) has a built-in theme editor: open the layer switcher (bottom left) and click **Custom**. Choose a light or dark base, recolor the palette, adjust saturation and brightness, and toggle what's shown (places, transit, buildings, labels). Changes apply live. **Save** keeps the theme in the browser, and **JSON** opens it in the config editor so you can copy or download it.
264
+
265
+ The exported file looks like this:
266
+
267
+ ```json
268
+ { "name": "brand", "font": "noto", "palette": { "water": "#7fc4f0", "...": "..." }, "styles": [ ... ] }
269
+ ```
270
+
271
+ ### Plug it in
272
+
273
+ ```js
274
+ // 1. by URL: fetched once and cached
275
+ juicyBasemap({ theme: '/themes/brand.json' });
276
+
277
+ // 2. bundled and registered under a name
278
+ import brand from './themes/brand.json';
279
+ import { registerTheme } from 'leaflet-juicy';
280
+ registerTheme('brand', brand);
281
+ juicyBasemap({ theme: 'brand' });
282
+
283
+ // 3. in code, from a palette (missing keys fall back to Juicy)
284
+ import { themeFromPalette } from 'leaflet-juicy';
285
+ juicyBasemap({ theme: themeFromPalette({ water: '#7fc4f0', green: '#b5e3a8' }) });
286
+
287
+ // 4. one-off overrides on top of any theme
288
+ juicyBasemap({ theme: 'juicy-dark', styles: [{ featureType: 'poi', stylers: [{ visibility: 'off' }] }] });
289
+ ```
290
+
291
+ ### Supported rule syntax
292
+
293
+ | | Supported |
294
+ |---|---|
295
+ | **featureType** | `all`, `administrative` (`.country`, `.province`, `.locality`, `.neighborhood`), `landscape` (`.man_made`, `.natural`, `.natural.landcover`, `.natural.terrain`), `poi` (`.park`, `.medical`, `.school`, `.sports_complex`, `.place_of_worship`), `road` (`.highway`, `.highway.controlled_access`, `.arterial`, `.local`), `transit` (`.line`, `.station`, `.station.airport`), `water` |
296
+ | **elementType** | `all`, `geometry` (`.fill`, `.stroke`), `labels` (`.icon`, `.text`, `.text.fill`, `.text.stroke`) |
297
+ | **stylers** | `color`, `visibility` (`on` / `off` / `simplified`), `hue`, `saturation`, `lightness`, `gamma`, `invert_lightness`, `weight` |
298
+
299
+ Rules apply in order, and later rules win. Rules for categories the tiles don't distinguish (for example `poi.business`, `transit.station.bus`) are accepted but have no effect. Icons are raster sprites, so color stylers don't affect them; only `visibility` does.
300
+
301
+ ---
302
+
303
+ ## Migrating from the Google Maps JavaScript API
304
+
305
+ The `compat` module mirrors the most-used classes. In most code the change is one line:
306
+
307
+ ```diff
308
+ - <script src="https://maps.googleapis.com/maps/api/js?key=...&callback=initMap"></script>
309
+ + <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
310
+ + <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
311
+ + <link rel="stylesheet" href="https://unpkg.com/leaflet-juicy/src/juicy.css">
312
+ ```
313
+
314
+ ```js
315
+ import { maps } from 'leaflet-juicy/compat';
316
+ const juicy = { maps }; // then replace `google.maps` → `juicy.maps`
317
+
318
+ const map = new juicy.maps.Map(document.getElementById('map'), {
319
+ center: { lat: 50.4501, lng: 30.5234 },
320
+ zoom: 13,
321
+ styles: myExistingStyles, // your old styles array works as-is
322
+ });
323
+
324
+ const marker = new juicy.maps.Marker({ position: { lat: 50.45, lng: 30.52 }, map, title: 'Hi', label: 'A' });
325
+ const info = new juicy.maps.InfoWindow({ content: '<b>Hello</b>' });
326
+ marker.addListener('click', () => info.open({ map, anchor: marker }));
327
+ ```
328
+
329
+ Full example: [`examples/migration.html`](examples/migration.html).
330
+
331
+ | Class / API | Status |
332
+ |---|---|
333
+ | `Map`: `center`, `zoom`, `minZoom`, `maxZoom`, `styles`, `mapTypeId`, `gestureHandling`, `disableDefaultUI`, `zoomControl`, `restriction`, `backgroundColor`; `setCenter`, `panTo`, `panBy`, `fitBounds`, `getBounds`, `setOptions`, `controls[...]`; events `click`, `idle`, `zoom_changed`, `bounds_changed`, `drag*` | ✅ |
334
+ | `Marker`: `position`, `map`, `title`, `label`, `icon` (URL, `{ url, scaledSize, anchor }`, or Juicy `{ variant, color, glyph }`), `draggable`, `zIndex`, `opacity`, `visible` | ✅ |
335
+ | `marker.AdvancedMarkerElement`, `marker.PinElement` | ✅ |
336
+ | `InfoWindow`: `open(map, anchor)` / `open({ map, anchor })`, `setContent`, `close`, events | ✅ |
337
+ | `Polyline`, `Polygon`, `Circle`, `Rectangle` | ✅ |
338
+ | `LatLng`, `LatLngBounds`, `event.*`, `MapTypeId`, `ControlPosition`, `importLibrary('maps' \| 'marker' \| 'core')` | ✅ |
339
+ | `mapTypeId`: `roadmap`, `satellite`, `hybrid` (`terrain` falls back to roadmap) | ✅ |
340
+ | Tilt / heading, Street View, Geocoder, Directions, Places, Data layer | ❌ use dedicated services or Leaflet plugins |
341
+ | `mapId` / cloud-based styling | ❌ export the style as JSON and pass it as `styles` |
342
+
343
+ Anything not covered is still reachable through `.leaflet`, for example `map.leaflet`, `marker.leaflet` or `info.leaflet`.
344
+
345
+ ---
346
+
347
+ ## Security
348
+
349
+ - **Escaped by default:** marker `label` and `text`, glyph paths, and the compat `Marker` title and label.
350
+ - **Validated:** marker and `PinElement` colors must be real CSS colors, so values like `red;background:url(…)` are rejected. Icon URLs must be `http(s)`, relative or `data:image/…`. Theme and variant names are looked up as own keys only.
351
+ - **Your responsibility (HTML by design):** `InfoWindow` content, `bindPopup()` content, `glyphHtml` and custom `registerMarkerVariant` renderers are inserted as HTML. Sanitize user-supplied strings first, for example with [DOMPurify](https://github.com/cure53/DOMPurify).
352
+ - **Supply chain:** the package has zero runtime dependencies and no install scripts. The lazy CDN loader pins exact versions and uses Subresource Integrity, so a tampered file is refused. To avoid third-party script hosts entirely, use `setMaplibreLoader()` with your bundle.
353
+ - **CSP:** with the default loader, allow `script-src https://unpkg.com` and `style-src https://unpkg.com`. With a bundled loader, nothing extra is needed for scripts. Vector maps also need `worker-src blob:` and `connect-src` for your tile, style and glyph hosts (by default `https://tiles.openfreemap.org` and `https://fonts.openmaptiles.org`).
354
+ - **Privacy:** tiles, glyphs and imagery are requested from third-party hosts (OpenFreeMap, OpenMapTiles fonts, Esri for satellite), which see visitors' IP addresses. Self-host tiles and glyphs (`styleUrl`, `font.glyphs`) if that matters for your users.
355
+ - **Theme files:** themes only produce map paint values; they cannot execute code. The theme builder still treats imported files as untrusted: only `#rrggbb` palette values are accepted.
356
+
357
+ ## Demo and development
358
+
359
+ ```bash
360
+ npm run dev # static server at http://127.0.0.1:8787
361
+ npm run build # minified files in build/ (also runs before npm publish)
362
+ ```
363
+
364
+ - `demo/`: full demo with marker styles, themes, fonts, search and filters.
365
+ - `demo/routes.html`: route styles.
366
+ - `demo/modules/`: demo-only UI (search, directions, theme editor); not part of the package.
367
+ - `docs/theme-builder.html`: theme builder.
368
+ - `examples/migration.html`: migration example.
369
+
370
+ No build step is needed for development: the package ships plain ES modules from `src/`. `npm run build` also produces minified files in `build/` (not committed): `leaflet-juicy.js` (ES module), `leaflet-juicy.iife.js` (classic `<script>`, global `LJuicy`) and `leaflet-juicy.css`, each with a source map. Leaflet stays external and is expected as the global `L`.
371
+
372
+ ## Attribution and tiles
373
+
374
+ The default basemap uses OpenFreeMap tiles built from OpenStreetMap data. The required attribution (*OpenFreeMap © OpenMapTiles © OpenStreetMap*) is added to the map automatically; keep it visible. To self-host, point `styleUrl` at any OpenMapTiles-schema style.
375
+
376
+ ## License
377
+
378
+ MIT
@@ -0,0 +1,3 @@
1
+ /*! leaflet-juicy v0.0.1 | MIT */
2
+ .jm{background:none;border:0}.jm-anchor{position:absolute;left:0;top:0}.jm-bottom{transform:translate(-50%,-100%)}.jm-center{transform:translate(-50%,-50%)}.jm-m{position:relative;cursor:pointer;transform-origin:50% 100%;transition:transform .18s ease}.jm-center .jm-m{transform-origin:50% 50%}.jm-animate .jm-m{animation:jm-pop .45s cubic-bezier(.2,1.5,.4,1) var(--jm-d, 0ms) both}.jm-m:hover{transform:translateY(-2px) scale(1.08)}.jm-active .jm-m{transform:scale(1.2)}@keyframes jm-pop{0%{scale:0;opacity:0}to{scale:1;opacity:1}}@media(prefers-reduced-motion:reduce){.jm-m{transition:none}.jm-animate .jm-m{animation:none}}.jm-text{color:#fff;font:700 12px/1 var(--jm-font, system-ui, sans-serif);white-space:nowrap}.jm-drop{width:36px;height:48px;filter:drop-shadow(0 3px 4px rgba(0,0,0,.28))}.jm-drop .jm-shape{position:absolute;inset:0}.jm .jm-m .jm-shape{z-index:0}.jm .jm-m .jm-glyph,.jm .jm-m .jm-text,.jm .jm-pin-glyph{z-index:1}.jm-drop .jm-fill{fill:var(--jm-c)}.jm-drop .jm-glyph{position:absolute;left:9px;top:8px;width:18px;height:18px;fill:#fff}.jm-drop .jm-text.jm-glyph{left:0;right:0;top:12px;width:auto;height:auto;text-align:center}.jm-circle{width:32px;height:32px;border-radius:50%;background:var(--jm-c);border:2.5px solid #fff;box-shadow:0 2px 6px #0000004d;display:grid;place-items:center}.jm-circle svg{width:16px;height:16px;fill:#fff}.jm-poi{width:24px;height:24px;border-radius:50%;background:var(--jm-c);box-shadow:0 1px 3px #0000004d;display:grid;place-items:center}.jm-poi svg{width:14px;height:14px;fill:#fff}.jm-poi-label{position:absolute;left:30px;top:50%;transform:translateY(-50%);white-space:nowrap;font:600 12px var(--jm-font, system-ui, sans-serif);color:var(--jm-c);--h: var(--jm-halo, #fff);text-shadow:0 0 2px var(--h),0 0 2px var(--h),0 0 3px var(--h),0 0 3px var(--h)}.jm-pill{display:flex;align-items:center;height:30px;padding:0 12px 0 5px;margin-bottom:7px;border-radius:15px;background:var(--jm-surface, #fff);color:var(--jm-text, #1f1f1f);font:600 13px var(--jm-font, system-ui, sans-serif);white-space:nowrap;box-shadow:0 2px 8px #00000040}.jm-pill:after{content:"";position:absolute;left:50%;bottom:-5px;width:10px;height:10px;background:var(--jm-surface, #fff);transform:translate(-50%) rotate(45deg)}.jm-pill-ic{width:20px;height:20px;margin-right:6px;border-radius:50%;background:var(--jm-c);display:grid;place-items:center}.jm-pill-ic svg{width:12px;height:12px;fill:#fff}.jm-pill-more{max-width:0;overflow:hidden;color:var(--jm-muted, #5f6368);font-weight:500;transition:max-width .25s ease}.jm-pill:hover .jm-pill-more,.jm-active .jm-pill-more{max-width:220px}.jm-tile{width:34px;height:34px;margin-bottom:7px;border-radius:10px;background:var(--jm-c);border:2px solid #fff;box-shadow:0 3px 8px #0000004d;display:grid;place-items:center}.jm-tile:after{content:"";position:absolute;left:50%;bottom:-13px;transform:translate(-50%);border:6px solid transparent;border-top:7px solid #fff}.jm-tile svg{width:18px;height:18px;fill:#fff}.jm-dot{width:16px;height:16px;border-radius:50%;background:var(--jm-c);border:3px solid #fff;box-shadow:0 1px 4px #00000059}.jm-tip{position:absolute;left:50%;bottom:calc(100% + 6px);transform:translate(-50%);padding:4px 8px;border-radius:6px;background:var(--jm-surface, #fff);color:var(--jm-text, #1f1f1f);font:500 12px var(--jm-font, system-ui, sans-serif);white-space:nowrap;box-shadow:0 2px 6px #00000040;opacity:0;pointer-events:none;transition:opacity .15s}.jm-dot:hover .jm-tip,.jm-active .jm-tip{opacity:1}.jm-glass{width:42px;height:42px;border-radius:50%;background:var(--jm-glass, rgba(255,255,255,.55));border:1px solid var(--jm-glass-border, rgba(255,255,255,.85));box-shadow:0 4px 14px #0003;-webkit-backdrop-filter:blur(8px) saturate(1.6);backdrop-filter:blur(8px) saturate(1.6);display:grid;place-items:center}.jm-glass svg{width:22px;height:22px;fill:var(--jm-c)}.jm-glass .jm-text{color:var(--jm-c);font-size:14px}.juicy-info .leaflet-popup-content-wrapper{padding:0;border-radius:var(--jm-radius, 12px);overflow:hidden;background:var(--jm-surface, #fff);color:var(--jm-text, #1f1f1f);box-shadow:0 8px 28px #3c404347}.juicy-info .leaflet-popup-content{margin:14px 16px;font:14px/1.45 var(--jm-font, system-ui, sans-serif)}.juicy-info .leaflet-popup-tip{background:var(--jm-surface, #fff);box-shadow:none}.juicy-info a.leaflet-popup-close-button{top:8px;right:8px;width:26px;height:26px;border-radius:50%;background:#00000059;color:#fff;font:17px/26px sans-serif;text-align:center}.juicy-info a.leaflet-popup-close-button:hover{background:#0000008c;color:#fff}.leaflet-control-zoom.leaflet-bar{border:0;border-radius:8px;overflow:hidden;box-shadow:0 2px 6px #3c404326,0 1px 2px #3c40434d}.leaflet-control-zoom.leaflet-bar a{width:40px;height:40px;line-height:40px;font-size:20px;font-weight:400;background:var(--jm-surface, #fff);color:var(--jm-muted, #5f6368);border-bottom-color:var(--jm-line, #e3e3e3)}.leaflet-control-zoom.leaflet-bar a{transition:background-color .18s ease,color .18s ease}.leaflet-control-zoom.leaflet-bar a:hover{color:var(--jm-text, #1f1f1f);background:color-mix(in srgb,var(--jm-text, #000) 5%,var(--jm-surface, #fff))}.leaflet-control-attribution{font:10px var(--jm-font, system-ui, sans-serif);border-radius:6px 0 0}.jm-pin .jm-pin-glyph{position:absolute;z-index:1;left:0;right:0;top:22%;display:grid;place-items:center;font:700 13px/1 var(--jm-font, system-ui, sans-serif)}.jm-pin .jm-pin-dot{width:30%;aspect-ratio:1;border-radius:50%;background:currentColor;display:block;min-width:8px}.jm-anchor img{display:block}.jr-icon{background:none;border:0}.jr-icon>div{position:absolute;transform:translate(-50%,-50%)}.jr-start{width:16px;height:16px;border-radius:50%;background:#fff;border:4px solid var(--jr-c);box-shadow:0 1px 4px #00000059;box-sizing:border-box}.jr-stop{width:12px;height:12px;border-radius:50%;background:#fff;border:3px solid #5f6368;box-shadow:0 1px 3px #0000004d;box-sizing:border-box}.jr-dots{filter:drop-shadow(0 1px 1px rgba(0,0,0,.25))}.jr-done{stroke:var(--jr-done, #a8adb5)}.jr-puck{width:22px;height:22px;border-radius:50%;background:var(--jr-c);border:3px solid #fff;box-sizing:border-box;box-shadow:0 0 0 7px color-mix(in srgb,var(--jr-c) 22%,transparent),0 2px 6px #00000059;display:grid;place-items:center}.jr-puck svg{width:12px;height:12px;fill:#fff;transform:rotate(var(--rot, 0deg))}.jr-arrow svg{display:block;width:14px;height:14px;fill:#fff;transform:rotate(var(--rot));filter:drop-shadow(0 0 1px rgba(0,0,0,.45))}.leaflet-tooltip.jr-label{background:var(--jm-surface, #fff);color:var(--jm-text, #1f1f1f);border:0;border-radius:10px;box-shadow:0 2px 6px #3c404340;font:600 12.5px var(--jm-font, system-ui, sans-serif);padding:4px 8px}.leaflet-tooltip.jr-label:before{display:none}.jr-draw{stroke-dasharray:var(--jr-len);stroke-dashoffset:var(--jr-len);animation:jr-draw 1.4s ease-out forwards}@keyframes jr-draw{to{stroke-dashoffset:0}}@media(prefers-reduced-motion:reduce){.jr-draw{animation:none;stroke-dashoffset:0}}
3
+ /*# sourceMappingURL=leaflet-juicy.css.map */
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/markers/juicy-markers.css", "../src/ui/juicy-ui.css", "../src/routes/juicy-route.css"],
4
+ "sourcesContent": ["/*\n * juicy-markers\n * Theme via CSS variables (set on any ancestor, e.g. body):\n * --jm-font, --jm-surface, --jm-text, --jm-muted, --jm-halo, --jm-glass, --jm-glass-border\n * Marker color comes from the `color` option (--jm-c).\n */\n\n/* ---------- shared: zero-size Leaflet icon, CSS does the anchoring ---------- */\n.jm { background: none; border: 0; }\n.jm-anchor { position: absolute; left: 0; top: 0; }\n.jm-bottom { transform: translate(-50%, -100%); }\n.jm-center { transform: translate(-50%, -50%); }\n.jm-m { position: relative; cursor: pointer; transform-origin: 50% 100%; transition: transform .18s ease; }\n.jm-center .jm-m { transform-origin: 50% 50%; }\n.jm-animate .jm-m { animation: jm-pop .45s cubic-bezier(.2, 1.5, .4, 1) var(--jm-d, 0ms) both; }\n.jm-m:hover { transform: translateY(-2px) scale(1.08); }\n.jm-active .jm-m { transform: scale(1.2); }\n/* `scale` (not `transform`) so the finished animation doesn't block hover/active transforms */\n@keyframes jm-pop { from { scale: 0; opacity: 0; } to { scale: 1; opacity: 1; } }\n@media (prefers-reduced-motion: reduce) {\n .jm-m { transition: none; }\n .jm-animate .jm-m { animation: none; }\n}\n\n/* text in place of a glyph (`text` option without `glyph`) */\n.jm-text { color: #fff; font: 700 12px/1 var(--jm-font, system-ui, sans-serif); white-space: nowrap; }\n\n/* ---------- drop ---------- */\n.jm-drop { width: 36px; height: 48px; filter: drop-shadow(0 3px 4px rgba(0,0,0,.28)); }\n.jm-drop .jm-shape { position: absolute; inset: 0; }\n/* Leaflet gives svg in panes z-index:200 \u2014 keep the shape under the glyph/text */\n.jm .jm-m .jm-shape { z-index: 0; }\n.jm .jm-m .jm-glyph, .jm .jm-m .jm-text, .jm .jm-pin-glyph { z-index: 1; }\n.jm-drop .jm-fill { fill: var(--jm-c); }\n.jm-drop .jm-glyph { position: absolute; left: 9px; top: 8px; width: 18px; height: 18px; fill: #fff; }\n.jm-drop .jm-text.jm-glyph { left: 0; right: 0; top: 12px; width: auto; height: auto; text-align: center; }\n\n/* ---------- circle ---------- */\n.jm-circle { width: 32px; height: 32px; border-radius: 50%; background: var(--jm-c); border: 2.5px solid #fff; box-shadow: 0 2px 6px rgba(0,0,0,.3); display: grid; place-items: center; }\n.jm-circle svg { width: 16px; height: 16px; fill: #fff; }\n\n/* ---------- poi ---------- */\n.jm-poi { width: 24px; height: 24px; border-radius: 50%; background: var(--jm-c); box-shadow: 0 1px 3px rgba(0,0,0,.3); display: grid; place-items: center; }\n.jm-poi svg { width: 14px; height: 14px; fill: #fff; }\n.jm-poi-label {\n position: absolute; left: 30px; top: 50%; transform: translateY(-50%);\n white-space: nowrap; font: 600 12px var(--jm-font, system-ui, sans-serif); color: var(--jm-c);\n --h: var(--jm-halo, #fff);\n text-shadow: 0 0 2px var(--h), 0 0 2px var(--h), 0 0 3px var(--h), 0 0 3px var(--h);\n}\n\n/* ---------- pill ---------- */\n.jm-pill {\n display: flex; align-items: center; height: 30px; padding: 0 12px 0 5px; margin-bottom: 7px;\n border-radius: 15px; background: var(--jm-surface, #fff); color: var(--jm-text, #1f1f1f);\n font: 600 13px var(--jm-font, system-ui, sans-serif); white-space: nowrap; box-shadow: 0 2px 8px rgba(0,0,0,.25);\n}\n.jm-pill::after { content: ''; position: absolute; left: 50%; bottom: -5px; width: 10px; height: 10px; background: var(--jm-surface, #fff); transform: translateX(-50%) rotate(45deg); }\n.jm-pill-ic { width: 20px; height: 20px; margin-right: 6px; border-radius: 50%; background: var(--jm-c); display: grid; place-items: center; }\n.jm-pill-ic svg { width: 12px; height: 12px; fill: #fff; }\n.jm-pill-more { max-width: 0; overflow: hidden; color: var(--jm-muted, #5f6368); font-weight: 500; transition: max-width .25s ease; }\n.jm-pill:hover .jm-pill-more, .jm-active .jm-pill-more { max-width: 220px; }\n\n/* ---------- tile ---------- */\n.jm-tile { width: 34px; height: 34px; margin-bottom: 7px; border-radius: 10px; background: var(--jm-c); border: 2px solid #fff; box-shadow: 0 3px 8px rgba(0,0,0,.3); display: grid; place-items: center; }\n.jm-tile::after { content: ''; position: absolute; left: 50%; bottom: -13px; transform: translateX(-50%); border: 6px solid transparent; border-top: 7px solid #fff; }\n.jm-tile svg { width: 18px; height: 18px; fill: #fff; }\n\n/* ---------- dot ---------- */\n.jm-dot { width: 16px; height: 16px; border-radius: 50%; background: var(--jm-c); border: 3px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,.35); }\n.jm-tip {\n position: absolute; left: 50%; bottom: calc(100% + 6px); transform: translateX(-50%);\n padding: 4px 8px; border-radius: 6px; background: var(--jm-surface, #fff); color: var(--jm-text, #1f1f1f);\n font: 500 12px var(--jm-font, system-ui, sans-serif); white-space: nowrap; box-shadow: 0 2px 6px rgba(0,0,0,.25);\n opacity: 0; pointer-events: none; transition: opacity .15s;\n}\n.jm-dot:hover .jm-tip, .jm-active .jm-tip { opacity: 1; }\n\n/* ---------- glass (backdrop-filter is costly: avoid with hundreds of markers) ---------- */\n.jm-glass {\n width: 42px; height: 42px; border-radius: 50%;\n background: var(--jm-glass, rgba(255,255,255,.55)); border: 1px solid var(--jm-glass-border, rgba(255,255,255,.85));\n box-shadow: 0 4px 14px rgba(0,0,0,.2);\n -webkit-backdrop-filter: blur(8px) saturate(1.6); backdrop-filter: blur(8px) saturate(1.6);\n display: grid; place-items: center;\n}\n.jm-glass svg { width: 22px; height: 22px; fill: var(--jm-c); }\n.jm-glass .jm-text { color: var(--jm-c); font-size: 14px; } /* a letter instead of a glyph */\n", "/*\n * juicy UI: info windows (popups), zoom control, attribution, pin element.\n * Theme variables (set on any ancestor):\n * --jm-font, --jm-surface, --jm-text, --jm-muted, --jm-line, --jm-accent, --jm-radius\n */\n\n/* ---------- info window ---------- */\n.juicy-info .leaflet-popup-content-wrapper {\n padding: 0; border-radius: var(--jm-radius, 12px); overflow: hidden;\n background: var(--jm-surface, #fff); color: var(--jm-text, #1f1f1f);\n box-shadow: 0 8px 28px rgba(60,64,67,.28);\n}\n.juicy-info .leaflet-popup-content { margin: 14px 16px; font: 14px/1.45 var(--jm-font, system-ui, sans-serif); }\n.juicy-info .leaflet-popup-tip { background: var(--jm-surface, #fff); box-shadow: none; }\n.juicy-info a.leaflet-popup-close-button {\n top: 8px; right: 8px; width: 26px; height: 26px; border-radius: 50%;\n background: rgba(0,0,0,.35); color: #fff; font: 17px/26px sans-serif; text-align: center;\n}\n.juicy-info a.leaflet-popup-close-button:hover { background: rgba(0,0,0,.55); color: #fff; }\n\n/* ---------- zoom control ---------- */\n.leaflet-control-zoom.leaflet-bar { border: 0; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 6px rgba(60,64,67,.15), 0 1px 2px rgba(60,64,67,.3); }\n.leaflet-control-zoom.leaflet-bar a {\n width: 40px; height: 40px; line-height: 40px; font-size: 20px; font-weight: 400;\n background: var(--jm-surface, #fff); color: var(--jm-muted, #5f6368); border-bottom-color: var(--jm-line, #e3e3e3);\n}\n.leaflet-control-zoom.leaflet-bar a { transition: background-color .18s ease, color .18s ease; }\n.leaflet-control-zoom.leaflet-bar a:hover { color: var(--jm-text, #1f1f1f); background: color-mix(in srgb, var(--jm-text, #000) 5%, var(--jm-surface, #fff)); }\n\n/* ---------- attribution ---------- */\n.leaflet-control-attribution { font: 10px var(--jm-font, system-ui, sans-serif); border-radius: 6px 0 0 0; }\n\n/* ---------- PinElement (compat) ---------- */\n.jm-pin .jm-pin-glyph { position: absolute; z-index: 1; left: 0; right: 0; top: 22%; display: grid; place-items: center; font: 700 13px/1 var(--jm-font, system-ui, sans-serif); }\n.jm-pin .jm-pin-dot { width: 30%; aspect-ratio: 1; border-radius: 50%; background: currentColor; display: block; min-width: 8px; }\n.jm-anchor img { display: block; }\n", "/*\n * juicy-route\n * Theme variables: --jr-done (travelled part), --jm-surface / --jm-text (label bubble), --jm-font\n */\n.jr-icon { background: none; border: 0; }\n.jr-icon > div { position: absolute; transform: translate(-50%, -50%); }\n\n/* start / stops */\n.jr-start { width: 16px; height: 16px; border-radius: 50%; background: #fff; border: 4px solid var(--jr-c); box-shadow: 0 1px 4px rgba(0,0,0,.35); box-sizing: border-box; }\n.jr-stop { width: 12px; height: 12px; border-radius: 50%; background: #fff; border: 3px solid #5f6368; box-shadow: 0 1px 3px rgba(0,0,0,.3); box-sizing: border-box; }\n\n/* walk */\n.jr-dots { filter: drop-shadow(0 1px 1px rgba(0,0,0,.25)); }\n\n/* progress */\n.jr-done { stroke: var(--jr-done, #a8adb5); }\n.jr-puck { width: 22px; height: 22px; border-radius: 50%; background: var(--jr-c); border: 3px solid #fff; box-sizing: border-box;\n box-shadow: 0 0 0 7px color-mix(in srgb, var(--jr-c) 22%, transparent), 0 2px 6px rgba(0,0,0,.35); display: grid; place-items: center; }\n.jr-puck svg { width: 12px; height: 12px; fill: #fff; transform: rotate(var(--rot, 0deg)); }\n.jr-arrow svg { display: block; width: 14px; height: 14px; fill: #fff; transform: rotate(var(--rot)); filter: drop-shadow(0 0 1px rgba(0,0,0,.45)); }\n\n/* label bubble */\n.leaflet-tooltip.jr-label { background: var(--jm-surface, #fff); color: var(--jm-text, #1f1f1f); border: 0; border-radius: 10px;\n box-shadow: 0 2px 6px rgba(60,64,67,.25); font: 600 12.5px var(--jm-font, system-ui, sans-serif); padding: 4px 8px; }\n.leaflet-tooltip.jr-label::before { display: none; }\n\n/* one-shot draw-in */\n.jr-draw { stroke-dasharray: var(--jr-len); stroke-dashoffset: var(--jr-len); animation: jr-draw 1.4s ease-out forwards; }\n@keyframes jr-draw { to { stroke-dashoffset: 0; } }\n@media (prefers-reduced-motion: reduce) { .jr-draw { animation: none; stroke-dashoffset: 0; } }\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,7 @@
1
+ /*! leaflet-juicy v0.0.1 | MIT */
2
+ var LJuicy=(()=>{var it=Object.defineProperty;var Ut=Object.getOwnPropertyDescriptor;var Vt=Object.getOwnPropertyNames;var Ft=Object.prototype.hasOwnProperty;var Zt=(e,t)=>{for(var s in t)it(e,s,{get:t[s],enumerable:!0})},Wt=(e,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Vt(t))!Ft.call(e,o)&&o!==s&&it(e,o,{get:()=>t[o],enumerable:!(i=Ut(t,o))||i.enumerable});return e};var Yt=e=>Wt(it({},"__esModule",{value:!0}),e);var ve={};Zt(ve,{CDN:()=>J,DEFAULT_STYLE_URL:()=>ft,FONTS:()=>pt,GLYPHS:()=>B,HYBRID_LABELS:()=>St,JUICY:()=>jt,JUICY_DARK:()=>Tt,JUICY_DARK_PALETTE:()=>Z,JUICY_PALETTE:()=>F,JuicyBasemap:()=>S,JuicyMarker:()=>O,JuicyRoute:()=>dt,MARKER_VARIANTS:()=>M,PALETTES:()=>W,PALETTE_FIELDS:()=>ne,ROUTE_VARIANTS:()=>Rt,SHOW_KEYS:()=>Ot,adjustRules:()=>lt,applyMapStyles:()=>H,buildStyle:()=>It,esc:()=>g,featureTypeOf:()=>nt,getThemeNames:()=>Ct,juicyBasemap:()=>zt,juicyMarker:()=>R,juicyRoute:()=>Nt,loadMaplibre:()=>$t,maps:()=>Lt,normalizeTheme:()=>V,own:()=>ot,parseColor:()=>N,registerMarkerVariant:()=>Kt,registerTheme:()=>ae,resolveTheme:()=>ct,safeColor:()=>y,setMaplibreLoader:()=>pe,setMarkerDefaults:()=>Gt,showRules:()=>at,themeFromPalette:()=>w});var B={food:"M11 9H9V2H7v7H5V2H3v7c0 2.12 1.66 3.84 3.75 3.97V22h2.5v-9.03C11.34 12.84 13 11.12 13 9V2h-2v7zm5-3v8h2.5v8H21V2c-2.76 0-5 2.24-5 4z",cafe:"M20 3H4v10c0 2.21 1.79 4 4 4h6c2.21 0 4-1.79 4-4v-3h2c1.11 0 2-.9 2-2V5c0-1.11-.89-2-2-2zm0 5h-2V5h2v3zM2 21h18v-2H2v2z",park:"M17 12h2L12 2 5.05 12H7l-3.9 6h6.92v4h3.96v-4H21z",museum:"M4 10v7h3v-7H4zm6 0v7h3v-7h-3zM2 22h19v-3H2v3zm14-12v7h3v-7h-3zm-4.5-9L2 6v2h19V6l-9.5-5z",hotel:"M7 13c1.66 0 3-1.34 3-3S8.66 7 7 7s-3 1.34-3 3 1.34 3 3 3zm12-6h-8v7H3V5H1v15h2v-3h18v3h2v-9c0-2.21-1.79-4-4-4z",place:"M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5a2.5 2.5 0 0 1 0-5 2.5 2.5 0 0 1 0 5z"},g=e=>String(e??"").replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t]),ot=(e,t)=>typeof t=="string"&&Object.prototype.hasOwnProperty.call(e,t);function y(e,t=null){return typeof e!="string"||e.length>64||/[;{}<>"'\\]|url\(|expression|\/\*/i.test(e)?t:typeof CSS<"u"&&CSS.supports?CSS.supports("color",e)?e:t:/^(#[0-9a-f]{3,8}|(rgb|hsl)a?\([\d\s.,%/+-]+\)|[a-z]+)$/i.test(e.trim())?e:t}function Jt(e,t="",s=null){if(s)return s;let i=ot(B,e)?B[e]:e||B.place;return`<svg class="${g(t)}" viewBox="0 0 24 24" aria-hidden="true"><path d="${g(i)}"/></svg>`}var M={glass:{label:"Glass",hint:"frosted, default",anchor:"center",popup:-22,render:(e,t)=>`<div class="jm-m jm-glass">${t()}</div>`},drop:{label:"Drop",hint:"classic pin with an icon",anchor:"bottom",popup:-48,render:(e,t)=>`<div class="jm-m jm-drop">
3
+ <svg class="jm-shape" viewBox="0 0 36 48" aria-hidden="true">
4
+ <path class="jm-fill" d="M18 0C8.06 0 0 8.06 0 18c0 13.5 18 30 18 30s18-16.5 18-30C36 8.06 27.94 0 18 0z"/>
5
+ <path d="M18 1.5C8.9 1.5 1.5 8.9 1.5 18" stroke="rgba(255,255,255,.35)" stroke-width="2" fill="none"/>
6
+ </svg>${t("jm-glyph")}</div>`},circle:{label:"Circle",hint:"compact, for dense maps",anchor:"center",popup:-18,render:(e,t)=>`<div class="jm-m jm-circle">${t()}</div>`},poi:{label:"POI",hint:"icon + name next to it",anchor:"center",popup:-14,render:(e,t)=>`<div class="jm-m jm-poi">${t()}${e.label?`<span class="jm-poi-label">${g(e.label)}</span>`:""}</div>`},pill:{label:"Pill",hint:"rating or price, name on hover",anchor:"bottom",popup:-40,render:(e,t,s)=>{let i=e.text!=null&&e.text!==""?`${g(e.text)}${e.label?`<span class="jm-pill-more">&nbsp;\xB7 ${g(e.label)}</span>`:""}`:g(e.label);return`<div class="jm-m jm-pill"><span class="jm-pill-ic">${s()}</span>${i}</div>`}},tile:{label:"Tile",hint:"rounded square with a tail",anchor:"bottom",popup:-46,render:(e,t)=>`<div class="jm-m jm-tile">${t()}</div>`},dot:{label:"Dot",hint:"minimal, for 1000+ points",anchor:"center",popup:-10,render:e=>`<div class="jm-m jm-dot">${e.label?`<span class="jm-tip">${g(e.label)}</span>`:""}</div>`}},P={variant:"glass",color:"#1a73e8",animate:!0};function Gt(e){Object.assign(P,e)}function Kt(e,t){M[e]={anchor:"center",popup:-16,label:e,hint:"",...t}}var O=L.Marker.extend({options:{variant:null,color:null,glyph:null,glyphHtml:null,label:"",text:"",animate:null,delay:0,riseOnHover:!0},initialize(e,t){L.Marker.prototype.initialize.call(this,e,t),!this.options.title&&this.options.label&&(this.options.title=this.options.label),this.options.icon=this._buildIcon(),this.on("popupopen",()=>this._el()?.classList.add("jm-active")),this.on("popupclose",()=>this._el()?.classList.remove("jm-active"))},setVariant(e){return this.options.variant=e,this._rerender()},setMarkerOptions(e){return L.Util.setOptions(this,e),this._rerender()},_rerender(){let e=this._el()?.classList.contains("jm-active");return this.options.animate=this.options.animate??!1,this.setIcon(this._buildIcon()),e&&this._el()?.classList.add("jm-active"),this},_el(){return this.getElement&&this.getElement()},_variant(){let e=this.options.variant||P.variant;return ot(M,e)?M[e]:(console.warn(`[juicy-markers] unknown variant "${e}", falling back to "glass"`),M.glass)},_buildIcon(){let e=this.options,t=this._variant(),s=y(e.color,null)||y(P.color,"#1a73e8"),i=e.animate??P.animate,o=n=>Jt(e.glyph,n,e.glyphHtml),r=n=>e.glyph||e.glyphHtml||!e.text?o(n):`<span class="jm-text ${n}">${g(e.text)}</span>`;return L.divIcon({className:"jm",html:`<div class="jm-anchor jm-${t.anchor}${i?" jm-animate":""}" style="--jm-c:${s};--jm-d:${Math.max(0,+e.delay||0)}ms">${t.render(e,r,o)}</div>`,iconSize:[0,0],iconAnchor:[0,0],popupAnchor:[0,t.popup]})}}),R=(e,t)=>new O(e,t);L.JuicyMarker=O;L.juicyMarker=R;var qt=[[/^background$/,"landscape"],[/^natural_earth$/,"landscape.natural.terrain"],[/^park/,"poi.park"],[/^landuse_residential$/,"landscape.man_made"],[/^landcover_/,"landscape.natural.landcover"],[/^landuse_(pitch|track)$/,"poi.sports_complex"],[/^landuse_cemetery$/,"poi.place_of_worship"],[/^landuse_hospital$/,"poi.medical"],[/^landuse_school$/,"poi.school"],[/^(water|waterway)/,"water"],[/^(aeroway|airport$)/,"transit.station.airport"],[/rail/,"transit.line"],[/^poi_transit$/,"transit.station"],[/^poi_/,"poi"],[/motorway/,"road.highway.controlled_access"],[/trunk_primary|shield/,"road.highway"],[/secondary_tertiary|^highway-name-major$/,"road.arterial"],[/^(road|bridge|tunnel)_|^highway-name/,"road.local"],[/^building/,"landscape.man_made"],[/^boundary_(2|disputed)$/,"administrative.country"],[/^boundary_/,"administrative.province"],[/^label_country/,"administrative.country"],[/^label_state/,"administrative.province"],[/^label_(city|town|village)/,"administrative.locality"],[/^label_other/,"administrative.neighborhood"]];function nt(e){for(let[t,s]of qt)if(t.test(e))return s;return null}function Qt(e){let t=e.id;switch(e.type){case"background":return[{el:"geometry.fill",color:"background-color"}];case"fill":return[{el:"geometry.fill",color:"fill-color",opacity:"fill-opacity"},{el:"geometry.stroke",color:"fill-outline-color"}];case"fill-extrusion":return[{el:"geometry.fill",color:"fill-extrusion-color"}];case"line":return[{el:t.endsWith("_casing")||t.startsWith("boundary")||t.endsWith("_outline")?"geometry.stroke":"geometry.fill",color:"line-color",width:"line-width"}];case"symbol":return[{el:"labels.text.fill",color:"text-color",opacity:"text-opacity"},{el:"labels.text.stroke",color:"text-halo-color",width:"text-halo-width"},{el:"labels.icon",opacity:"icon-opacity"}];case"raster":return[{el:"geometry.fill",opacity:"raster-opacity"}];default:return[]}}var vt=(e,t)=>!t||t==="all"||e===t||e!=null&&e.startsWith(t+"."),Xt={black:"#000000",white:"#ffffff",transparent:"rgba(0,0,0,0)"};function N(e){if(typeof e!="string")return null;let t=(Xt[e.trim().toLowerCase()]||e).trim(),s;if(s=t.match(/^#([0-9a-f]{3,8})$/i)){let i=s[1];if((i.length===3||i.length===4)&&(i=[...i].map(r=>r+r).join("")),i.length!==6&&i.length!==8)return null;let o=r=>parseInt(i.slice(r,r+2),16);return{r:o(0),g:o(2),b:o(4),a:i.length===8?o(6)/255:1}}if(s=t.match(/^rgba?\(([^)]+)\)$/i)){let[i,o,r,n=1]=s[1].split(/[\s,/]+/).filter(Boolean).map(parseFloat);return{r:i,g:o,b:r,a:n}}if(s=t.match(/^hsla?\(([^)]+)\)$/i)){let[i,o,r,n=1]=s[1].split(/[\s,/]+/).filter(Boolean).map(parseFloat);return{...kt(i,o/100,r/100),a:n}}return null}function xt({r:e,g:t,b:s}){e/=255,t/=255,s/=255;let i=Math.max(e,t,s),o=Math.min(e,t,s),r=(i+o)/2;if(i===o)return{h:0,s:0,l:r};let n=i-o,p=r>.5?n/(2-i-o):n/(i+o);return{h:(i===e?(t-s)/n+(t<s?6:0):i===t?(s-e)/n+2:(e-t)/n+4)*60,s:p,l:r}}function kt(e,t,s){let i=n=>(n+e/30)%12,o=t*Math.min(s,1-s),r=n=>s-o*Math.max(-1,Math.min(i(n)-3,9-i(n),1));return{r:Math.round(r(0)*255),g:Math.round(r(8)*255),b:Math.round(r(4)*255)}}var te=({r:e,g:t,b:s,a:i})=>`rgba(${Math.round(e)},${Math.round(t)},${Math.round(s)},${+i.toFixed(3)})`,ee=e=>Math.max(0,Math.min(1,e)),wt=(e,t)=>ee(t>=0?e+(1-e)*t/100:e+e*t/100);function se(e){return t=>{let{h:s,s:i,l:o}=xt(t);if(e.invert_lightness&&(o=1-o),e.hue!=null){let r=N(e.hue);r&&(s=xt(r).h)}return e.saturation!=null&&(i=wt(i,+e.saturation)),e.lightness!=null&&(o=wt(o,+e.lightness)),e.gamma!=null&&+e.gamma>0&&(o=Math.pow(o,+e.gamma)),{...kt(s,i,o),a:t.a}}}function rt(e,t){if(typeof e=="string"){let s=N(e);return s?te(t(s)):e}return Array.isArray(e)?e.map(s=>rt(s,t)):e&&typeof e=="object"&&Array.isArray(e.stops)?{...e,stops:e.stops.map(([s,i])=>[s,rt(i,t)])}:e}function ie(e,t){if(t){t.glyphs&&(e.glyphs=t.glyphs);for(let s of e.layers){let i=s.layout&&s.layout["text-font"];if(!Array.isArray(i))continue;let o=i.join(" "),r=/bold/i.test(o)?t.bold:/italic/i.test(o)?t.italic:t.regular;s.layout["text-font"]=[r||t.regular]}}}function oe(e,t){if(!t||t!=="local"&&!/^[a-z]{2,3}(-[a-z]{2,4})?$/i.test(t))return;let s=t==="local"?["get","name"]:["coalesce",["get",`name:${t}`],...t==="en"?[["get","name_en"]]:[],["get","name:latin"],["get","name"]];for(let i of e.layers){let o=i.layout&&i.layout["text-field"];o&&/"name/.test(JSON.stringify(o))&&(i.layout["text-field"]=s)}}function H(e,t=[],s={}){ie(e,s.font),oe(e,s.language);for(let i of e.layers){let o=nt(i.id),r=t.filter(l=>vt(o,l.featureType));if(!r.length)continue;let n=i.paint||(i.paint={}),p=new Set,c=Qt(i);for(let l of c)for(let m of r)if(vt(l.el,m.elementType))for(let u of m.stylers||[])u.visibility==="off"?p.add(l):u.visibility==="on"?p.delete(l):u.visibility==="simplified"&&(l.el==="labels.icon"||l.el==="geometry.stroke")&&p.add(l),u.color!=null&&l.color&&(n[l.color]=u.color,l.opacity&&i.type==="fill"&&(n[l.opacity]=1),l.el==="geometry.fill"&&delete n["fill-pattern"]),l.color&&n[l.color]!==void 0&&["hue","saturation","lightness","gamma","invert_lightness"].some(z=>u[z]!=null)&&(n[l.color]=rt(n[l.color],se(u))),u.weight!=null&&l.width&&(n[l.width]=+u.weight);re(i,c,p)}return e}function re(e,t,s){if(!s.size)return;let i=()=>e.layout={...e.layout||{},visibility:"none"},o=e.paint;if(e.type==="symbol"){let r=c=>t.some(l=>l.el===c&&s.has(l)),n=r("labels.text.fill"),p=r("labels.icon")||!(e.layout&&e.layout["icon-image"]);if(n&&p)return i();n&&(o["text-opacity"]=0),r("labels.text.stroke")&&(o["text-halo-width"]=0),r("labels.icon")&&(o["icon-opacity"]=0);return}for(let r of s)if(r.el==="geometry.stroke"&&e.type==="fill")o["fill-outline-color"]="rgba(0,0,0,0)";else return i()}var ne=[{group:"Base",fields:[["land","Land"],["built","Built-up areas"],["builtStroke","Building outlines"]]},{group:"Nature",fields:[["green","Parks & greenery"],["water","Water"],["waterLabel","Water labels"]]},{group:"Roads",fields:[["road","Streets"],["roadStroke","Street outlines"],["primary","Main roads"],["primaryStroke","Main road outlines"],["motorway","Motorways"],["motorwayStroke","Motorway outlines"],["rail","Railways"]]},{group:"Labels",fields:[["label","Text"],["labelHalo","Text halo"],["poiLabel","Place labels"],["countryLabel","Countries"]]},{group:"Places",fields:[["medical","Hospitals"],["school","Education"],["sports","Sports"],["cemetery","Cemeteries"],["airport","Airports"],["border","Borders"]]}],F={land:"#f3f1ec",built:"#ebe7e0",builtStroke:"#dcd7ce",green:"#c6e8c0",water:"#9dcbf3",waterLabel:"#3d76b5",road:"#ffffff",roadStroke:"#d9d4cb",primary:"#fff3c4",primaryStroke:"#ecd27e",motorway:"#ffd36e",motorwayStroke:"#e0a83a",rail:"#cfcac1",label:"#545454",labelHalo:"#ffffff",poiLabel:"#6b6b6b",countryLabel:"#3c3c3c",medical:"#f6dede",school:"#efe8d4",sports:"#bfe3c8",cemetery:"#d5e6cc",airport:"#e6e3ee",border:"#a596b8",dark:!1},Z={land:"#1b2029",built:"#242a35",builtStroke:"#2d3442",green:"#1d3329",water:"#0f2236",waterLabel:"#6f9bcc",road:"#363f4f",roadStroke:"#222833",primary:"#4d5769",primaryStroke:"#2a313e",motorway:"#8a6c3a",motorwayStroke:"#3f3320",rail:"#384050",label:"#b9c1ce",labelHalo:"#1b2029",poiLabel:"#8f98a8",countryLabel:"#dfe3ea",medical:"#2b262d",school:"#282828",sports:"#1c3329",cemetery:"#1f2e29",airport:"#272d3a",border:"#6b5f80",dark:!0},a=(e,t,...s)=>({...e&&{featureType:e},...t&&{elementType:t},stylers:s});function w(e){let t={...e?.dark?Z:F,...e};return[a(null,"labels.text.fill",{color:t.label}),a(null,"labels.text.stroke",{color:t.labelHalo},{weight:1.6}),a("landscape","geometry.fill",{color:t.land}),a("landscape.man_made","geometry.fill",{color:t.built}),a("landscape.man_made","geometry.stroke",{color:t.builtStroke}),a("landscape.natural.landcover","geometry.fill",{color:t.green}),a("landscape.natural.terrain",null,{visibility:"off"}),a("poi.park","geometry.fill",{color:t.green}),a("poi.park","geometry.stroke",{visibility:"off"}),a("poi.medical","geometry.fill",{color:t.medical}),a("poi.school","geometry.fill",{color:t.school}),a("poi.sports_complex","geometry.fill",{color:t.sports}),a("poi.place_of_worship","geometry.fill",{color:t.cemetery}),a("poi","labels.text.fill",{color:t.poiLabel}),a("transit.station.airport","geometry",{color:t.airport}),a("water","geometry",{color:t.water}),a("water","labels.text.fill",{color:t.waterLabel}),a("road","geometry.fill",{color:t.road}),a("road","geometry.stroke",{color:t.roadStroke}),a("road.highway","geometry.fill",{color:t.primary}),a("road.highway","geometry.stroke",{color:t.primaryStroke}),a("road.highway.controlled_access","geometry.fill",{color:t.motorway}),a("road.highway.controlled_access","geometry.stroke",{color:t.motorwayStroke}),a("transit.line","geometry",{color:t.rail}),a("administrative","geometry.stroke",{color:t.border}),a("administrative.country","labels.text.fill",{color:t.countryLabel}),...t.dark?[a("road.highway","labels",{visibility:"off"}),a("administrative.locality","labels.icon",{visibility:"off"})]:[]]}var jt=w(F),Tt=w(Z),W={juicy:F,"juicy-dark":Z},Mt={pois:a("poi","labels",{visibility:"off"}),transit:a("transit",null,{visibility:"off"}),buildings:a("landscape.man_made","geometry",{visibility:"off"}),roadLabels:a("road","labels",{visibility:"off"}),placeLabels:a("administrative","labels",{visibility:"off"}),waterLabels:a("water","labels",{visibility:"off"})},Ot=Object.keys(Mt);function at(e){return e?Ot.filter(t=>e[t]===!1).map(t=>Mt[t]):[]}function lt(e){if(!e)return[];let t=[];return e.hue&&t.push({hue:e.hue}),+e.saturation&&t.push({saturation:Math.max(-100,Math.min(100,+e.saturation))}),+e.lightness&&t.push({lightness:Math.max(-100,Math.min(100,+e.lightness))}),t.length?[{stylers:t}]:[]}var St=[a(null,"geometry",{visibility:"off"}),a("road.highway","geometry.fill",{visibility:"on"},{color:"#f3d27a"}),a(null,"labels.text.fill",{color:"#ffffff"}),a(null,"labels.text.stroke",{color:"#000000"},{weight:1.4}),a("poi","labels",{visibility:"off"}),a("road.highway","labels",{visibility:"off"})],U={juicy:jt,"juicy-dark":Tt,hybrid:St,none:[]};function V(e){if(!e)return[];if(Array.isArray(e))return e;if(Array.isArray(e.styles))return e.styles;if(e.palette)return w(e.palette);throw new Error("[juicy] theme must be an array of rules, { styles } or { palette }")}function ae(e,t){U[e]=V(t)}var Ct=()=>Object.keys(U),D=new Map;async function ct(e){if(typeof e!="string")return V(e);if(Object.prototype.hasOwnProperty.call(U,e))return U[e];if(/[/.]/.test(e))return D.has(e)||D.set(e,fetch(e).then(t=>{if(!t.ok)throw new Error(`[juicy] theme ${e}: HTTP ${t.status}`);return t.json()}).then(V).catch(t=>{throw D.delete(e),t})),D.get(e);throw new Error(`[juicy] unknown theme "${e}". Registered: ${Ct().join(", ")}`)}var ft="https://tiles.openfreemap.org/styles/liberty",pt={noto:{glyphs:"https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf",regular:"Noto Sans Regular",bold:"Noto Sans Bold",italic:"Noto Sans Italic"},"open-sans":{glyphs:"https://fonts.openmaptiles.org/{fontstack}/{range}.pbf",regular:"Open Sans Regular",bold:"Open Sans Bold",italic:"Open Sans Italic"}},ht=(e,t)=>`<a href="${e}" target="_blank" rel="noopener noreferrer">${t}</a>`,le=`${ht("https://openfreemap.org","OpenFreeMap")} &copy; ${ht("https://www.openmaptiles.org/","OpenMapTiles")} &copy; ${ht("https://www.openstreetmap.org/copyright","OpenStreetMap")}`,ce={version:8,sources:{},layers:[]},J={js:{url:"https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js",integrity:"sha384-SYKAG6cglRMN0RVvhNeBY0r3FYKNOJtznwA0v7B5Vp9tr31xAHsZC0DqkQ/pZDmj"},css:{url:"https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css",integrity:"sha384-MinO0mNliZ3vwppuPOUnGa+iq619pfMhLVUXfC4LHwSCvF9H+6P/KO4Q7qBOYV5V"},plugin:{url:"https://unpkg.com/@maplibre/maplibre-gl-leaflet@0.1.4/leaflet-maplibre-gl.js",integrity:"sha384-tXYNKOHx4T02jMP7YYCtBxPIv1B5gaA5mcVPBzqMp6d7VzWzxJgI2aWF/nJLrQdS"}},Et=({url:e,integrity:t})=>new Promise((s,i)=>{let o=Object.assign(document.createElement("script"),{src:e,async:!0,crossOrigin:"anonymous"});t&&(o.integrity=t),o.onload=s,o.onerror=()=>i(new Error(`[juicy] failed to load ${e}`)),document.head.appendChild(o)}),he=({url:e,integrity:t})=>{if([...document.querySelectorAll("link[rel=stylesheet]")].some(i=>i.href===e))return;let s=Object.assign(document.createElement("link"),{rel:"stylesheet",href:e,crossOrigin:"anonymous"});t&&(s.integrity=t),document.head.appendChild(s)},At=async()=>{window.maplibregl||(he(J.css),await Et(J.js)),L.maplibreGL||await Et(J.plugin)},ut=null;function pe(e){At=e,ut=null}function $t(){return window.maplibregl&&L.maplibreGL?Promise.resolve():ut||(ut=Promise.resolve().then(At).catch(e=>{throw ut=null,e}))}var Y=new Map;function ue(e){return Y.has(e)||Y.set(e,fetch(e).then(t=>{if(!t.ok)throw new Error(`[juicy] ${e}: HTTP ${t.status}`);return t.json()}).catch(t=>{throw Y.delete(e),t})),Y.get(e)}var fe=e=>(typeof e=="string"?Object.prototype.hasOwnProperty.call(pt,e)?pt[e]:null:e)||null;function de(e,{extrusions:t}){e.layers=e.layers.filter(i=>i.layout?.visibility!=="none"&&(t||i.type!=="fill-extrusion"));let s=new Set(e.layers.map(i=>i.source).filter(Boolean));for(let i of Object.keys(e.sources))s.has(i)||delete e.sources[i];return e}async function It({theme:e="juicy",palette:t=null,adjust:s=null,show:i=null,styles:o=[],font:r="noto",language:n=null,styleUrl:p=ft,extrusions:c=!1}={}){let l=t&&typeof e=="string"&&Object.prototype.hasOwnProperty.call(W,e),[m,u]=await Promise.all([ue(p),l?w({...W[e],...t}):ct(e)]),z=structuredClone(m),Dt=[...u,...at(i),...o||[],...lt(s)];return H(z,Dt,{font:fe(r),language:n}),de(z,{extrusions:c})}var S=L.Layer.extend({options:{theme:"juicy",palette:null,adjust:null,show:null,styles:[],font:"noto",language:null,styleUrl:ft,extrusions:!1,pane:"tilePane",attribution:le,maplibre:{}},initialize(e){L.setOptions(this,e),this._version=0},onAdd(e){$t().then(()=>{this._map!==e||this._gl||(this._gl=L.maplibreGL({style:ce,pane:this.options.pane,attributionControl:!1,pixelRatio:Math.min(window.devicePixelRatio||1,2),maxTileCacheSize:200,fadeDuration:150,refreshExpiredTiles:!1,...this.options.maplibre}).addTo(e),this.fire("rendererload"),this._render())}).catch(t=>this.fire("styleerror",{error:t}))},onRemove(e){this._gl&&e.removeLayer(this._gl),this._gl=null},update(e){return L.setOptions(this,e),this._render(),this},setTheme(e){return this.update({theme:e})},setMapStyles(e){return this.update({styles:e})},setFont(e){return this.update({font:e})},setLanguage(e){return this.update({language:e})},getMaplibreMap(){return this._gl?.getMaplibreMap()??null},async _render(){let e=this.getMaplibreMap();if(!e)return;let t=++this._version;try{let s=await It(this.options);if(t!==this._version||!this.getMaplibreMap())return;e.setStyle(s,{diff:!0}),this.fire("stylechange",{style:s})}catch(s){this.fire("styleerror",{error:s}),console.error(s)}}}),zt=e=>new S(e);L.JuicyBasemap=S;L.juicyBasemap=zt;var Bt="#2f7cf6";function ge(e,t=.35){let s=/^#([0-9a-f]{6})$/i.exec(e);if(!s)return"rgba(0,0,0,.35)";let i=parseInt(s[1],16),o=r=>Math.round((i>>r&255)*(1-t)).toString(16).padStart(2,"0");return`#${o(16)}${o(8)}${o(0)}`}function Pt(e,t){let s=Math.PI/180,i=Math.sin((t.lng-e.lng)*s)*Math.cos(t.lat*s),o=Math.cos(e.lat*s)*Math.sin(t.lat*s)-Math.sin(e.lat*s)*Math.cos(t.lat*s)*Math.cos((t.lng-e.lng)*s);return(Math.atan2(i,o)/s+360)%360}var me='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8.6 5.6 10 4.2l7.8 7.8-7.8 7.8-1.4-1.4 6.4-6.4z"/></svg>',ye='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2 4.5 20.3l.7.7L12 18l6.8 3 .7-.7z"/></svg>',Rt=["classic","walk","progress"],dt=L.FeatureGroup.extend({options:{variant:"classic",color:Bt,casingColor:null,weight:6,progress:0,arrows:!0,arrowSpacing:350,endpoints:!0,finishColor:"#e5484d",stops:[],label:"",animate:!0},initialize(e,t){L.FeatureGroup.prototype.initialize.call(this,[],t),L.setOptions(this,t),this._drawn=!1,this.setLatLngs(e)},setLatLngs(e){this._pts=(e||[]).map(t=>L.latLng(t)),this._cum=[0];for(let t=1;t<this._pts.length;t++)this._cum.push(this._cum[t-1]+this._pts[t-1].distanceTo(this._pts[t]));return this._render(),this},getLatLngs(){return this._pts.slice()},getDistance(){return this._cum[this._cum.length-1]||0},setVariant(e){return this.setRouteOptions({variant:e})},setProgress(e){return this.setRouteOptions({progress:e})},setRouteOptions(e){return L.setOptions(this,e),this._render(),this},onAdd(e){L.FeatureGroup.prototype.onAdd.call(this,e),this.options.animate&&!this._drawn&&this._drawIn(),this._drawn=!0},pointAt(e){let t=this._pts,s=this._cum;if(t.length<2)return{latlng:t[0],index:0,before:t.slice(),after:t.slice()};let i=this.getDistance()*Math.min(Math.max(e,0),1),o=s.findIndex(l=>l>=i);o<=0&&(o=1);let r=(i-s[o-1])/(s[o]-s[o-1]||1),n=t[o-1],p=t[o],c=L.latLng(n.lat+(p.lat-n.lat)*r,n.lng+(p.lng-n.lng)*r);return{latlng:c,index:o,before:[...t.slice(0,o),c],after:[c,...t.slice(o)]}},_render(){this.clearLayers();let e=this._pts;if(e.length<2)return;let t=this.options,s=y(t.color,Bt),i=y(t.casingColor,null)||ge(s),o=Math.max(1,+t.weight||6),r=(c,l)=>L.polyline(c,{lineCap:"round",lineJoin:"round",interactive:!1,...l}).addTo(this),n=Rt.includes(t.variant)?t.variant:"classic",p=this.pointAt(.5).latlng;if(n==="classic")r(e,{color:i,weight:o+3.5}),this._main=r(e,{color:s,weight:o});else if(n==="walk")this._main=null,r(e,{color:s,weight:o+1,dashArray:`0 ${Math.round(o*2)}`,className:"jr-dots"});else{let c=this.pointAt(t.progress||0);r(c.before,{className:"jr-done",color:"#a8adb5",weight:o}),r(c.after,{color:i,weight:o+3.5}),this._main=r(c.after,{color:s,weight:o}),t.arrows&&this._arrows(t.progress||0,+t.arrowSpacing||350);let l=this._pts[c.index],m=this._pts[c.index-1];this._icon(c.latlng,`<div class="jr-puck" style="--jr-c:${s};--rot:${Pt(m,l)}deg">${ye}</div>`,1e3),p=c.latlng}t.endpoints&&((n!=="progress"||!t.progress)&&this._icon(e[0],`<div class="jr-start" style="--jr-c:${s}"></div>`),(t.stops||[]).forEach(c=>this._icon(L.latLng(c),'<div class="jr-stop"></div>')),R(e[e.length-1],{glyph:"place",color:t.finishColor,animate:!1,interactive:!1,keyboard:!1}).addTo(this)),t.label&&L.tooltip({permanent:!0,direction:"top",className:"jr-label",offset:[0,n==="progress"?-14:-6]}).setLatLng(p).setContent(g(t.label)).addTo(this)},_icon(e,t,s=0){L.marker(e,{icon:L.divIcon({className:"jr-icon",html:t,iconSize:[0,0]}),interactive:!1,keyboard:!1,zIndexOffset:s}).addTo(this)},_arrows(e,t){let s=this.getDistance();if(!s)return;let i=t/s;for(let o=e+i;o<1-i/2;o+=i){let r=this.pointAt(o),n=Pt(this._pts[r.index-1],this._pts[r.index])-90;this._icon(r.latlng,`<div class="jr-arrow" style="--rot:${n}deg">${me}</div>`)}},_drawIn(){let e=this._main?.getElement?.();!e||typeof e.getTotalLength!="function"||(e.style.setProperty("--jr-len",Math.ceil(e.getTotalLength())),e.classList.add("jr-draw"),e.addEventListener("animationend",()=>e.classList.remove("jr-draw"),{once:!0}))}}),Nt=(e,t)=>new dt(e,t);L.JuicyRoute=dt;L.juicyRoute=Nt;var v=Symbol("listeners"),h={addListener(e,t,s){let i=e[v]||(e[v]={});return(i[t]||(i[t]=new Set)).add(s),{remove:()=>i[t]?.delete(s)}},addListenerOnce(e,t,s){let i=h.addListener(e,t,function(...o){i.remove(),s.apply(this,o)});return i},removeListener(e){e?.remove()},clearListeners(e,t){e[v]&&delete e[v][t]},clearInstanceListeners(e){e[v]={}},trigger(e,t,...s){e[v]?.[t]?.forEach(i=>i.apply(e,s))},addDomListener(e,t,s,i){return e.addEventListener(t,s,i),{remove:()=>e.removeEventListener(t,s,i)}}},C=class{addListener(t,s){return h.addListener(this,t,s)}_forward(t,s){for(let[i,o]of Object.entries(s))t.on(i,r=>h.trigger(this,o,j(r)))}},j=e=>({latLng:e.latlng?f(e.latlng):void 0,domEvent:e.originalEvent,pixel:e.containerPoint?{x:e.containerPoint.x,y:e.containerPoint.y}:void 0,stop:()=>e.originalEvent&&L.DomEvent.stop(e.originalEvent)}),b=class{constructor(t,s){t&&typeof t=="object"&&({lat:t,lng:s}=t),this._lat=+t,this._lng=+s}lat(){return this._lat}lng(){return this._lng}equals(t){return!!t&&Math.abs(t.lat()-this._lat)<1e-9&&Math.abs(t.lng()-this._lng)<1e-9}toJSON(){return{lat:this._lat,lng:this._lng}}toString(){return`(${this._lat}, ${this._lng})`}toUrlValue(t=6){return`${+this._lat.toFixed(t)},${+this._lng.toFixed(t)}`}},Ht=e=>typeof e=="function"?e():e,f=e=>new b(e.lat,e.lng),d=e=>e instanceof L.LatLng?e:Array.isArray(e)?L.latLng(e):L.latLng(Ht(e.lat),Ht(e.lng)),_=class{constructor(t,s){this._b=null,t&&"north"in t?this._b=L.latLngBounds([t.south,t.west],[t.north,t.east]):t&&(this._b=L.latLngBounds(d(t),d(s??t)))}extend(t){let s=d(t);return this._b?this._b.extend(s):this._b=L.latLngBounds(s,s),this}union(t){let s=x(t);return s&&(this._b?this._b.extend(s):this._b=L.latLngBounds(s.getSouthWest(),s.getNorthEast())),this}contains(t){return!!this._b&&this._b.contains(d(t))}intersects(t){let s=x(t);return!!(this._b&&s&&this._b.intersects(s))}isEmpty(){return!this._b}getCenter(){return this._b?f(this._b.getCenter()):new b(0,0)}getNorthEast(){return this._b?f(this._b.getNorthEast()):new b(-90,-180)}getSouthWest(){return this._b?f(this._b.getSouthWest()):new b(90,180)}toJSON(){let t=this._b;return t?{north:t.getNorth(),south:t.getSouth(),east:t.getEast(),west:t.getWest()}:null}toString(){return this._b?`(${this.getSouthWest()}, ${this.getNorthEast()})`:"((1, 180), (-1, -180))"}};function x(e){return e?e instanceof L.LatLngBounds?e:e instanceof _?e._b:"north"in e?L.latLngBounds([e.south,e.west],[e.north,e.east]):null:null}var yt={ROADMAP:"roadmap",SATELLITE:"satellite",HYBRID:"hybrid",TERRAIN:"terrain"},_t={TOP_LEFT:"topleft",TOP_CENTER:"topleft",TOP_RIGHT:"topright",LEFT_TOP:"topleft",LEFT_CENTER:"topleft",LEFT_BOTTOM:"bottomleft",RIGHT_TOP:"topright",RIGHT_CENTER:"topright",RIGHT_BOTTOM:"bottomright",BOTTOM_LEFT:"bottomleft",BOTTOM_CENTER:"bottomleft",BOTTOM_RIGHT:"bottomright",BLOCK_START_INLINE_START:"topleft",BLOCK_START_INLINE_END:"topright",BLOCK_END_INLINE_START:"bottomleft",BLOCK_END_INLINE_END:"bottomright"},be="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",bt=class extends Array{constructor(t,s){super(),this._map=t,this._pos=s}static get[Symbol.species](){return Array}push(...t){for(let s of t){let i=new(L.Control.extend({onAdd:()=>s}))({position:this._pos}).addTo(this._map);L.DomEvent.disableClickPropagation(s),s.__juicyControl=i,super.push(s)}return this.length}removeAt(t){let[s]=this.splice(t,1);return s?.__juicyControl?.remove(),s}clear(){for(;this.length;)this.removeAt(0)}getArray(){return[...this]}getLength(){return this.length}getAt(t){return this[t]}},E=class extends C{constructor(t,s={}){super(),this._div=typeof t=="string"?document.getElementById(t):t,this._opts={},this.leaflet=L.map(this._div,{zoomControl:!1,zoomSnap:.25,zoomDelta:.5,wheelPxPerZoomLevel:90}),this.leaflet.createPane("juicyRaster").style.zIndex=150,this.controls={};for(let o of new Set(Object.values(_t)))this.controls[o]=new bt(this.leaflet,o);this._forward(this.leaflet,{click:"click",dblclick:"dblclick",contextmenu:"rightclick",mousemove:"mousemove",mouseover:"mouseover",mouseout:"mouseout"});let i=this.leaflet;i.on("dragstart",()=>h.trigger(this,"dragstart")),i.on("drag",()=>h.trigger(this,"drag")),i.on("dragend",()=>h.trigger(this,"dragend")),i.on("move",()=>{h.trigger(this,"center_changed"),h.trigger(this,"bounds_changed")}),i.on("zoomend",()=>h.trigger(this,"zoom_changed")),i.on("moveend",()=>h.trigger(this,"idle")),i.on("resize",()=>h.trigger(this,"resize")),this.leaflet.whenReady(()=>h.trigger(this,"tilesloaded")),this.setOptions({mapTypeId:"roadmap",zoomControl:!0,...s})}setOptions(t={}){Object.assign(this._opts,t);let s=this.leaflet,i=this._opts;("center"in t||"zoom"in t)&&i.center!=null&&i.zoom!=null&&s.setView(d(i.center),i.zoom,{animate:!1}),"minZoom"in t&&s.setMinZoom(t.minZoom??0),"maxZoom"in t&&s.setMaxZoom(t.maxZoom??20),"restriction"in t&&s.setMaxBounds(t.restriction?x(t.restriction.latLngBounds):null),"backgroundColor"in t&&(this._div.style.background=t.backgroundColor),["gestureHandling","draggable","scrollwheel","disableDoubleClickZoom","keyboardShortcuts"].some(o=>o in t)&&this._applyGestures(),["disableDefaultUI","zoomControl","zoomControlOptions"].some(o=>o in t)&&this._applyControls(),["mapTypeId","styles","theme","font","language","styleUrl"].some(o=>o in t)&&this._applyBase()}_applyGestures(){let t=this._opts,s=this.leaflet,i=t.gestureHandling==="none",o=(r,n)=>n?r.enable():r.disable();o(s.dragging,!i&&t.draggable!==!1),o(s.scrollWheelZoom,!i&&t.scrollwheel!==!1&&t.gestureHandling!=="cooperative"),o(s.doubleClickZoom,!i&&!t.disableDoubleClickZoom),o(s.touchZoom,!i),o(s.boxZoom,!i),o(s.keyboard,!i&&t.keyboardShortcuts!==!1)}_applyControls(){let t=this._opts,s=t.zoomControl??!t.disableDefaultUI;this._zoomCtl?.remove(),this._zoomCtl=s?L.control.zoom({position:t.zoomControlOptions?.position??"bottomright"}).addTo(this.leaflet):null}_applyBase(){let t=this._opts,s=this.leaflet,i=t.mapTypeId||"roadmap";if(i==="satellite"||i==="hybrid"?(this._sat||(this._sat=L.tileLayer(be,{pane:"juicyRaster",maxZoom:19,attribution:"Imagery &copy; Esri"})),this._sat.addTo(s)):this._sat&&s.removeLayer(this._sat),i==="satellite"){this._vec&&s.removeLayer(this._vec);return}let r=i==="hybrid"?{theme:"hybrid",styles:[],font:t.font??"noto",language:t.language??null}:{theme:t.theme??"juicy",styles:t.styles??[],font:t.font??"noto",language:t.language??null,...t.styleUrl&&{styleUrl:t.styleUrl}};this._vec?this._vec.update(r):this._vec=new S(r),s.hasLayer(this._vec)||this._vec.addTo(s)}getDiv(){return this._div}getCenter(){return f(this.leaflet.getCenter())}setCenter(t){this._opts.center=t,this.leaflet.setView(d(t),this.leaflet.getZoom()??this._opts.zoom??3)}getZoom(){return this.leaflet.getZoom()}setZoom(t){this._opts.zoom=t,this.leaflet.setZoom(t)}panTo(t){this.leaflet.panTo(d(t))}panBy(t,s){this.leaflet.panBy([t,s])}getBounds(){let t=this.leaflet.getBounds();return new _(f(t.getSouthWest()),f(t.getNorthEast()))}fitBounds(t,s=0){let i=typeof s=="number"?{top:s,right:s,bottom:s,left:s}:{top:0,right:0,bottom:0,left:0,...s};this.leaflet.fitBounds(x(t),{paddingTopLeft:[i.left,i.top],paddingBottomRight:[i.right,i.bottom]})}panToBounds(t){this.leaflet.panInsideBounds(x(t))}getMapTypeId(){return this._opts.mapTypeId}setMapTypeId(t){this.setOptions({mapTypeId:t})}getHeading(){return 0}setHeading(){}getTilt(){return 0}setTilt(){}},A=class extends C{setMap(t){this._map!==t&&(this._map&&this.leaflet&&this._map.leaflet.removeLayer(this.leaflet),this._map=t||null,this._map&&this.leaflet&&this._visible!==!1&&this.leaflet.addTo(this._map.leaflet))}getMap(){return this._map||null}setVisible(t){this._visible=!!t,!(!this._map||!this.leaflet)&&(t?this.leaflet.addTo(this._map.leaflet):this._map.leaflet.removeLayer(this.leaflet))}getVisible(){return this._visible!==!1}};function gt(e){let t=String(e??"").trim();if(/^data:image\//i.test(t))return t;try{let s=new URL(t,location.href);return s.protocol==="http:"||s.protocol==="https:"?s.href:null}catch{return null}}function _e(e){if(typeof e=="string"){let t=gt(e);return t?L.divIcon({className:"jm",html:`<div class="jm-anchor jm-bottom"><img src="${g(t)}" alt="" draggable="false"></div>`,iconSize:[0,0],iconAnchor:[0,0]}):null}if(e&&e.url&&gt(e.url)){let t=e.scaledSize?.width,s=e.scaledSize?.height;return L.icon({iconUrl:gt(e.url),iconSize:t&&s?[t,s]:void 0,iconAnchor:e.anchor?[e.anchor.x,e.anchor.y]:t&&s?[t/2,s]:void 0})}return null}function Le(e){let t=e.icon&&typeof e.icon=="object"&&!e.icon.url?e.icon:{},s=typeof e.label=="string"?e.label:e.label?.text;return{variant:t.variant,color:t.color??t.fillColor,glyph:t.glyph,text:s??t.text??"",label:t.label??e.title??"",animate:t.animate??!1,title:e.title}}var K=class extends A{constructor(t={}){super(),this._opts={...t},this._visible=t.visible!==!1,this.leaflet=this._create(),t.map&&this.setMap(t.map)}_create(){let t=this._opts,s=d(t.position??{lat:0,lng:0}),i=_e(t.icon),o={draggable:!!t.draggable,opacity:t.opacity??1,zIndexOffset:t.zIndex??0,title:t.title??"",riseOnHover:!0},r=i?L.marker(s,{...o,icon:i}):new O(s,{...o,...Le(t)});return this._forward(r,{click:"click",dblclick:"dblclick",contextmenu:"rightclick",mouseover:"mouseover",mouseout:"mouseout",mousedown:"mousedown",mouseup:"mouseup"}),r.on("dragstart",n=>h.trigger(this,"dragstart",j({...n,latlng:r.getLatLng()}))),r.on("drag",n=>h.trigger(this,"drag",j(n))),r.on("dragend",n=>{h.trigger(this,"dragend",j({...n,latlng:r.getLatLng()})),h.trigger(this,"position_changed")}),r}_rebuild(){let t=this._map;this.setMap(null),this.leaflet=this._create(),t&&this.setMap(t)}setOptions(t){let s=["icon","label","title"].some(i=>i in t);Object.assign(this._opts,t),s&&this._rebuild(),"position"in t&&this.setPosition(t.position),"draggable"in t&&this.setDraggable(t.draggable),"opacity"in t&&this.setOpacity(t.opacity),"zIndex"in t&&this.setZIndex(t.zIndex),"visible"in t&&this.setVisible(t.visible),"map"in t&&this.setMap(t.map)}getPosition(){return f(this.leaflet.getLatLng())}setPosition(t){this._opts.position=t,this.leaflet.setLatLng(d(t)),h.trigger(this,"position_changed")}getTitle(){return this._opts.title}setTitle(t){this.setOptions({title:t})}getLabel(){return this._opts.label}setLabel(t){this.setOptions({label:t})}getIcon(){return this._opts.icon}setIcon(t){this.setOptions({icon:t})}getDraggable(){return!!this._opts.draggable}setDraggable(t){this._opts.draggable=t;let s=this.leaflet.dragging;s&&(t?s.enable():s.disable())}setOpacity(t){this._opts.opacity=t,this.leaflet.setOpacity(t??1)}getZIndex(){return this._opts.zIndex}setZIndex(t){this._opts.zIndex=t,this.leaflet.setZIndexOffset(t??0)}},q=class extends A{constructor(t={}){super();let s=document.createElement("div");s.className="jm-anchor jm-bottom",s.appendChild(t.content??new $().element),this.content=t.content??s.firstChild,this.leaflet=L.marker(d(t.position??{lat:0,lng:0}),{icon:L.divIcon({className:"jm",html:s,iconSize:[0,0],iconAnchor:[0,0]}),title:t.title??"",zIndexOffset:t.zIndex??0,draggable:!!t.gmpDraggable}),this._forward(this.leaflet,{click:"click"}),this.leaflet.on("click",i=>h.trigger(this,"gmp-click",j(i))),this.leaflet.on("dragend",i=>h.trigger(this,"dragend",j({...i,latlng:this.leaflet.getLatLng()}))),t.map&&this.setMap(t.map)}get map(){return this.getMap()}set map(t){this.setMap(t)}get position(){return this.leaflet.getLatLng()}set position(t){t&&this.leaflet.setLatLng(d(t))}},$=class{constructor({background:t="#ea4335",borderColor:s="rgba(0,0,0,.2)",glyphColor:i="#ffffff",glyph:o,scale:r=1}={}){let n=document.createElement("div");n.className="jm-m jm-drop jm-pin";let p=Math.min(Math.max(+r||1,.2),5);n.style.setProperty("--jm-c",y(t,"#ea4335")),n.style.width=`${36*p}px`,n.style.height=`${48*p}px`;let c="http://www.w3.org/2000/svg",l=document.createElementNS(c,"svg");l.setAttribute("class","jm-shape"),l.setAttribute("viewBox","0 0 36 48"),l.setAttribute("aria-hidden","true");let m=document.createElementNS(c,"path");m.setAttribute("class","jm-fill"),m.setAttribute("stroke",y(s,"rgba(0,0,0,.2)")),m.setAttribute("stroke-width","1.5"),m.setAttribute("d","M18 1C8.6 1 1 8.6 1 18c0 13 17 29 17 29s17-16 17-29C35 8.6 27.4 1 18 1z"),l.appendChild(m),n.appendChild(l);let u=document.createElement("div");u.className="jm-pin-glyph",u.style.color=y(i,"#ffffff"),o instanceof Node?u.appendChild(o):o!=null?u.textContent=o:u.appendChild(Object.assign(document.createElement("span"),{className:"jm-pin-dot"})),n.appendChild(u),this.element=n}},Q=class extends C{constructor(t={}){super(),this._opts={...t},this.leaflet=L.popup({className:"juicy-info",maxWidth:t.maxWidth??320,minWidth:t.minWidth??50,closeButton:!t.headerDisabled,autoPan:!t.disableAutoPan,autoPanPadding:[40,40],autoClose:!1}),this.leaflet.on("remove",()=>{h.trigger(this,"closeclick"),h.trigger(this,"close")}),t.content!=null&&this.setContent(t.content),t.position&&this.setPosition(t.position)}open(t,s){let i=t;if(t&&!(t instanceof E)&&("map"in t||"anchor"in t)&&({map:i,anchor:s}=t),i||(i=s?.getMap?.()),!!i){if(s?.leaflet){let r=s.leaflet.options.icon?.options?.popupAnchor?.[1]??-40;this.leaflet.options.offset=L.point(0,r+7),this.leaflet.setLatLng(s.leaflet.getLatLng())}else this.leaflet.options.offset=L.point(0,7);this.leaflet.addTo(i.leaflet),this._map=i,setTimeout(()=>h.trigger(this,"domready"))}}close(){this.leaflet.remove(),this._map=null}get isOpen(){return!!this._map&&this._map.leaflet.hasLayer(this.leaflet)}getContent(){return this._opts.content}setContent(t){this._opts.content=t,this.leaflet.setContent(t),h.trigger(this,"content_changed")}getPosition(){let t=this.leaflet.getLatLng();return t?f(t):void 0}setPosition(t){this.leaflet.setLatLng(d(t))}setOptions(t){Object.assign(this._opts,t),"content"in t&&this.setContent(t.content),"position"in t&&this.setPosition(t.position)}setZIndex(){}},I=e=>({color:e.strokeColor??"#1a73e8",opacity:e.strokeOpacity??1,weight:e.strokeWeight??3,fillColor:e.fillColor??e.strokeColor??"#1a73e8",fillOpacity:e.fillOpacity??.3,interactive:e.clickable??!0}),G=e=>Object.assign(e,{getArray:()=>e,getLength:()=>e.length,getAt:t=>e[t]}),k=e=>(e?.getArray?e.getArray():e||[]).map(d),T=class extends A{_init(t,s){this._opts={...s},this._visible=s.visible!==!1,this.leaflet=t,this._forward(t,{click:"click",dblclick:"dblclick",contextmenu:"rightclick",mouseover:"mouseover",mouseout:"mouseout"}),s.map&&this.setMap(s.map)}setOptions(t){Object.assign(this._opts,t),this.leaflet.setStyle(I(this._opts)),"map"in t&&this.setMap(t.map),"visible"in t&&this.setVisible(t.visible)}},X=class extends T{constructor(t={}){super(),this._init(L.polyline(k(t.path),{...I(t),fill:!1}),t)}getPath(){return G(this.leaflet.getLatLngs().map(f))}setPath(t){this.leaflet.setLatLngs(k(t))}},tt=class extends T{constructor(t={}){super();let s=t.paths??[],i=Array.isArray(s[0])||s[0]?.getArray?s.map(k):[k(s)];this._init(L.polygon(i,I(t)),t)}getPath(){return G(this.leaflet.getLatLngs()[0].map(f))}getPaths(){return G(this.leaflet.getLatLngs().map(t=>G(t.map(f))))}setPath(t){this.leaflet.setLatLngs([k(t)])}setPaths(t){this.leaflet.setLatLngs(t.map(k))}},et=class extends T{constructor(t={}){super(),this._init(L.circle(d(t.center??{lat:0,lng:0}),{...I(t),radius:t.radius??0}),t)}getCenter(){return f(this.leaflet.getLatLng())}setCenter(t){this.leaflet.setLatLng(d(t))}getRadius(){return this.leaflet.getRadius()}setRadius(t){this.leaflet.setRadius(t)}getBounds(){let t=this.leaflet.getBounds();return new _(f(t.getSouthWest()),f(t.getNorthEast()))}},st=class extends T{constructor(t={}){super(),this._init(L.rectangle(x(t.bounds)??[[0,0],[0,0]],I(t)),t)}getBounds(){let t=this.leaflet.getBounds();return new _(f(t.getSouthWest()),f(t.getNorthEast()))}setBounds(t){this.leaflet.setBounds(x(t))}},mt={core:{LatLng:b,LatLngBounds:_,event:h,MapTypeId:yt,ControlPosition:_t},maps:{Map:E,InfoWindow:Q,Polyline:X,Polygon:tt,Circle:et,Rectangle:st,LatLng:b,LatLngBounds:_,MapTypeId:yt},marker:{AdvancedMarkerElement:q,PinElement:$,Marker:K}},Lt={Map:E,Marker:K,InfoWindow:Q,LatLng:b,LatLngBounds:_,Polyline:X,Polygon:tt,Circle:et,Rectangle:st,event:h,MapTypeId:yt,ControlPosition:_t,marker:{AdvancedMarkerElement:q,PinElement:$},importLibrary:async e=>{if(!mt[e])throw new Error(`[juicy] library "${e}" is not supported (available: ${Object.keys(mt).join(", ")})`);return mt[e]}};L.juicy={...L.juicy||{},maps:Lt};return Yt(ve);})();
7
+ //# sourceMappingURL=leaflet-juicy.iife.js.map