diff options
| author | Ariel Costas Guerrero <ariel@costas.dev> | 2025-11-15 18:00:59 +0100 |
|---|---|---|
| committer | Ariel Costas Guerrero <ariel@costas.dev> | 2025-11-15 18:00:59 +0100 |
| commit | 4b9c57dc6547d0c9d105ac3767dcc90da758a25d (patch) | |
| tree | 5150d5494e7591df2fe6d83d42fc4642e9b0d1b1 | |
| parent | f349c491284c0cb007a97c9a11220cc00adbb64f (diff) | |
Refactor code structure for improved readability and maintainability
| -rw-r--r-- | src/frontend/app/components/StopMapSheet.css | 66 | ||||
| -rw-r--r-- | src/frontend/app/components/StopMapSheet.tsx | 353 | ||||
| -rw-r--r-- | src/frontend/app/components/Stops/ConsolidatedCirculationList.css | 31 | ||||
| -rw-r--r-- | src/frontend/app/maps/styleloader.ts | 7 | ||||
| -rw-r--r-- | src/frontend/app/root.css | 1 | ||||
| -rw-r--r-- | src/frontend/app/routes/stops-$id.css | 7 | ||||
| -rw-r--r-- | src/frontend/app/routes/stops-$id.tsx | 2 | ||||
| -rw-r--r-- | src/frontend/public/maps/styles/openfreemap-dark.json | 1 | ||||
| -rw-r--r-- | src/frontend/public/maps/styles/openfreemap-light.json (renamed from src/frontend/public/maps/styles/openfreemap-any.json) | 0 |
9 files changed, 337 insertions, 131 deletions
diff --git a/src/frontend/app/components/StopMapSheet.css b/src/frontend/app/components/StopMapSheet.css index 7a3b88c..5125ff0 100644 --- a/src/frontend/app/components/StopMapSheet.css +++ b/src/frontend/app/components/StopMapSheet.css @@ -6,10 +6,74 @@ border: 1px solid var(--border-color); margin-block-start: 0; flex-shrink: 0; + position: relative; } @media (max-width: 640px) { .stop-map-container { - height: 25vh; + height: 30vh; } } + +/* Floating controls */ +.map-floating-controls { + position: absolute; + left: 8px; + top: 8px; + display: flex; + gap: 8px; + z-index: 2; +} + +.center-btn { + appearance: none; + border: 1px solid rgba(0,0,0,0.15); + background: color-mix(in oklab, var(--background-color, #fff) 85%, transparent); + color: var(--text-primary, #111); + padding: 6px; + border-radius: 6px; + font-size: 12px; + line-height: 1; + box-shadow: 0 1px 2px rgba(0,0,0,0.15); + cursor: pointer; +} + +/* User location dot */ +.user-dot { + position: relative; + width: 22px; + height: 22px; +} + +.user-dot__core { + position: absolute; + left: 50%; + top: 50%; + width: 10px; + height: 10px; + margin-left: -5px; + margin-top: -5px; + background: #2a6df4; + border: 2px solid #fff; + border-radius: 50%; + box-shadow: 0 1px 2px rgba(0,0,0,0.3); +} + +.user-dot__pulse { + position: absolute; + left: 50%; + top: 50%; + width: 22px; + height: 22px; + margin-left: -11px; + margin-top: -11px; + border-radius: 50%; + background: rgba(42, 109, 244, 0.25); + animation: userPulse 1.8s ease-out infinite; +} + +@keyframes userPulse { + 0% { transform: scale(0.6); opacity: 0.8; } + 70% { transform: scale(1.2); opacity: 0.15; } + 100% { transform: scale(1.4); opacity: 0; } +} diff --git a/src/frontend/app/components/StopMapSheet.tsx b/src/frontend/app/components/StopMapSheet.tsx index 2dc85db..e87e8c8 100644 --- a/src/frontend/app/components/StopMapSheet.tsx +++ b/src/frontend/app/components/StopMapSheet.tsx @@ -1,6 +1,6 @@ import maplibregl from "maplibre-gl"; import React, { useEffect, useMemo, useRef, useState } from "react"; -import Map, { Marker, NavigationControl, type MapRef } from "react-map-gl/maplibre"; +import Map, { AttributionControl, Marker, type MapRef } from "react-map-gl/maplibre"; import { useApp } from "~/AppContext"; import { getLineColor } from "~/data/LineColors"; import type { RegionId } from "~/data/RegionConfig"; @@ -35,6 +35,67 @@ export const StopMap: React.FC<StopMapProps> = ({ const [styleSpec, setStyleSpec] = useState<any | null>(null); const mapRef = useRef<MapRef | null>(null); const hasFitBounds = useRef(false); + const [userPosition, setUserPosition] = useState<{ + latitude: number; + longitude: number; + accuracy?: number; + } | null>(null); + const geoWatchId = useRef<number | null>(null); + const [zoom, setZoom] = useState<number>(16); + const [moveTick, setMoveTick] = useState<number>(0); + + type Pt = { lat: number; lon: number }; + const haversineKm = (a: Pt, b: Pt) => { + const R = 6371; + const dLat = ((b.lat - a.lat) * Math.PI) / 180; + const dLon = ((b.lon - a.lon) * Math.PI) / 180; + const lat1 = (a.lat * Math.PI) / 180; + const lat2 = (b.lat * Math.PI) / 180; + const sinDLat = Math.sin(dLat / 2); + const sinDLon = Math.sin(dLon / 2); + const h = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon; + return 2 * R * Math.asin(Math.min(1, Math.sqrt(h))); + }; + const computeFocusPoints = (): Pt[] => { + const buses: Pt[] = []; + for (const c of busPositions) { + if (c.currentPosition) buses.push({ lat: c.currentPosition.latitude, lon: c.currentPosition.longitude }); + } + const stopPt = stop.latitude && stop.longitude ? { lat: stop.latitude, lon: stop.longitude } : null; + const userPt = userPosition ? { lat: userPosition.latitude, lon: userPosition.longitude } : null; + + if (buses.length === 0 && !stopPt && !userPt) return []; + + // Choose anchor for proximity: stop > user > average of buses + let anchor: Pt | null = stopPt || userPt || null; + if (!anchor && buses.length) { + let lat = 0, lon = 0; + for (const b of buses) { lat += b.lat; lon += b.lon; } + anchor = { lat: lat / buses.length, lon: lon / buses.length }; + } + + const nearBuses = buses + .map((p) => ({ p, d: anchor ? haversineKm(anchor, p) : 0 })) + .sort((a, b) => a.d - b.d) + .slice(0, 8) // take closest N + .filter((x) => x.d <= 8) // within 8km + .map((x) => x.p); + + const pts: Pt[] = []; + if (stopPt) pts.push(stopPt); + pts.push(...nearBuses); + if (userPt) { + // include user if not too far from anchor + const includeUser = anchor ? haversineKm(anchor, userPt) <= 10 : true; + if (includeUser) pts.push(userPt); + } + // Fallback: if no buses survived, at least return stop or user + if (pts.length === 0) { + if (stopPt) return [stopPt]; + if (userPt) return [userPt]; + } + return pts; + }; useEffect(() => { let mounted = true; @@ -48,6 +109,42 @@ export const StopMap: React.FC<StopMapProps> = ({ }; }, [theme]); + // Geolocation: request immediately without blocking UI; update when available. + useEffect(() => { + if (!("geolocation" in navigator)) return; + try { + navigator.geolocation.getCurrentPosition( + (pos) => { + setUserPosition({ + latitude: pos.coords.latitude, + longitude: pos.coords.longitude, + accuracy: pos.coords.accuracy, + }); + }, + () => {}, + { enableHighAccuracy: true, maximumAge: 15000, timeout: 5000 }, + ); + geoWatchId.current = navigator.geolocation.watchPosition( + (pos) => { + setUserPosition({ + latitude: pos.coords.latitude, + longitude: pos.coords.longitude, + accuracy: pos.coords.accuracy, + }); + }, + () => {}, + { enableHighAccuracy: true, maximumAge: 30000, timeout: 10000 }, + ); + } catch {} + return () => { + if (geoWatchId.current != null && "geolocation" in navigator) { + try { + navigator.geolocation.clearWatch(geoWatchId.current); + } catch {} + } + }; + }, []); + const center = useMemo(() => { if (stop.latitude && stop.longitude) { return { latitude: stop.latitude, longitude: stop.longitude }; @@ -69,18 +166,7 @@ export const StopMap: React.FC<StopMapProps> = ({ useEffect(() => { if (!styleSpec || !mapRef.current || hasFitBounds.current) return; - const points: { lat: number; lon: number }[] = []; - if (stop.latitude && stop.longitude) { - points.push({ lat: stop.latitude, lon: stop.longitude }); - } - for (const c of busPositions) { - if (c.currentPosition) { - points.push({ - lat: c.currentPosition.latitude, - lon: c.currentPosition.longitude, - }); - } - } + const points = computeFocusPoints(); if (points.length === 0) return; let minLat = points[0].lat, @@ -94,26 +180,57 @@ export const StopMap: React.FC<StopMapProps> = ({ if (p.lon > maxLon) maxLon = p.lon; } - // ~1km in degrees - const kmToDegLat = 1.0 / 111.32; // ≈0.008983 - const centerLat = (minLat + maxLat) / 2; - const kmToDegLon = kmToDegLat / Math.max(Math.cos((centerLat * Math.PI) / 180), 0.1); - const padLat = kmToDegLat; - const padLon = kmToDegLon; - - const sw = [minLon - padLon, minLat - padLat] as [number, number]; - const ne = [maxLon + padLon, maxLat + padLat] as [number, number]; + const sw = [minLon, minLat] as [number, number]; + const ne = [maxLon, maxLat] as [number, number]; const bounds = new maplibregl.LngLatBounds(sw, ne); + // Determine predominant bus quadrant relative to stop to bias padding. + const padding: number | { top: number; right: number; bottom: number; left: number } = 24; + + // If the diagonal is huge (likely outliers sneaked in), clamp via zoom fallback try { - mapRef.current.fitBounds(bounds, { - padding: 32, - duration: 700, - maxZoom: 17, - } as any); + if (points.length === 1) { + const only = points[0]; + mapRef.current.getMap().jumpTo({ center: [only.lon, only.lat], zoom: 16 }); + } else { + mapRef.current.fitBounds(bounds, { + padding: padding as any, + duration: 700, + maxZoom: 17, + } as any); + } hasFitBounds.current = true; } catch {} - }, [styleSpec, stop.latitude, stop.longitude, busPositions]); + }, [styleSpec, stop.latitude, stop.longitude, busPositions, userPosition]); + + const handleCenter = () => { + if (!mapRef.current) return; + const pts = computeFocusPoints(); + if (pts.length === 0) return; + + let minLat = pts[0].lat, maxLat = pts[0].lat, minLon = pts[0].lon, maxLon = pts[0].lon; + for (const p of pts) { + if (p.lat < minLat) minLat = p.lat; + if (p.lat > maxLat) maxLat = p.lat; + if (p.lon < minLon) minLon = p.lon; + if (p.lon > maxLon) maxLon = p.lon; + } + + const sw = [minLon, minLat] as [number, number]; + const ne = [maxLon, maxLat] as [number, number]; + const bounds = new maplibregl.LngLatBounds(sw, ne); + + const padding: number | { top: number; right: number; bottom: number; left: number } = 24; + + try { + if (pts.length === 1) { + const only = pts[0]; + mapRef.current.getMap().easeTo({ center: [only.lon, only.lat], zoom: 16, duration: 450 }); + } else { + mapRef.current.fitBounds(bounds, { padding: padding as any, duration: 500, maxZoom: 17 } as any); + } + } catch {} + }; return ( <div className="stop-map-container"> @@ -129,90 +246,130 @@ export const StopMap: React.FC<StopMapProps> = ({ mapStyle={styleSpec} attributionControl={false} ref={mapRef} + onMove={(e) => { + setZoom(e.viewState.zoom); + setMoveTick((t) => (t + 1) % 1000000); + }} > - <NavigationControl position="top-left" /> + {/* Compact attribution (closed by default) */} + <AttributionControl position="bottom-left" compact /> {/* Stop marker (center) */} {stop.latitude && stop.longitude && ( - <Marker - longitude={stop.longitude} - latitude={stop.latitude} - anchor="bottom" - > - <div - style={{ - width: 14, - height: 14, - background: "#1976d2", - border: "2px solid white", - borderRadius: "5%", - boxShadow: "0 0 0 2px rgba(0,0,0,0.2)", - }} - title={`Stop ${stop.stopId}`} - /> + <Marker longitude={stop.longitude} latitude={stop.latitude} anchor="bottom"> + <div title={`Stop ${stop.stopId}`}> + <svg width="28" height="36" viewBox="0 0 28 36"> + <defs> + <filter id="drop" x="-20%" y="-20%" width="140%" height="140%"> + <feDropShadow dx="0" dy="1" stdDeviation="1" flood-opacity="0.35" /> + </filter> + </defs> + <path d="M14 0C6.82 0 1 5.82 1 13c0 8.5 11 23 13 23s13-14.5 13-23C27 5.82 21.18 0 14 0z" fill="#1976d2" stroke="#fff" strokeWidth="2" filter="url(#drop)" /> + <circle cx="14" cy="13" r="5" fill="#fff" /> + <circle cx="14" cy="13" r="3" fill="#1976d2" /> + </svg> + </div> </Marker> )} - {/* Bus markers with heading */} - {busPositions.map((c, idx) => { - const p = c.currentPosition!; - const lineColor = getLineColor(region, c.line); - return ( - <Marker - key={idx} - longitude={p.longitude} - latitude={p.latitude} - anchor="center" - > - <div - style={{ - display: "flex", - flexDirection: "column", - alignItems: "center", - gap: 2, - transform: `rotate(${p.orientationDegrees}deg)`, - transformOrigin: "center center", - }} - > - {/* Line number above */} + {/* User position marker (if available) */} + {userPosition && ( + <Marker longitude={userPosition.longitude} latitude={userPosition.latitude} anchor="center"> + <div className="user-dot" title="Your location"> + <div className="user-dot__pulse" /> + <div className="user-dot__core" /> + </div> + </Marker> + )} + + {/* Bus markers with heading and dynamic label spacing */} + {(() => { + const map = mapRef.current?.getMap(); + const baseGap = 6; + const thresholdPx = 22; + const gaps: number[] = new Array(busPositions.length).fill(baseGap); + if (map && zoom >= 14.5 && busPositions.length > 1) { + const pts = busPositions.map((c) => + c.currentPosition ? map.project([c.currentPosition.longitude, c.currentPosition.latitude]) : null, + ); + for (let i = 0; i < pts.length; i++) { + const pi = pts[i]; + if (!pi) continue; + let close = 0; + for (let j = 0; j < pts.length; j++) { + if (i === j) continue; + const pj = pts[j]; + if (!pj) continue; + const dx = pi.x - pj.x; + const dy = pi.y - pj.y; + if (dx * dx + dy * dy <= thresholdPx * thresholdPx) close++; + } + gaps[i] = baseGap + Math.min(3, close) * 10; + } + } + + return busPositions.map((c, idx) => { + const p = c.currentPosition!; + const lineColor = getLineColor(region, c.line); + const showLabel = zoom >= 13; + const labelGap = gaps[idx] ?? baseGap; + return ( + <Marker key={idx} longitude={p.longitude} latitude={p.latitude} anchor="center"> <div style={{ - background: lineColor.background, - color: lineColor.text, - padding: "2px 4px", - borderRadius: 4, - fontSize: 10, - fontWeight: 700, - lineHeight: 1, - border: "1px solid #fff", - boxShadow: "0 1px 2px rgba(0,0,0,0.3)", - transform: `rotate(${-p.orientationDegrees}deg)`, + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: labelGap, + transform: `rotate(${p.orientationDegrees}deg)`, + transformOrigin: "center center", }} > - {c.line} + <svg + width="20" + height="20" + viewBox="0 0 24 24" + style={{ filter: "drop-shadow(0 1px 2px rgba(0,0,0,0.3))" }} + > + <path d="M12 2 L20 22 L12 18 L4 22 Z" fill={lineColor.background} stroke="#fff" strokeWidth="1.5" /> + </svg> + {showLabel && ( + <div + style={{ + background: lineColor.background, + color: lineColor.text, + padding: "2px 4px", + borderRadius: 4, + fontSize: 10, + fontWeight: 700, + lineHeight: 1, + border: "1px solid #fff", + boxShadow: "0 1px 2px rgba(0,0,0,0.3)", + transform: `rotate(${-p.orientationDegrees}deg)`, + pointerEvents: "none", + zIndex: 0, + }} + > + {c.line} + </div> + )} </div> - {/* Arrow pointing direction */} - <svg - width="20" - height="20" - viewBox="0 0 24 24" - style={{ - filter: "drop-shadow(0 1px 2px rgba(0,0,0,0.3))", - }} - > - <path - d="M12 2 L20 22 L12 18 L4 22 Z" - fill={lineColor.background} - stroke="#fff" - strokeWidth="1.5" - /> - </svg> - </div> - </Marker> - ); - })} + </Marker> + ); + }); + })()} </Map> )} + {/* Floating controls */} + <div className="map-floating-controls"> + <button type="button" aria-label="Center" className="center-btn" onClick={handleCenter} title="Center view"> + <svg width="20" height="20" viewBox="0 0 24 24" aria-hidden="true"> + <circle cx="12" cy="12" r="3" fill="currentColor"/> + <path d="M12 2v3M12 19v3M2 12h3M19 12h3" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/> + <circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" strokeWidth="1.5"/> + </svg> + </button> + </div> </div> ); }; diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationList.css b/src/frontend/app/components/Stops/ConsolidatedCirculationList.css index ca136d8..4d6a3a8 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationList.css +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationList.css @@ -2,7 +2,6 @@ font-size: 0.9rem; color: var(--subtitle-color); text-align: center; - margin-bottom: 1rem; padding: 0.5rem; } @@ -77,38 +76,24 @@ } /* Time color states */ -.consolidated-circulation-card .arrival-time.time-running { - color: #22c55e; -} - +.consolidated-circulation-card .arrival-time.time-running, .consolidated-circulation-card .arrival-time.time-running svg { color: #22c55e; } -.consolidated-circulation-card .arrival-time.time-delayed { - color: #09106e; -} - +.consolidated-circulation-card .arrival-time.time-delayed, .consolidated-circulation-card .arrival-time.time-delayed svg { - color: #09106e; -} - -/* Scheduled-only: dark blue in light mode, softer blue in dark mode */ -.consolidated-circulation-card .arrival-time.time-scheduled { - color: #0b3d91; /* dark blue */ + color: #ff6a00; } +.consolidated-circulation-card .arrival-time.time-scheduled, .consolidated-circulation-card .arrival-time.time-scheduled svg { - color: #0b3d91; + color: #0b3d91; /* dark blue */ } -@media (prefers-color-scheme: dark) { - .consolidated-circulation-card .arrival-time.time-scheduled { - color: #8fb4ff; /* lighten for dark backgrounds */ - } - .consolidated-circulation-card .arrival-time.time-scheduled svg { - color: #8fb4ff; - } +[data-theme="dark"] .consolidated-circulation-card .arrival-time.time-scheduled, +[data-theme="dark"] .consolidated-circulation-card .arrival-time.time-scheduled svg { + color: #8fb4ff; /* lighten for dark backgrounds */ } .consolidated-circulation-card .distance-info { diff --git a/src/frontend/app/maps/styleloader.ts b/src/frontend/app/maps/styleloader.ts index 93f6693..d20fd31 100644 --- a/src/frontend/app/maps/styleloader.ts +++ b/src/frontend/app/maps/styleloader.ts @@ -5,8 +5,13 @@ export async function loadStyle( styleName: string, colorScheme: Theme, ): Promise<StyleSpecification> { + if (colorScheme == "system") { + const isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches; + colorScheme = isDarkMode ? "dark" : "light"; + } + if (styleName == "openfreemap") { - const url = "/maps/styles/openfreemap-any.json"; + const url = `/maps/styles/openfreemap-${colorScheme}.json`; const resp = await fetch(url); if (!resp.ok) { diff --git a/src/frontend/app/root.css b/src/frontend/app/root.css index 12441af..e832e96 100644 --- a/src/frontend/app/root.css +++ b/src/frontend/app/root.css @@ -202,4 +202,5 @@ body { .maplibregl-ctrl-attrib-inner { font-size: 0.9em; + color: var(--ml-c-link-2); } diff --git a/src/frontend/app/routes/stops-$id.css b/src/frontend/app/routes/stops-$id.css index 3b377a7..7df3af2 100644 --- a/src/frontend/app/routes/stops-$id.css +++ b/src/frontend/app/routes/stops-$id.css @@ -276,16 +276,9 @@ .experimental-notice strong { display: block; - margin-bottom: 0.5rem; color: #856404; } -.experimental-notice p { - margin: 0; - font-size: 0.9rem; - line-height: 1.4; -} - [data-theme="dark"] .experimental-notice { background-color: #3d3100; border-color: #ffc107; diff --git a/src/frontend/app/routes/stops-$id.tsx b/src/frontend/app/routes/stops-$id.tsx index 812821d..6e669ca 100644 --- a/src/frontend/app/routes/stops-$id.tsx +++ b/src/frontend/app/routes/stops-$id.tsx @@ -141,7 +141,7 @@ export default function Estimates() { // Auto-refresh estimates data every 30 seconds (only if not in error state) useAutoRefresh({ onRefresh: refreshData, - interval: 30000, + interval: 12000, enabled: !dataError, }); diff --git a/src/frontend/public/maps/styles/openfreemap-dark.json b/src/frontend/public/maps/styles/openfreemap-dark.json new file mode 100644 index 0000000..8e78862 --- /dev/null +++ b/src/frontend/public/maps/styles/openfreemap-dark.json @@ -0,0 +1 @@ +{"version":8,"sources":{"ne2_shaded":{"maxzoom":6,"tileSize":256,"tiles":["https://tiles.openfreemap.org/natural_earth/ne2sr/{z}/{x}/{y}.png"],"type":"raster"},"openmaptiles":{"type":"vector","url":"https://tiles.openfreemap.org/planet"}},"sprite":"https://tiles.openfreemap.org/sprites/ofm_f384/ofm","glyphs":"https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf","layers":[{"id":"background","type":"background","paint":{"background-color":"rgb(242,243,240)"}},{"id":"park","type":"fill","source":"openmaptiles","source-layer":"park","filter":["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],"paint":{"fill-color":"rgb(230, 233, 229)"}},{"id":"water","type":"fill","source":"openmaptiles","source-layer":"water","filter":["all",["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],["!=",["get","brunnel"],"tunnel"]],"paint":{"fill-antialias":true,"fill-color":"rgb(194, 200, 202)"}},{"id":"landcover_ice_shelf","type":"fill","source":"openmaptiles","source-layer":"landcover","maxzoom":8,"filter":["all",["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],["==",["get","subclass"],"ice_shelf"]],"paint":{"fill-color":"hsl(0,0%,98%)","fill-opacity":0.7}},{"id":"landcover_glacier","type":"fill","source":"openmaptiles","source-layer":"landcover","maxzoom":8,"filter":["all",["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],["==",["get","subclass"],"glacier"]],"paint":{"fill-color":"hsl(0,0%,98%)","fill-opacity":["interpolate",["linear"],["zoom"],0,1,8,0.5]}},{"id":"landuse_residential","type":"fill","source":"openmaptiles","source-layer":"landuse","maxzoom":16,"filter":["all",["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],["==",["get","class"],"residential"]],"paint":{"fill-color":"rgb(234, 234, 230)","fill-opacity":["interpolate",["exponential",0.6],["zoom"],8,0.8,9,0.6]}},{"id":"landcover_wood","type":"fill","source":"openmaptiles","source-layer":"landcover","minzoom":10,"filter":["all",["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],["==",["get","class"],"wood"]],"paint":{"fill-color":"rgb(220,224,220)","fill-opacity":["interpolate",["linear"],["zoom"],8,0,12,1]}},{"id":"waterway","type":"line","source":"openmaptiles","source-layer":"waterway","filter":["match",["geometry-type"],["LineString","MultiLineString"],true,false],"paint":{"line-color":"hsl(195,17%,78%)"}},{"id":"building","type":"fill","source":"openmaptiles","source-layer":"building","minzoom":12,"paint":{"fill-antialias":true,"fill-color":"rgb(234, 234, 229)","fill-outline-color":"rgb(219, 219, 218)"}},{"id":"tunnel_motorway_casing","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":6,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["==",["get","brunnel"],"tunnel"],["==",["get","class"],"motorway"]]],"layout":{"line-cap":"butt","line-join":"miter"},"paint":{"line-color":"rgb(213, 213, 213)","line-opacity":1,"line-width":["interpolate",["exponential",1.4],["zoom"],5.8,0,6,3,20,40]}},{"id":"tunnel_motorway_inner","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":6,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["==",["get","brunnel"],"tunnel"],["==",["get","class"],"motorway"]]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"rgb(234,234,234)","line-width":["interpolate",["exponential",1.4],["zoom"],4,2,6,1.3,20,30]}},{"id":"aeroway-taxiway","type":"line","source":"openmaptiles","source-layer":"aeroway","minzoom":12,"filter":["match",["get","class"],["taxiway"],true,false],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"hsl(0,0%,88%)","line-opacity":1,"line-width":["interpolate",["exponential",1.55],["zoom"],13,1.8,20,20]}},{"id":"aeroway-runway-casing","type":"line","source":"openmaptiles","source-layer":"aeroway","minzoom":11,"filter":["match",["get","class"],["runway"],true,false],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"hsl(0,0%,88%)","line-opacity":1,"line-width":["interpolate",["exponential",1.5],["zoom"],11,6,17,55]}},{"id":"aeroway-area","type":"fill","source":"openmaptiles","source-layer":"aeroway","minzoom":4,"filter":["all",["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],["match",["get","class"],["runway","taxiway"],true,false]],"paint":{"fill-color":"rgba(255, 255, 255, 1)","fill-opacity":["interpolate",["linear"],["zoom"],13,0,14,1]}},{"id":"aeroway-runway","type":"line","source":"openmaptiles","source-layer":"aeroway","minzoom":11,"filter":["all",["match",["get","class"],["runway"],true,false],["match",["geometry-type"],["LineString","MultiLineString"],true,false]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"rgba(255, 255, 255, 1)","line-opacity":1,"line-width":["interpolate",["exponential",1.5],["zoom"],11,4,17,50]}},{"id":"road_area_pier","type":"fill","source":"openmaptiles","source-layer":"transportation","filter":["all",["match",["geometry-type"],["MultiPolygon","Polygon"],true,false],["==",["get","class"],"pier"]],"paint":{"fill-antialias":true,"fill-color":"rgb(242,243,240)"}},{"id":"road_pier","type":"line","source":"openmaptiles","source-layer":"transportation","filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","class"],["pier"],true,false]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"rgb(242,243,240)","line-width":["interpolate",["exponential",1.2],["zoom"],15,1,17,4]}},{"id":"highway_path","type":"line","source":"openmaptiles","source-layer":"transportation","filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["==",["get","class"],"path"]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"rgb(234, 234, 234)","line-opacity":0.9,"line-width":["interpolate",["exponential",1.2],["zoom"],13,1,20,10]}},{"id":"highway_minor","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":8,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","class"],["minor","service","track"],true,false]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"hsl(0,0%,88%)","line-opacity":0.9,"line-width":["interpolate",["exponential",1.55],["zoom"],13,1.8,20,20]}},{"id":"highway_major_casing","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":11,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","class"],["primary","secondary","tertiary","trunk"],true,false]],"layout":{"line-cap":"butt","line-join":"miter"},"paint":{"line-color":"rgb(213, 213, 213)","line-dasharray":[12,0],"line-width":["interpolate",["exponential",1.3],["zoom"],10,3,20,23]}},{"id":"highway_major_inner","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":11,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","class"],["primary","secondary","tertiary","trunk"],true,false]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"#fff","line-width":["interpolate",["exponential",1.3],["zoom"],10,2,20,20]}},{"id":"highway_major_subtle","type":"line","source":"openmaptiles","source-layer":"transportation","maxzoom":11,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","class"],["primary","secondary","tertiary","trunk"],true,false]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"hsla(0,0%,85%,0.69)","line-width":2}},{"id":"highway_motorway_casing","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":6,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["match",["get","brunnel"],["bridge","tunnel"],false,true],["==",["get","class"],"motorway"]]],"layout":{"line-cap":"butt","line-join":"miter"},"paint":{"line-color":"rgb(213, 213, 213)","line-dasharray":[2,0],"line-opacity":1,"line-width":["interpolate",["exponential",1.4],["zoom"],5.8,0,6,3,20,40]}},{"id":"highway_motorway_inner","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":6,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["match",["get","brunnel"],["bridge","tunnel"],false,true],["==",["get","class"],"motorway"]]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":["interpolate",["linear"],["zoom"],5.8,"hsla(0,0%,85%,0.53)",6,"#fff"],"line-width":["interpolate",["exponential",1.4],["zoom"],4,2,6,1.3,20,30]}},{"id":"highway_motorway_subtle","type":"line","source":"openmaptiles","source-layer":"transportation","maxzoom":6,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["==",["get","class"],"motorway"]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"hsla(0,0%,85%,0.53)","line-width":["interpolate",["exponential",1.4],["zoom"],4,2,6,1.3]}},{"id":"railway_transit","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":16,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["==",["get","class"],"transit"],["match",["get","brunnel"],["tunnel"],false,true]]],"layout":{"line-join":"round"},"paint":{"line-color":"#dddddd","line-width":3}},{"id":"railway_transit_dashline","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":16,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["==",["get","class"],"transit"],["match",["get","brunnel"],["tunnel"],false,true]]],"layout":{"line-join":"round"},"paint":{"line-color":"#fafafa","line-dasharray":[3,3],"line-width":2}},{"id":"railway_service","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":16,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["==",["get","class"],"rail"],["has","service"]]],"layout":{"line-join":"round"},"paint":{"line-color":"#dddddd","line-width":3}},{"id":"railway_service_dashline","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":16,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["==",["get","class"],"rail"],["has","service"]],"layout":{"line-join":"round"},"paint":{"line-color":"#fafafa","line-dasharray":[3,3],"line-width":2}},{"id":"railway","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":13,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["!",["has","service"]],["==",["get","class"],"rail"]]],"layout":{"line-join":"round"},"paint":{"line-color":"#dddddd","line-width":["interpolate",["exponential",1.3],["zoom"],16,3,20,7]}},{"id":"railway_dashline","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":13,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["!",["has","service"]],["==",["get","class"],"rail"]]],"layout":{"line-join":"round"},"paint":{"line-color":"#fafafa","line-dasharray":[3,3],"line-width":["interpolate",["exponential",1.3],["zoom"],16,2,20,6]}},{"id":"highway_motorway_bridge_casing","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":6,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["==",["get","brunnel"],"bridge"],["==",["get","class"],"motorway"]]],"layout":{"line-cap":"butt","line-join":"miter"},"paint":{"line-color":"rgb(213, 213, 213)","line-dasharray":[2,0],"line-opacity":1,"line-width":["interpolate",["exponential",1.4],["zoom"],5.8,0,6,5,20,45]}},{"id":"highway_motorway_bridge_inner","type":"line","source":"openmaptiles","source-layer":"transportation","minzoom":6,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["all",["==",["get","brunnel"],"bridge"],["==",["get","class"],"motorway"]]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":["interpolate",["linear"],["zoom"],5.8,"hsla(0,0%,85%,0.53)",6,"#fff"],"line-width":["interpolate",["exponential",1.4],["zoom"],4,2,6,1.3,20,30]}},{"id":"boundary_3","type":"line","source":"openmaptiles","source-layer":"boundary","minzoom":8,"filter":["all",[">=",["get","admin_level"],3],["<=",["get","admin_level"],6],["!=",["get","maritime"],1],["!=",["get","disputed"],1],["!",["has","claimed_by"]]],"paint":{"line-color":"hsl(0,0%,70%)","line-dasharray":[1,1],"line-width":["interpolate",["linear",1],["zoom"],7,1,11,2]}},{"id":"boundary_2","type":"line","source":"openmaptiles","source-layer":"boundary","filter":["all",["==",["get","admin_level"],2],["!=",["get","maritime"],1],["!=",["get","disputed"],1],["!",["has","claimed_by"]]],"layout":{"line-cap":"round","line-join":"round"},"paint":{"line-color":"hsl(0,0%,70%)","line-opacity":["interpolate",["linear"],["zoom"],0,0.4,4,1],"line-width":["interpolate",["linear"],["zoom"],3,1,5,1.2,12,3]}},{"id":"boundary_disputed","type":"line","source":"openmaptiles","source-layer":"boundary","filter":["all",["!=",["get","maritime"],1],["==",["get","disputed"],1]],"paint":{"line-color":"hsl(0,0%,70%)","line-dasharray":[1,2],"line-width":["interpolate",["linear"],["zoom"],3,1,5,1.2,12,3]}},{"id":"waterway_line_label","type":"symbol","source":"openmaptiles","source-layer":"waterway","minzoom":10,"filter":["match",["geometry-type"],["LineString","MultiLineString"],true,false],"layout":{"symbol-placement":"line","symbol-spacing":350,"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"]," ",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Italic"],"text-letter-spacing":0.2,"text-max-width":5,"text-size":14},"paint":{"text-color":"hsl(0,0%,66%)","text-halo-color":"rgba(255,255,255,0.7)","text-halo-width":1.5}},{"id":"water_name_point_label","type":"symbol","source":"openmaptiles","source-layer":"water_name","filter":["match",["geometry-type"],["MultiPoint","Point"],true,false],"layout":{"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Italic"],"text-letter-spacing":0.2,"text-max-width":5,"text-size":["interpolate",["linear"],["zoom"],0,10,8,14]},"paint":{"text-color":"#495e91","text-halo-color":"rgba(255,255,255,0.7)","text-halo-width":1.5}},{"id":"water_name_line_label","type":"symbol","source":"openmaptiles","source-layer":"water_name","filter":["match",["geometry-type"],["LineString","MultiLineString"],true,false],"layout":{"symbol-placement":"line","symbol-spacing":350,"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"]," ",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Italic"],"text-letter-spacing":0.2,"text-max-width":5,"text-size":14},"paint":{"text-color":"#495e91","text-halo-color":"rgba(255,255,255,0.7)","text-halo-width":1.5}},{"id":"highway-name-path","type":"symbol","source":"openmaptiles","source-layer":"transportation_name","minzoom":15.5,"filter":["==",["get","class"],"path"],"layout":{"symbol-placement":"line","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"]," ",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Regular"],"text-rotation-alignment":"map","text-size":["interpolate",["linear"],["zoom"],13,12,14,13]},"paint":{"text-color":"hsl(30,0%,62%)","text-halo-color":"#f8f4f0","text-halo-width":0.5}},{"id":"highway-name-minor","type":"symbol","source":"openmaptiles","source-layer":"transportation_name","minzoom":15,"filter":["all",["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","class"],["minor","service","track"],true,false]],"layout":{"symbol-placement":"line","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"]," ",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Regular"],"text-rotation-alignment":"map","text-size":["interpolate",["linear"],["zoom"],13,12,14,13]},"paint":{"text-color":"#666","text-halo-blur":0.5,"text-halo-width":1}},{"id":"highway-name-major","type":"symbol","source":"openmaptiles","source-layer":"transportation_name","minzoom":12.2,"filter":["match",["get","class"],["primary","secondary","tertiary","trunk"],true,false],"layout":{"symbol-placement":"line","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"]," ",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Regular"],"text-rotation-alignment":"map","text-size":["interpolate",["linear"],["zoom"],13,12,14,13]},"paint":{"text-color":"#666","text-halo-blur":0.5,"text-halo-width":1}},{"id":"highway-shield-non-us","type":"symbol","source":"openmaptiles","source-layer":"transportation_name","minzoom":11,"filter":["all",["<=",["get","ref_length"],6],["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","network"],["us-highway","us-interstate","us-state"],false,true]],"layout":{"icon-image":["concat","road_",["get","ref_length"]],"icon-rotation-alignment":"viewport","icon-size":1,"symbol-placement":["step",["zoom"],"point",11,"line"],"symbol-spacing":200,"text-field":["to-string",["get","ref"]],"text-font":["Noto Sans Regular"],"text-rotation-alignment":"viewport","text-size":10}},{"id":"highway-shield-us-interstate","type":"symbol","source":"openmaptiles","source-layer":"transportation_name","minzoom":11,"filter":["all",["<=",["get","ref_length"],6],["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","network"],["us-interstate"],true,false]],"layout":{"icon-image":["concat",["get","network"],"_",["get","ref_length"]],"icon-rotation-alignment":"viewport","icon-size":1,"symbol-placement":["step",["zoom"],"point",7,"line",8,"line"],"symbol-spacing":200,"text-field":["to-string",["get","ref"]],"text-font":["Noto Sans Regular"],"text-rotation-alignment":"viewport","text-size":10}},{"id":"road_shield_us","type":"symbol","source":"openmaptiles","source-layer":"transportation_name","minzoom":12,"filter":["all",["<=",["get","ref_length"],6],["match",["geometry-type"],["LineString","MultiLineString"],true,false],["match",["get","network"],["us-highway","us-state"],true,false]],"layout":{"icon-image":["concat",["get","network"],"_",["get","ref_length"]],"icon-rotation-alignment":"viewport","icon-size":1,"symbol-placement":["step",["zoom"],"point",11,"line"],"symbol-spacing":200,"text-field":["to-string",["get","ref"]],"text-font":["Noto Sans Regular"],"text-rotation-alignment":"viewport","text-size":10}},{"id":"airport","type":"symbol","source":"openmaptiles","source-layer":"aerodrome_label","minzoom":11,"filter":["all",["has","iata"]],"layout":{"icon-image":"airport_11","icon-size":1,"text-anchor":"top","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Regular"],"text-max-width":9,"text-offset":[0,0.6],"text-optional":true,"text-padding":2,"text-size":12},"paint":{"text-color":"#666","text-halo-blur":0.5,"text-halo-color":"#ffffff","text-halo-width":1}},{"id":"label_other","type":"symbol","source":"openmaptiles","source-layer":"place","minzoom":8,"filter":["match",["get","class"],["city","continent","country","state","town","village"],false,true],"layout":{"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Italic"],"text-letter-spacing":0.1,"text-max-width":9,"text-size":["interpolate",["linear"],["zoom"],8,9,12,10],"text-transform":"uppercase"},"paint":{"text-color":"#333","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_village","type":"symbol","source":"openmaptiles","source-layer":"place","minzoom":9,"filter":["==",["get","class"],"village"],"layout":{"icon-allow-overlap":true,"icon-image":["step",["zoom"],"circle_11_black",10,""],"icon-optional":false,"icon-size":0.2,"text-anchor":"bottom","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Regular"],"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],7,10,11,12]},"paint":{"text-color":"#000","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_town","type":"symbol","source":"openmaptiles","source-layer":"place","minzoom":6,"filter":["==",["get","class"],"town"],"layout":{"icon-allow-overlap":true,"icon-image":["step",["zoom"],"circle_11_black",10,""],"icon-optional":false,"icon-size":0.2,"text-anchor":"bottom","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Regular"],"text-max-width":8,"text-size":["interpolate",["exponential",1.2],["zoom"],7,12,11,14]},"paint":{"text-color":"#000","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_state","type":"symbol","source":"openmaptiles","source-layer":"place","minzoom":5,"maxzoom":8,"filter":["==",["get","class"],"state"],"layout":{"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Italic"],"text-letter-spacing":0.2,"text-max-width":9,"text-size":["interpolate",["linear"],["zoom"],5,10,8,14],"text-transform":"uppercase"},"paint":{"text-color":"#333","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_city","type":"symbol","source":"openmaptiles","source-layer":"place","minzoom":3,"filter":["all",["==",["get","class"],"city"],["!=",["get","capital"],2]],"layout":{"icon-allow-overlap":true,"icon-image":["step",["zoom"],"circle_11_black",9,""],"icon-optional":false,"icon-size":0.4,"text-anchor":"bottom","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Regular"],"text-max-width":8,"text-offset":[0,-0.1],"text-size":["interpolate",["exponential",1.2],["zoom"],4,11,7,13,11,18]},"paint":{"text-color":"#000","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_city_capital","type":"symbol","source":"openmaptiles","source-layer":"place","minzoom":3,"filter":["all",["==",["get","class"],"city"],["==",["get","capital"],2]],"layout":{"icon-allow-overlap":true,"icon-image":["step",["zoom"],"circle_11_black",9,""],"icon-optional":false,"icon-size":0.5,"text-anchor":"bottom","text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Bold"],"text-max-width":8,"text-offset":[0,-0.2],"text-size":["interpolate",["exponential",1.2],["zoom"],4,12,7,14,11,20]},"paint":{"text-color":"#000","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_country_3","type":"symbol","source":"openmaptiles","source-layer":"place","minzoom":2,"maxzoom":9,"filter":["all",["==",["get","class"],"country"],[">=",["get","rank"],3]],"layout":{"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Bold"],"text-max-width":6.25,"text-size":["interpolate",["linear"],["zoom"],3,9,7,17]},"paint":{"text-color":"#000","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_country_2","type":"symbol","source":"openmaptiles","source-layer":"place","maxzoom":9,"filter":["all",["==",["get","class"],"country"],["==",["get","rank"],2]],"layout":{"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Bold"],"text-max-width":6.25,"text-size":["interpolate",["linear"],["zoom"],2,9,5,17]},"paint":{"text-color":"#000","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}},{"id":"label_country_1","type":"symbol","source":"openmaptiles","source-layer":"place","maxzoom":9,"filter":["all",["==",["get","class"],"country"],["==",["get","rank"],1]],"layout":{"text-field":["case",["has","name:nonlatin"],["concat",["get","name:latin"],"\n",["get","name:nonlatin"]],["coalesce",["get","name_en"],["get","name"]]],"text-font":["Noto Sans Bold"],"text-max-width":6.25,"text-size":["interpolate",["linear"],["zoom"],1,9,4,17]},"paint":{"text-color":"#000","text-halo-blur":1,"text-halo-color":"#fff","text-halo-width":1}}]} diff --git a/src/frontend/public/maps/styles/openfreemap-any.json b/src/frontend/public/maps/styles/openfreemap-light.json index cb528da..cb528da 100644 --- a/src/frontend/public/maps/styles/openfreemap-any.json +++ b/src/frontend/public/maps/styles/openfreemap-light.json |
