@zendir/ui 0.2.11 → 0.2.13

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.
@@ -284,7 +284,7 @@ function GroundTrackMap({
284
284
  const terminatorEdge = calculateTerminatorContinuous(now, 0);
285
285
  if (terminatorEdge.sunset.length > 2) {
286
286
  ctx.save();
287
- ctx.strokeStyle = "rgba(143, 174, 200, 0.08)";
287
+ ctx.strokeStyle = "rgba(160, 160, 160, 0.08)";
288
288
  ctx.lineWidth = 3;
289
289
  for (const curve of [terminatorEdge.sunset, terminatorEdge.sunrise]) {
290
290
  for (const offset of [-360, 0, 360]) {
@@ -298,7 +298,7 @@ function GroundTrackMap({
298
298
  ctx.stroke();
299
299
  }
300
300
  }
301
- ctx.strokeStyle = "rgba(154, 184, 216, 0.35)";
301
+ ctx.strokeStyle = "rgba(168, 168, 168, 0.30)";
302
302
  ctx.lineWidth = 1;
303
303
  for (const curve of [terminatorEdge.sunset, terminatorEdge.sunrise]) {
304
304
  for (const offset of [-360, 0, 360]) {
@@ -1 +1 @@
1
- {"version":3,"file":"GroundTrackMap.js","sources":["../../../src/react/charts/GroundTrackMap.tsx"],"sourcesContent":["/**\n * @zendir/ui - GroundTrackMap Component (Enhanced)\n * \n * Full-featured 2D world map showing spacecraft ground tracks, current positions,\n * ground station locations, coverage footprints, satellite icons, and day/night terminator.\n * \n * Inspired by Astro UXDS TT&C Monitor / GRM Dashboard ground map patterns:\n * - Satellite icons with status-colored indicators (not just dots)\n * - Ground station antenna icons with coverage circles\n * - Sensor/antenna footprint cone projections\n * - Future orbit tracks (dashed) vs past tracks (solid)\n * - Day/night terminator\n * - Multi-satellite support\n * - Interactive hover tooltips\n * - AOS/LOS markers on track\n * - Legend with satellite/station counts\n * \n * Astro UX Compliance:\n * - Theme-integrated via useTheme()\n * - Uses official Astro status colors from theme tokens\n * - Uses Astro monitoring icon patterns\n * - 14pt minimum for labels (AstroUXDS guideline)\n * - Consistent with Astro data visualization patterns\n */\n\nimport React, { useRef, useEffect, useCallback, useMemo, useState } from 'react';\nimport { useTheme } from '../theme';\nimport { AstroIcon } from '../core/AstroIcon';\nimport type { GroundTrackPoint, GroundStation } from '../types';\nimport type { GroundTrackMapLeafletProps } from './GroundTrackMapLeaflet';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SatelliteTrack {\n /** Unique satellite identifier */\n id: string;\n /** Satellite display name */\n name: string;\n /** Ground track points */\n groundTrack: GroundTrackPoint[];\n /** Track color */\n color?: string;\n /** Satellite status for icon coloring */\n status?: 'normal' | 'caution' | 'serious' | 'critical' | 'standby' | 'off';\n /** Access mask (true = in contact) */\n accessMask?: boolean[];\n /** Show this satellite's sensor footprint */\n showFootprint?: boolean;\n /** Footprint radius in degrees (sensor cone half-angle on ground) */\n footprintRadius?: number;\n /** Show future (predicted) track as dashed line */\n futureTrackIndex?: number;\n /** AOS/LOS markers */\n passMarkers?: Array<{ type: 'aos' | 'los'; latitude: number; longitude: number; label?: string }>;\n}\n\nexport interface GroundStationEnhanced extends GroundStation {\n /** Station status */\n status?: 'normal' | 'caution' | 'serious' | 'critical' | 'standby' | 'off';\n /** Show coverage circle */\n showCoverage?: boolean;\n /** Coverage radius in degrees (visibility horizon) */\n coverageRadius?: number;\n /** Station type (affects icon) */\n type?: 'dish' | 'phased-array' | 'omni' | 'relay';\n}\n\n/** \n * SRO-compatible team path format (space-range-operator CustomMap data shape).\n * Provide this as an alternative to `satellites` for plug-and-play compatibility.\n */\nexport interface TeamPath {\n /** Team/satellite name */\n name: string;\n /** Track color */\n color?: string;\n /** Ordered position array */\n positions: Array<{\n lat: number;\n lng: number;\n time?: number;\n altitude?: number | null;\n }>;\n}\n\n/** SRO-compatible ground station format */\nexport interface SROGroundStation {\n name: string;\n latitude: number;\n longitude: number;\n altitude?: number | null;\n}\n\n/**\n * User-placed point-of-interest pin on the map.\n * Designed for collaborative scenarios where operators share annotated locations\n * across terminals in real time (e.g. targets, waypoints, hazard markers).\n */\nexport interface MapPin {\n /** Unique identifier (used as key and for update/remove callbacks) */\n id: string;\n /** Latitude in degrees (−90 … 90) */\n latitude: number;\n /** Longitude in degrees (−180 … 180) */\n longitude: number;\n /** Short label displayed next to the pin (e.g. \"Target Alpha\") */\n label?: string;\n /** Pin color — any CSS color string. Defaults to accent primary. */\n color?: string;\n /** Optional description shown in tooltip on hover */\n description?: string;\n /** Who placed the pin (display-only; not enforced) */\n createdBy?: string;\n}\n\n/**\n * A point light source rendered on the night side of the map.\n * Use this to display city lights, base locations, RF emitters,\n * or any glow that should only be visible after sunset.\n *\n * Light sources are masked by the terminator — they fade in\n * through the twilight gradient and reach full brightness in\n * deep night, matching real-world light-pollution behavior.\n */\nexport interface LightSource {\n /** Latitude in degrees (−90 … 90) */\n latitude: number;\n /** Longitude in degrees (−180 … 180) */\n longitude: number;\n /** Glow radius in pixels (default 4). Larger values create wider halos. */\n radius?: number;\n /** Glow intensity 0–1 (default 0.8). Controls the peak alpha of the light dot. */\n intensity?: number;\n /** Light color — any CSS color string (default '#ffeedd', warm white). */\n color?: string;\n /** Optional label shown on hover (Leaflet) or in tooltip (Canvas). */\n label?: string;\n}\n\n/**\n * Developer-defined map layer shown in the Layers panel.\n * The GroundTrackMap does not render the layer content — it only provides\n * the toggle UI. The consumer app should listen to `onLayerChange` and\n * render/hide its own overlay accordingly.\n */\nexport interface MapLayerDef {\n /** Unique identifier for the layer (e.g. 'heatmap', 'coverage') */\n id: string;\n /** Display label in the Layers panel */\n label: string;\n /** Whether the layer is on by default (default true) */\n defaultEnabled?: boolean;\n}\n\nexport interface GroundTrackMapProps {\n /** Single satellite ground track (legacy API) */\n groundTrack?: GroundTrackPoint[];\n /** Multiple satellite tracks */\n satellites?: SatelliteTrack[];\n /** Ground stations to display */\n groundStations?: (GroundStation | GroundStationEnhanced | SROGroundStation)[];\n /** Access mask for single-satellite mode (legacy API) */\n accessMask?: boolean[];\n\n // --- SRO-compatible alternate API (space-range-operator plug-and-play) ---\n /** Team path data (SRO CustomMap format) — auto-converts to satellites internally */\n teamPaths?: TeamPath[];\n\n // --- Display options ---\n /** Show day/night terminator */\n showTerminator?: boolean;\n /** Override the time used for the day/night terminator calculation.\n * Defaults to wall-clock `new Date()` when omitted.\n * Pass a simulation/mission UTC to keep the terminator in sync with a sim clock. */\n terminatorTime?: Date;\n /** Show grid lines */\n showGrid?: boolean;\n /** Show legend */\n showLegend?: boolean;\n /** Show equator highlight */\n showEquator?: boolean;\n /** Show recenter button (SRO compat) */\n showRecenterButton?: boolean;\n /** Show a toggle button to switch between Dark and Satellite tile styles. Default true for Leaflet. */\n showMapStyleToggle?: boolean;\n\n // --- State ---\n /** Whether data is still loading (SRO compat) */\n isLoading?: boolean;\n /** Message when there is no data (SRO compat) */\n emptyMessage?: string;\n\n // --- Sizing ---\n /** Chart width (default: 100%) */\n width?: number | string;\n /** Chart height — number for fixed px, or CSS string like '100%' to fill a flex parent */\n height?: number | string;\n /** Minimum height CSS string (SRO compat, e.g. \"400px\") */\n minHeight?: string;\n\n // --- Centering ---\n /** Default center [lat, lon] (SRO compat) */\n defaultCenter?: [number, number];\n /** Default zoom level 1-10 (SRO compat, affects initial scale) */\n defaultZoom?: number;\n\n /** Custom className */\n className?: string;\n /** Click handler for satellites */\n onSatelliteClick?: (satelliteId: string) => void;\n /** Click handler for ground stations */\n onStationClick?: (stationId: string) => void;\n\n /** Map backend: 'leaflet' (default, requires leaflet peer) or 'canvas' */\n mapProvider?: 'leaflet' | 'canvas';\n /** Tile URL for Leaflet (default: CartoDB dark). Ignored when mapProvider is 'canvas'. */\n tileUrl?: string;\n\n // --- Day/Night Tile Masking (Leaflet only) ---\n /**\n * URL template for a \"night\" tile layer (e.g. NASA Black Marble, VIIRS city lights).\n * When provided, this layer is rendered beneath the terminator overlay so that it\n * appears only on the night side of the map — creating a realistic day/night transition.\n * The day tiles remain visible on the sunlit side.\n *\n * Requires `showTerminator` to be enabled. Leaflet backend only.\n *\n * Example: `'https://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_CityLights_2012/...'`\n */\n nightTileUrl?: string;\n\n // --- Dynamic Light Sources ---\n /**\n * Array of point light sources rendered on the night side of the map.\n * Each light appears as a soft glow dot that is masked by the terminator —\n * invisible in daylight, fading in through twilight, full brightness at night.\n *\n * Use cases: city lights, base indicators, RF emitters, targets, population centers.\n */\n lightSources?: LightSource[];\n\n // --- Collaborative Pins (Points of Interest) ---\n /** Array of user-placed pins displayed on the map */\n pins?: MapPin[];\n /**\n * Allow operators to place new pins by clicking the map.\n * When true, a single-click on an empty area opens a pin creation flow.\n * Requires `onPinAdd` to be set. Default false.\n */\n pinsEditable?: boolean;\n /** Called when the user places a new pin (provides lat/lon; consumer assigns id and persists) */\n onPinAdd?: (pin: Omit<MapPin, 'id'>) => void;\n /** Called when the user edits an existing pin (label, color, description change) */\n onPinUpdate?: (pin: MapPin) => void;\n /** Called when the user removes a pin */\n onPinRemove?: (pinId: string) => void;\n\n // --- Layers Panel ---\n /**\n * Custom overlay layers shown in the Layers panel dropdown.\n * Each layer gets a toggle switch. The GroundTrackMap does NOT render\n * the layer content — it only provides the toggle UI.\n * Listen to `onLayerChange` for state updates and render your own overlays.\n */\n customLayers?: MapLayerDef[];\n /**\n * Called when any layer is toggled (built-in or custom).\n * `layerId` is one of: 'terminator', 'grid', or a custom layer id.\n * `enabled` is the new toggle state.\n */\n onLayerChange?: (layerId: string, enabled: boolean) => void;\n\n /**\n * Show sun and moon position markers on the map.\n * Requires `showTerminator`. Default: true when terminator is enabled.\n */\n showCelestialMarkers?: boolean;\n}\n\n// =============================================================================\n// Constants — aligned with official Astro UXDS status colors\n// These MUST match the STATUS_COLORS in unified/theme.ts and ThemeProvider\n// =============================================================================\n\nconst STATUS_COLOR_MAP: Record<string, string> = {\n normal: '#56f000', // Green — Astro UXDS \"Normal\"\n standby: '#2dccff', // Cyan — Astro UXDS \"Standby\"\n caution: '#fce83a', // Yellow — Astro UXDS \"Caution\"\n serious: '#ffb302', // Orange — Astro UXDS \"Serious\"\n critical: '#ff3838', // Red — Astro UXDS \"Critical\"\n off: '#a4abb6', // Grey — Astro UXDS \"Off\"\n};\n\nconst DEFAULT_TRACK_COLORS = [\n '#2dccff', '#3E3CFF', '#9D70FF', '#56f000', '#fce83a', '#ff7849', '#2dd4bf', '#ff3838',\n];\n\n// Earth constants for realistic coverage calculations\nconst EARTH_RADIUS_KM = 6371;\nconst _DEG_PER_KM = 1 / 111.32; // Approximate degrees per km at equator\n\n// Higher-quality world map coastline paths (Mercator-compatible)\nconst WORLD_MAP_PATHS = [\n // North America\n 'M-168,70 L-168,60 L-145,63 L-140,58 L-130,55 L-125,49 L-122,48 L-117,33 L-115,28 L-105,22 L-97,18 L-88,20 L-82,25 L-82,30 L-80,32 L-67,47 L-60,46 L-55,52 L-56,60 L-65,70 L-85,73 L-100,72 L-130,70 L-168,70',\n // South America\n 'M-82,12 L-77,8 L-73,11 L-65,5 L-60,5 L-50,0 L-45,-5 L-43,-10 L-39,-15 L-38,-22 L-40,-25 L-43,-30 L-48,-33 L-50,-40 L-55,-48 L-57,-52 L-68,-55 L-73,-50 L-78,-42 L-80,-20 L-78,-5 L-82,12',\n // Europe + Africa\n 'M-10,72 L-5,60 L-5,48 L0,44 L3,44 L5,48 L8,44 L3,37 L-5,35 L-17,28 L-17,15 L-8,10 L-4,5 L5,5 L10,2 L15,-3 L22,-12 L28,-22 L33,-30 L30,-35 L22,-35 L18,-27 L12,-20 L8,-10 L3,0 L-5,10 L-12,15 L-15,20 L-13,32 L-10,38 L0,48 L8,55 L15,58 L20,60 L25,65 L30,70 L-10,72',\n // Asia \n 'M30,70 L40,65 L50,60 L60,55 L70,50 L80,45 L90,45 L100,40 L105,35 L110,30 L115,25 L120,30 L125,35 L130,40 L135,45 L140,50 L145,55 L150,60 L155,65 L160,68 L170,70 L180,70 L180,72 L30,72 L30,70',\n // Australia\n 'M112,-12 L118,-14 L125,-15 L132,-13 L138,-15 L143,-17 L148,-20 L152,-23 L153,-28 L150,-33 L147,-37 L140,-38 L134,-36 L130,-33 L126,-30 L120,-30 L116,-28 L114,-24 L113,-18 L112,-12',\n // Antarctica\n 'M-180,-72 L180,-72 L180,-90 L-180,-90 Z',\n];\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Calculate ground station visibility radius in degrees.\n * Uses spherical Earth geometry: for a station with minimum elevation angle `elDeg`\n * and a satellite at altitude `altKm`, the half-angle subtended at Earth center is:\n * ρ = acos(R / (R + h)) − el_rad\n * Then the ground-range in degrees ≈ ρ * (180/π).\n * If no altitude context, coverageRadius prop is used directly (in degrees).\n */\nfunction _visibilityRadiusDeg(altitudeKm: number = 500, minElevationDeg: number = 5): number {\n const elRad = (minElevationDeg * Math.PI) / 180;\n const rho = Math.acos(EARTH_RADIUS_KM / (EARTH_RADIUS_KM + altitudeKm)) - elRad;\n return Math.max(0, (rho * 180) / Math.PI);\n}\n\n/**\n * Draw a ground-circle footprint using great-circle math.\n * Given a center lat/lon and an angular radius (in degrees measured along\n * Earth's surface), compute N points around the circle on the sphere, then\n * project each to equirectangular pixel coordinates.\n *\n * This produces a circle that is geographically correct AND looks natural\n * on the map — at high latitudes the circle is wider in longitude because\n * that's how equirectangular projection works, but it's capped by reality\n * rather than a simple 1/cos blowup.\n */\nfunction drawCoverageEllipse(\n ctx: CanvasRenderingContext2D,\n centerLat: number,\n centerLon: number,\n radiusDeg: number,\n W: number,\n H: number,\n lonToX: (lon: number, w: number) => number,\n latToY: (lat: number, h: number) => number,\n numSegments: number = 72,\n): void {\n const lat0 = (centerLat * Math.PI) / 180;\n const lon0 = (centerLon * Math.PI) / 180;\n const d = (radiusDeg * Math.PI) / 180; // angular radius in radians\n\n // Compute the center pixel once — all points are placed relative to this\n // so the circle never jumps across the date-line seam.\n const cx = lonToX(centerLon, W);\n const cy = latToY(centerLat, H);\n const pxPerDegLon = W / 360;\n const pxPerDegLat = H / 180;\n\n ctx.beginPath();\n for (let i = 0; i <= numSegments; i++) {\n const bearing = (i / numSegments) * 2 * Math.PI;\n\n // Great-circle destination formula\n const sinLat = Math.sin(lat0) * Math.cos(d) + Math.cos(lat0) * Math.sin(d) * Math.cos(bearing);\n const lat = Math.asin(Math.max(-1, Math.min(1, sinLat)));\n const lon = lon0 + Math.atan2(\n Math.sin(bearing) * Math.sin(d) * Math.cos(lat0),\n Math.cos(d) - Math.sin(lat0) * sinLat,\n );\n\n const pLatDeg = (lat * 180) / Math.PI;\n const pLonDeg = (lon * 180) / Math.PI;\n\n // Pixel offset from center — no normalization, so no date-line jump\n const dLon = pLonDeg - centerLon;\n const dLat = pLatDeg - centerLat;\n const px = cx + dLon * pxPerDegLon;\n const py = cy - dLat * pxPerDegLat; // Y inverted (lat goes up, pixels go down)\n\n if (i === 0) ctx.moveTo(px, py);\n else ctx.lineTo(px, py);\n }\n ctx.closePath();\n}\n//sz ee*s \n\n/** Parse a CSS hex color to [r, g, b]. Falls back to warm white. */\nfunction hexToRgb(hex: string): [number, number, number] {\n const h = hex.replace('#', '');\n if (h.length === 3) {\n return [parseInt(h[0] + h[0], 16), parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16)];\n }\n if (h.length >= 6) {\n return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];\n }\n return [255, 238, 221]; // fallback warm white\n}\n\n/**\n * Calculate solar terminator points for a given date and solar depression angle.\n *\n * `depressionDeg` offsets the zenith angle to produce twilight boundaries:\n * - 0° = geometric sunset/sunrise\n * - 6° = civil twilight (IAU/USNO)\n * - 12° = nautical twilight\n * - 18° = astronomical twilight\n */\n\n/** Calculate the sub-solar point (latitude, longitude) for a given UTC Date. */\nfunction calculateSubSolarPoint(date: Date): [number, number] {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const lon = -(solarHours - 12) * 15;\n return [declination, ((lon + 540) % 360) - 180];\n}\n\n/** Calculate the approximate sub-lunar point for a given UTC Date (low-precision). */\nfunction calculateSubLunarPoint(date: Date): [number, number] {\n const J2000 = Date.UTC(2000, 0, 1, 12, 0, 0);\n const d = (date.getTime() - J2000) / 86400000;\n const DEG = Math.PI / 180;\n const L = (218.316 + 13.176396 * d) % 360;\n const M = (134.963 + 13.064993 * d) % 360;\n const F = (93.272 + 13.229350 * d) % 360;\n const lon_ecl = L + 6.289 * Math.sin(M * DEG);\n const lat_ecl = 5.128 * Math.sin(F * DEG);\n const obliquity = 23.439 - 0.00000036 * d;\n const sinRA = Math.sin(lon_ecl * DEG) * Math.cos(obliquity * DEG) - Math.tan(lat_ecl * DEG) * Math.sin(obliquity * DEG);\n const cosRA = Math.cos(lon_ecl * DEG);\n let RA = Math.atan2(sinRA, cosRA) / DEG;\n if (RA < 0) RA += 360;\n const dec = Math.asin(\n Math.sin(lat_ecl * DEG) * Math.cos(obliquity * DEG)\n + Math.cos(lat_ecl * DEG) * Math.sin(obliquity * DEG) * Math.sin(lon_ecl * DEG)\n ) / DEG;\n const GMST = (280.46061837 + 360.98564736629 * d) % 360;\n let geoLon = RA - GMST;\n geoLon = ((geoLon + 540) % 360) - 180;\n return [dec, geoLon];\n}\n\nfunction calculateTerminatorContinuous(\n date: Date,\n depressionDeg: number = 0,\n numPoints: number = 360,\n): { sunset: Array<[number, number]>, sunrise: Array<[number, number]> } {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n\n // Equation of Time correction (minutes) for more accurate solar position\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n\n // Sub-solar longitude: use full UTC time (hours + minutes + seconds) plus EoT\n // Sub-solar longitude: where the sun is directly overhead.\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const subSolarLon = -(solarHours - 12) * 15;\n const depRad = (depressionDeg * Math.PI) / 180;\n\n const sunset: Array<[number, number]> = [];\n const sunrise: Array<[number, number]> = [];\n\n for (let i = 0; i <= numPoints; i++) {\n const lat = -89.999 + (i / numPoints) * 179.998;\n const latRad = lat * (Math.PI / 180);\n const cosH = -(Math.sin(depRad) + Math.sin(latRad) * Math.sin(decRad))\n / (Math.cos(latRad) * Math.cos(decRad));\n \n if (cosH < -1) {\n // All day — midnight sun. No night boundary.\n } else if (cosH > 1) {\n // All night — polar night. Night spans all longitudes.\n sunset.push([lat, subSolarLon]);\n sunrise.push([lat, subSolarLon + 360]);\n } else {\n const H = (Math.acos(cosH) * 180) / Math.PI;\n // Sunset: H degrees east of sub-solar point (afternoon→evening)\n sunset.push([lat, subSolarLon + H]);\n // Sunrise: H degrees west, expressed as +360-H for continuous polygon\n sunrise.push([lat, subSolarLon + 360 - H]);\n }\n }\n \n return { sunset, sunrise };\n}\n\nfunction buildNightPolygon(\n terminator: { sunset: Array<[number, number]>, sunrise: Array<[number, number]> }\n): [number, number][] {\n const { sunset, sunrise } = terminator;\n if (!sunset.length || !sunrise.length) return [];\n\n const poly: [number, number][] = [];\n\n // Left edge of night (sunset): South to North\n poly.push(...sunset);\n\n // Right edge of night (sunrise): North to South\n poly.push(...[...sunrise].reverse());\n\n return poly;\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function GroundTrackMap({\n groundTrack,\n satellites = [],\n groundStations = [],\n accessMask,\n teamPaths,\n showTerminator = true,\n terminatorTime,\n showGrid = true,\n showLegend = true,\n showEquator = true,\n showRecenterButton = false,\n showMapStyleToggle = true,\n isLoading = false,\n emptyMessage = 'No orbital data available',\n width = '100%',\n height = '100%',\n minHeight = '400px',\n defaultCenter,\n defaultZoom,\n className = '',\n onSatelliteClick,\n onStationClick,\n mapProvider = 'leaflet',\n tileUrl,\n nightTileUrl,\n lightSources,\n pins,\n pinsEditable = false,\n onPinAdd,\n onPinUpdate,\n onPinRemove,\n customLayers,\n onLayerChange,\n showCelestialMarkers,\n}: GroundTrackMapProps): React.ReactElement {\n const { tokens } = useTheme();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const [tooltip, setTooltip] = useState<{\n x: number; y: number;\n type: 'satellite' | 'station';\n name: string;\n status: string;\n statusColor: string;\n lat: number;\n lon: number;\n alt?: number;\n // Ground station extras\n stationType?: string;\n network?: string;\n coverageRadius?: number;\n // Satellite extras\n trackColor?: string;\n hasFootprint?: boolean;\n futurePoints?: number;\n pastPoints?: number;\n } | null>(null);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const [_viewOffset, setViewOffset] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n\n // Normalize satellites: support SRO teamPaths, legacy single-track, and native API\n const allSatellites = useMemo<SatelliteTrack[]>(() => {\n // Priority 1: native satellites prop\n if (satellites.length > 0) return satellites;\n // Priority 2: SRO teamPaths format — auto-convert\n if (teamPaths && teamPaths.length > 0) {\n return teamPaths.map((tp, idx) => ({\n id: `team-${idx}`,\n name: tp.name,\n color: tp.color,\n status: 'normal' as const,\n groundTrack: tp.positions\n .filter(p => p.lat != null && p.lng != null)\n .map(p => ({\n latitude: p.lat,\n longitude: p.lng,\n altitude: p.altitude ?? 0,\n timestamp: p.time != null ? new Date(p.time * 1000).toISOString() : new Date().toISOString(),\n })),\n }));\n }\n // Priority 3: legacy single-track API\n if (groundTrack && groundTrack.length > 0) {\n return [{\n id: 'primary',\n name: 'Satellite',\n groundTrack,\n status: 'normal',\n accessMask,\n }];\n }\n return [];\n }, [satellites, groundTrack, accessMask, teamPaths]);\n\n // Stable defaults for Leaflet so animated updates don't get new refs and trigger map recreation\n const leafletDefaultCenter = useMemo<[number, number]>(() => defaultCenter ?? [20, 0], [defaultCenter]);\n const leafletDefaultZoom = useMemo(() => defaultZoom ?? 2, [defaultZoom]);\n\n // Optional Leaflet map: load when mapProvider is 'leaflet'\n const [LeafletMap, setLeafletMap] = useState<React.ComponentType<GroundTrackMapLeafletProps> | null>(null);\n const [leafletFailed, setLeafletFailed] = useState(false);\n\n useEffect(() => {\n if (mapProvider !== 'leaflet') return;\n import('./GroundTrackMapLeaflet')\n .then((m) => setLeafletMap(() => m.GroundTrackMapLeaflet))\n .catch((err) => {\n console.warn('[GroundTrackMap] Leaflet backend failed to load. Install \"leaflet\" and ensure it is resolvable. Falling back to static canvas.', err);\n setLeafletFailed(true);\n });\n }, [mapProvider]);\n\n // All canvas-backend hooks must run unconditionally (same hook count every render)\n // Recenter handler (canvas backend)\n const handleRecenter = useCallback(() => {\n setViewOffset({ x: 0, y: 0 });\n }, []);\n\n const COLORS = useMemo(() => ({\n background: tokens.colors.background.base,\n grid: tokens.colors.border.muted,\n text: tokens.colors.text.secondary,\n accent: tokens.colors.accent.primary,\n land: 'rgba(30, 40, 58, 0.92)',\n ocean: tokens.colors.background.base,\n night: 'rgba(0, 10, 40, 0.35)',\n equator: 'rgba(88, 166, 255, 0.25)',\n }), [tokens]);\n\n const lonToX = useCallback((lon: number, w: number) => {\n let normalizedLon = lon;\n while (normalizedLon > 180) normalizedLon -= 360;\n while (normalizedLon < -180) normalizedLon += 360;\n return ((normalizedLon + 180) / 360) * w;\n }, []);\n\n const latToY = useCallback((lat: number, h: number) => {\n return ((90 - lat) / 180) * h;\n }, []);\n\n const draw = useCallback(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const dpr = window.devicePixelRatio || 1;\n const rect = container.getBoundingClientRect();\n const W = rect.width;\n // When height is a CSS string ('100%'), use the measured container height\n const H = typeof height === 'number' ? height : rect.height || 400;\n\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n ctx.scale(dpr, dpr);\n\n // === Background ===\n ctx.fillStyle = COLORS.background;\n ctx.fillRect(0, 0, W, H);\n\n // === Day/Night Terminator with smooth graduated twilight ===\n // Many thin bands (every 2° of solar depression) produce a seamless\n // day→night gradient instead of hard-edged zones.\n if (showTerminator) {\n const now = terminatorTime ?? new Date();\n\n const BAND_STEP = 1.5;\n const MAX_DEP = 30;\n const NIGHT_ALPHA = 0.38;\n const bandSteps: Array<{ depression: number; alpha: number }> = [];\n for (let d = 0; d <= MAX_DEP; d += BAND_STEP) {\n const t = Math.min(d / 18, 1);\n const alpha = Math.pow(t, 1.6) * (NIGHT_ALPHA * 0.85) + (d > 18 ? (d - 18) / 12 * (NIGHT_ALPHA * 0.15) : 0);\n bandSteps.push({ depression: d, alpha: Math.min(alpha, NIGHT_ALPHA) });\n }\n bandSteps.push({ depression: 90, alpha: NIGHT_ALPHA });\n\n let prevAlpha = 0;\n for (const zone of bandSteps) {\n const dep = Math.min(zone.depression, 89);\n const bandAlpha = zone.alpha - prevAlpha;\n if (bandAlpha < 0.002) { prevAlpha = zone.alpha; continue; }\n\n const terminator = calculateTerminatorContinuous(now, dep);\n if (terminator.sunset.length === 0) { prevAlpha = zone.alpha; continue; }\n \n const poly = buildNightPolygon(terminator);\n if (poly.length < 3) { prevAlpha = zone.alpha; continue; }\n\n ctx.fillStyle = `rgba(42, 58, 82, ${bandAlpha.toFixed(4)})`;\n \n // Draw the polygon (wrapping around longitude boundaries by drawing 3 copies)\n for (const offset of [-360, 0, 360]) {\n ctx.beginPath();\n for (let i = 0; i < poly.length; i++) {\n const lat = poly[i][0];\n const lon = poly[i][1] + offset;\n const x = lonToX(lon, W);\n const y = latToY(lat, H);\n \n // To prevent lines jumping completely across the canvas from right to left\n // if a polygon crosses the map boundary, we should probably handle it.\n // But since we draw 3 full copies (-360, 0, +360), they overlap seamlessly.\n if (i === 0) {\n ctx.moveTo(x, y);\n } else {\n // If distance is huge (e.g. > W/2), it means it's wrapping around the map edge.\n // Move instead of line to avoid a horizontal streak.\n // (Actually, since we unwrap longitude continuously in calculateTerminatorContinuous,\n // there are NO jumps in longitude inside the polygon! It's one continuous shape.)\n ctx.lineTo(x, y);\n }\n }\n ctx.closePath();\n ctx.fill();\n }\n \n prevAlpha = zone.alpha;\n }\n\n // Draw a smooth terminator boundary line (0° depression)\n const terminatorEdge = calculateTerminatorContinuous(now, 0);\n if (terminatorEdge.sunset.length > 2) {\n ctx.save();\n // Soft outer glow\n ctx.strokeStyle = 'rgba(143, 174, 200, 0.08)';\n ctx.lineWidth = 3;\n for (const curve of [terminatorEdge.sunset, terminatorEdge.sunrise]) {\n for (const offset of [-360, 0, 360]) {\n ctx.beginPath();\n for (let i = 0; i < curve.length; i++) {\n const x = lonToX(curve[i][1] + offset, W);\n const y = latToY(curve[i][0], H);\n if (i === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n }\n // Fine core line\n ctx.strokeStyle = 'rgba(154, 184, 216, 0.35)';\n ctx.lineWidth = 1;\n for (const curve of [terminatorEdge.sunset, terminatorEdge.sunrise]) {\n for (const offset of [-360, 0, 360]) {\n ctx.beginPath();\n for (let i = 0; i < curve.length; i++) {\n const x = lonToX(curve[i][1] + offset, W);\n const y = latToY(curve[i][0], H);\n if (i === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n }\n ctx.restore();\n }\n\n // TODO: Re-enable sun/moon celestial markers once visual design is finalized.\n // Uncomment to restore: const celestialEnabled = showCelestialMarkers !== undefined ? showCelestialMarkers : true;\n const celestialEnabled = false;\n if (celestialEnabled) {\n const [sunLat, sunLon] = calculateSubSolarPoint(now);\n const sx = lonToX(sunLon, W), sy = latToY(sunLat, H);\n ctx.save();\n ctx.shadowColor = 'rgba(255, 179, 0, 0.5)';\n ctx.shadowBlur = 8;\n ctx.fillStyle = '#FFB300';\n ctx.strokeStyle = '#FF8F00';\n ctx.lineWidth = 1.2;\n ctx.beginPath();\n ctx.arc(sx, sy, 6, 0, Math.PI * 2);\n ctx.fill();\n ctx.stroke();\n ctx.shadowBlur = 0;\n ctx.strokeStyle = 'rgba(255, 179, 0, 0.85)';\n ctx.lineWidth = 1.4;\n for (let a = 0; a < 360; a += 45) {\n const rad = (a * Math.PI) / 180;\n ctx.beginPath();\n ctx.moveTo(sx + 8 * Math.cos(rad), sy + 8 * Math.sin(rad));\n ctx.lineTo(sx + 12 * Math.cos(rad), sy + 12 * Math.sin(rad));\n ctx.stroke();\n }\n ctx.restore();\n\n const [moonLat, moonLon] = calculateSubLunarPoint(now);\n const mx = lonToX(moonLon, W), my = latToY(moonLat, H);\n ctx.save();\n ctx.shadowColor = 'rgba(224, 224, 224, 0.4)';\n ctx.shadowBlur = 6;\n ctx.fillStyle = '#e0e0e0';\n ctx.strokeStyle = '#9e9e9e';\n ctx.lineWidth = 0.8;\n ctx.beginPath();\n ctx.arc(mx, my, 5.5, 0, Math.PI * 2);\n ctx.fill();\n ctx.stroke();\n ctx.shadowBlur = 0;\n ctx.fillStyle = 'rgba(189, 189, 189, 0.5)';\n ctx.beginPath(); ctx.arc(mx - 1.5, my - 1, 1.4, 0, Math.PI * 2); ctx.fill();\n ctx.fillStyle = 'rgba(189, 189, 189, 0.4)';\n ctx.beginPath(); ctx.arc(mx + 2, my + 1.5, 0.9, 0, Math.PI * 2); ctx.fill();\n ctx.restore();\n }\n }\n\n // === World Map (land visible against ocean) ===\n ctx.fillStyle = COLORS.land;\n ctx.strokeStyle = 'rgba(100, 120, 160, 0.25)';\n ctx.lineWidth = 1;\n\n for (const pathStr of WORLD_MAP_PATHS) {\n const commands = pathStr.split(' ');\n ctx.beginPath();\n for (const cmd of commands) {\n if (cmd.startsWith('M') || cmd.startsWith('L')) {\n const coords = cmd.substring(1).split(',');\n const lon = parseFloat(coords[0]);\n const lat = parseFloat(coords[1]);\n const x = lonToX(lon, W);\n const y = latToY(lat, H);\n if (cmd.startsWith('M')) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n } else if (cmd === 'Z') {\n ctx.closePath();\n }\n }\n ctx.fill();\n ctx.stroke();\n }\n\n // === Grid ===\n if (showGrid) {\n ctx.strokeStyle = COLORS.grid;\n ctx.lineWidth = 0.4;\n for (let lon = -180; lon <= 180; lon += 30) {\n const x = lonToX(lon, W);\n ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke();\n }\n for (let lat = -90; lat <= 90; lat += 30) {\n const y = latToY(lat, H);\n ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke();\n }\n }\n\n // === Equator ===\n if (showEquator) {\n const eqY = latToY(0, H);\n ctx.strokeStyle = COLORS.equator;\n ctx.lineWidth = 1;\n ctx.setLineDash([6, 4]);\n ctx.beginPath(); ctx.moveTo(0, eqY); ctx.lineTo(W, eqY); ctx.stroke();\n ctx.setLineDash([]);\n }\n\n // === Ground Station Coverage Circles (latitude-corrected ellipses) ===\n for (const gs of groundStations) {\n const enhanced = gs as GroundStationEnhanced;\n if (enhanced.showCoverage && enhanced.coverageRadius) {\n const statusColor = STATUS_COLOR_MAP[enhanced.status || 'standby'] || STATUS_COLOR_MAP.standby;\n\n // Use the coverage radius as-is (in degrees) — caller can compute\n // from visibilityRadiusDeg() or provide a direct value\n drawCoverageEllipse(ctx, gs.latitude, gs.longitude, enhanced.coverageRadius, W, H, lonToX, latToY);\n ctx.fillStyle = `${statusColor}15`;\n ctx.fill();\n ctx.strokeStyle = `${statusColor}40`;\n ctx.lineWidth = 1;\n ctx.setLineDash([4, 3]);\n ctx.stroke();\n ctx.setLineDash([]);\n }\n }\n\n // === Ground Stations (Astro UX Icons + Status Badges) ===\n for (const gs of groundStations) {\n const enhanced = gs as GroundStationEnhanced;\n const x = lonToX(gs.longitude, W);\n const y = latToY(gs.latitude, H);\n const status = enhanced.status || 'standby';\n const statusColor = STATUS_COLOR_MAP[status] || STATUS_COLOR_MAP.standby;\n const stationType = enhanced.type || 'dish';\n const iconSize = 20;\n const halfIcon = iconSize / 2;\n\n ctx.save();\n ctx.translate(x, y);\n\n // -- Background circle (subtle glow) --\n ctx.beginPath();\n ctx.arc(0, 0, halfIcon + 2, 0, Math.PI * 2);\n ctx.fillStyle = `${statusColor}18`;\n ctx.fill();\n\n // -- Icon background pill --\n ctx.beginPath();\n ctx.arc(0, 0, halfIcon, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.85)';\n ctx.fill();\n ctx.strokeStyle = `${statusColor}66`;\n ctx.lineWidth = 1.5;\n ctx.stroke();\n\n // -- Draw Astro UX icon via SVG paths scaled to icon size --\n ctx.save();\n const iconScale = iconSize / 24;\n ctx.translate(-halfIcon, -halfIcon);\n ctx.scale(iconScale, iconScale);\n\n if (stationType === 'dish' || stationType === 'omni') {\n // Antenna icon (concentric arcs — Astro antenna pattern)\n ctx.strokeStyle = statusColor;\n ctx.fillStyle = statusColor;\n ctx.lineWidth = 2 / iconScale;\n // Outer arc\n ctx.beginPath(); ctx.arc(12, 12, 10, Math.PI * 1.25, Math.PI * 1.75); ctx.stroke();\n // Middle arc\n ctx.beginPath(); ctx.arc(12, 12, 6.5, Math.PI * 1.2, Math.PI * 1.8); ctx.stroke();\n // Inner arc\n ctx.beginPath(); ctx.arc(12, 12, 3, Math.PI * 1.15, Math.PI * 1.85); ctx.stroke();\n // Center dot (feed point)\n ctx.beginPath(); ctx.arc(12, 12, 1.5, 0, Math.PI * 2); ctx.fill();\n // Stand\n ctx.lineWidth = 1.5 / iconScale;\n ctx.beginPath(); ctx.moveTo(12, 14); ctx.lineTo(12, 20); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(8, 20); ctx.lineTo(16, 20); ctx.stroke();\n } else if (stationType === 'phased-array') {\n // Phased array icon (grid pattern)\n ctx.strokeStyle = statusColor;\n ctx.fillStyle = statusColor;\n ctx.lineWidth = 1.5 / iconScale;\n ctx.strokeRect(5, 4, 14, 12);\n // Grid lines\n for (let gx = 8; gx <= 16; gx += 4) {\n ctx.beginPath(); ctx.moveTo(gx, 4); ctx.lineTo(gx, 16); ctx.stroke();\n }\n for (let gy = 8; gy <= 12; gy += 4) {\n ctx.beginPath(); ctx.moveTo(5, gy); ctx.lineTo(19, gy); ctx.stroke();\n }\n // Stand\n ctx.beginPath(); ctx.moveTo(12, 16); ctx.lineTo(12, 21); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(8, 21); ctx.lineTo(16, 21); ctx.stroke();\n } else {\n // Relay: satellite dish with signal waves\n ctx.strokeStyle = statusColor;\n ctx.fillStyle = statusColor;\n ctx.lineWidth = 2 / iconScale;\n // Dish bowl\n ctx.beginPath(); ctx.arc(10, 12, 7, Math.PI * 0.8, Math.PI * 1.7); ctx.stroke();\n // Feed arm\n ctx.lineWidth = 1.5 / iconScale;\n ctx.beginPath(); ctx.moveTo(10, 12); ctx.lineTo(16, 6); ctx.stroke();\n // Signal waves\n ctx.lineWidth = 1.2 / iconScale;\n ctx.beginPath(); ctx.arc(17, 5, 2.5, Math.PI * 1.2, Math.PI * 1.7); ctx.stroke();\n ctx.beginPath(); ctx.arc(17, 5, 4.5, Math.PI * 1.15, Math.PI * 1.75); ctx.stroke();\n // Base\n ctx.lineWidth = 1.5 / iconScale;\n ctx.beginPath(); ctx.moveTo(10, 14); ctx.lineTo(10, 20); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(6, 20); ctx.lineTo(14, 20); ctx.stroke();\n }\n\n ctx.restore(); // icon scaling\n\n // -- Astro UX Status Badge (top-left of icon) --\n const badgeX = -halfIcon + 1;\n const badgeY = -halfIcon + 1;\n const badgeSize = 7;\n\n // Badge background ring\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 2 + 2, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.9)';\n ctx.fill();\n\n // Status shape per Astro UX spec (StatusIndicator.tsx canonical reference):\n // off → small filled dot, standby → ring (hollow circle),\n // normal → filled circle, caution → square,\n // serious → diamond, critical → triangle pointing DOWN\n ctx.fillStyle = statusColor;\n ctx.strokeStyle = statusColor;\n ctx.lineWidth = 1;\n if (status === 'normal') {\n // Filled circle for normal\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 2, 0, Math.PI * 2);\n ctx.fill();\n } else if (status === 'standby') {\n // Ring (hollow circle) for standby\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 2 - 0.5, 0, Math.PI * 2);\n ctx.lineWidth = 2;\n ctx.stroke();\n } else if (status === 'caution') {\n // Square for caution\n const hs = badgeSize / 2;\n ctx.fillRect(badgeX - hs, badgeY - hs, badgeSize, badgeSize);\n } else if (status === 'serious') {\n // Diamond for serious\n const hs = badgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(badgeX, badgeY - hs);\n ctx.lineTo(badgeX + hs, badgeY);\n ctx.lineTo(badgeX, badgeY + hs);\n ctx.lineTo(badgeX - hs, badgeY);\n ctx.closePath();\n ctx.fill();\n } else if (status === 'critical') {\n // Triangle pointing DOWN for critical\n const hs = badgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(badgeX, badgeY + hs); // bottom point\n ctx.lineTo(badgeX + hs, badgeY - hs); // top-right\n ctx.lineTo(badgeX - hs, badgeY - hs); // top-left\n ctx.closePath();\n ctx.fill();\n } else {\n // Off: small filled dot\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 3, 0, Math.PI * 2);\n ctx.fill();\n }\n\n ctx.restore();\n\n // Label\n ctx.fillStyle = COLORS.text;\n ctx.font = '9px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(gs.name.length > 14 ? gs.name.slice(0, 14) + '…' : gs.name, x, y + halfIcon + 12);\n }\n\n // === Light Sources (visible only on the night side of the terminator) ===\n if (lightSources && lightSources.length > 0 && showTerminator) {\n const now = terminatorTime ?? new Date();\n\n for (const light of lightSources) {\n const lx = lonToX(light.longitude, W);\n const ly = latToY(light.latitude, H);\n const r = light.radius ?? 4;\n const intensity = light.intensity ?? 0.8;\n const color = light.color ?? '#ffeedd';\n\n // Compute night factor: how deeply this point is inside the night zone.\n // We use the geometric terminator (0°) and astronomical (18°) as endpoints\n // for a 0→1 ramp.\n const dayOfYear = Math.floor((now.getTime() - Date.UTC(now.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n const lsSubSolarLon = -((now.getUTCHours() + now.getUTCMinutes() / 60) - 12) * 15;\n const latRad = (light.latitude * Math.PI) / 180;\n\n // Solar elevation angle at the light's position\n const sinAlt = Math.sin(latRad) * Math.sin(decRad) +\n Math.cos(latRad) * Math.cos(decRad) *\n Math.cos(((light.longitude - lsSubSolarLon) * Math.PI) / 180);\n const solarAltDeg = (Math.asin(sinAlt) * 180) / Math.PI;\n\n // Lights fade in: full day (alt > 0°) = invisible, deep night (alt < -18°) = full brightness\n let nightFactor: number;\n if (solarAltDeg >= 0) nightFactor = 0;\n else if (solarAltDeg <= -18) nightFactor = 1;\n else nightFactor = Math.min(1, -solarAltDeg / 18);\n\n if (nightFactor < 0.01) continue;\n\n const alpha = intensity * nightFactor;\n const [cr, cg, cb] = hexToRgb(color);\n const grad = ctx.createRadialGradient(lx, ly, 0, lx, ly, r * 2);\n grad.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, ${alpha})`);\n grad.addColorStop(0.4, `rgba(${cr}, ${cg}, ${cb}, ${alpha * 0.6})`);\n grad.addColorStop(1, `rgba(${cr}, ${cg}, ${cb}, 0)`);\n\n ctx.fillStyle = grad;\n ctx.beginPath();\n ctx.arc(lx, ly, r * 2, 0, Math.PI * 2);\n ctx.fill();\n\n // Bright core\n ctx.fillStyle = `rgba(${cr}, ${cg}, ${cb}, ${Math.min(1, alpha * 1.3)})`;\n ctx.beginPath();\n ctx.arc(lx, ly, Math.max(1, r * 0.4), 0, Math.PI * 2);\n ctx.fill();\n }\n }\n\n // === Satellite Tracks ===\n allSatellites.forEach((sat, satIdx) => {\n const track = sat.groundTrack;\n if (!track || track.length === 0) return;\n\n const trackColor = sat.color || DEFAULT_TRACK_COLORS[satIdx % DEFAULT_TRACK_COLORS.length];\n const futureIdx = sat.futureTrackIndex ?? track.length;\n\n // Draw past track (solid)\n ctx.strokeStyle = trackColor;\n ctx.lineWidth = 2;\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n ctx.setLineDash([]);\n ctx.beginPath();\n\n let prevX = lonToX(track[0].longitude, W);\n let prevY = latToY(track[0].latitude, H);\n ctx.moveTo(prevX, prevY);\n\n for (let i = 1; i < Math.min(futureIdx, track.length); i++) {\n const x = lonToX(track[i].longitude, W);\n const y = latToY(track[i].latitude, H);\n const crossesDateLine = Math.abs(x - prevX) > W / 2;\n if (crossesDateLine) {\n ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y);\n } else {\n ctx.lineTo(x, y);\n }\n prevX = x; prevY = y;\n }\n ctx.stroke();\n\n // Draw future track (dashed)\n if (futureIdx < track.length) {\n ctx.strokeStyle = `${trackColor}88`;\n ctx.lineWidth = 1.5;\n ctx.setLineDash([6, 4]);\n ctx.beginPath();\n ctx.moveTo(lonToX(track[futureIdx].longitude, W), latToY(track[futureIdx].latitude, H));\n let fpx = lonToX(track[futureIdx].longitude, W);\n\n for (let i = futureIdx + 1; i < track.length; i++) {\n const x = lonToX(track[i].longitude, W);\n const y = latToY(track[i].latitude, H);\n if (Math.abs(x - fpx) > W / 2) {\n ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y);\n } else {\n ctx.lineTo(x, y);\n }\n fpx = x;\n }\n ctx.stroke();\n ctx.setLineDash([]);\n }\n\n // Draw access segments (contact passes)\n if (sat.accessMask && sat.accessMask.some(Boolean)) {\n ctx.strokeStyle = STATUS_COLOR_MAP.normal;\n ctx.lineWidth = 3;\n ctx.setLineDash([]);\n ctx.beginPath();\n let drawing = false;\n let apx = lonToX(track[0].longitude, W);\n\n for (let i = 0; i < track.length; i++) {\n const x = lonToX(track[i].longitude, W);\n const y = latToY(track[i].latitude, H);\n const active = sat.accessMask[i];\n const crossesDateLine = i > 0 && Math.abs(x - apx) > W / 2;\n\n if (active && !crossesDateLine) {\n if (!drawing) { ctx.moveTo(x, y); drawing = true; }\n else ctx.lineTo(x, y);\n } else {\n if (drawing) { ctx.stroke(); ctx.beginPath(); drawing = false; }\n }\n apx = x;\n }\n if (drawing) ctx.stroke();\n }\n\n // AOS/LOS markers\n if (sat.passMarkers) {\n for (const marker of sat.passMarkers) {\n const mx = lonToX(marker.longitude, W);\n const my = latToY(marker.latitude, H);\n const markerColor = marker.type === 'aos' ? STATUS_COLOR_MAP.normal : STATUS_COLOR_MAP.critical;\n\n ctx.save();\n ctx.translate(mx, my);\n // Triangle marker\n ctx.beginPath();\n if (marker.type === 'aos') {\n ctx.moveTo(0, -6); ctx.lineTo(4, 2); ctx.lineTo(-4, 2);\n } else {\n ctx.moveTo(0, 6); ctx.lineTo(4, -2); ctx.lineTo(-4, -2);\n }\n ctx.closePath();\n ctx.fillStyle = markerColor;\n ctx.fill();\n ctx.restore();\n\n if (marker.label) {\n ctx.fillStyle = markerColor;\n ctx.font = '8px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(marker.label, mx, marker.type === 'aos' ? my - 9 : my + 13);\n }\n }\n }\n\n // Satellite footprint (latitude-corrected ellipse)\n if (sat.showFootprint && sat.footprintRadius) {\n const lastPt = futureIdx > 0 ? track[Math.min(futureIdx - 1, track.length - 1)] : track[track.length - 1];\n\n drawCoverageEllipse(ctx, lastPt.latitude, lastPt.longitude, sat.footprintRadius, W, H, lonToX, latToY);\n ctx.fillStyle = `${trackColor}12`;\n ctx.fill();\n ctx.strokeStyle = `${trackColor}50`;\n ctx.lineWidth = 1;\n ctx.setLineDash([3, 3]);\n ctx.stroke();\n ctx.setLineDash([]);\n }\n\n // Current position satellite icon (Astro UX style)\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, track.length - 1) : track.length - 1;\n const current = track[currentIdx];\n const cx = lonToX(current.longitude, W);\n const cy = latToY(current.latitude, H);\n const satStatus = sat.status || 'normal';\n const statusColor = STATUS_COLOR_MAP[satStatus] || STATUS_COLOR_MAP.normal;\n const satIconSize = 22;\n const satHalf = satIconSize / 2;\n\n // Outer pulsing glow\n ctx.beginPath();\n ctx.arc(cx, cy, satHalf + 6, 0, Math.PI * 2);\n ctx.fillStyle = `${statusColor}12`;\n ctx.fill();\n\n ctx.beginPath();\n ctx.arc(cx, cy, satHalf + 3, 0, Math.PI * 2);\n ctx.fillStyle = `${statusColor}20`;\n ctx.fill();\n\n // Icon background\n ctx.save();\n ctx.translate(cx, cy);\n\n ctx.beginPath();\n ctx.arc(0, 0, satHalf, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.88)';\n ctx.fill();\n ctx.strokeStyle = `${statusColor}88`;\n ctx.lineWidth = 1.5;\n ctx.stroke();\n\n // Draw satellite shape (body + solar panels)\n ctx.fillStyle = statusColor;\n // Body (rounded rect approximation)\n const bw = 5, bh = 3.5;\n ctx.beginPath();\n ctx.moveTo(-bw / 2 + 0.5, -bh / 2);\n ctx.lineTo(bw / 2 - 0.5, -bh / 2);\n ctx.arcTo(bw / 2, -bh / 2, bw / 2, -bh / 2 + 0.5, 0.5);\n ctx.lineTo(bw / 2, bh / 2 - 0.5);\n ctx.arcTo(bw / 2, bh / 2, bw / 2 - 0.5, bh / 2, 0.5);\n ctx.lineTo(-bw / 2 + 0.5, bh / 2);\n ctx.arcTo(-bw / 2, bh / 2, -bw / 2, bh / 2 - 0.5, 0.5);\n ctx.lineTo(-bw / 2, -bh / 2 + 0.5);\n ctx.arcTo(-bw / 2, -bh / 2, -bw / 2 + 0.5, -bh / 2, 0.5);\n ctx.closePath();\n ctx.fill();\n\n // Solar panel left\n ctx.fillStyle = `${statusColor}BB`;\n ctx.fillRect(-satHalf + 2, -2, 5, 4);\n // Panel lines\n ctx.strokeStyle = `${statusColor}55`;\n ctx.lineWidth = 0.5;\n ctx.beginPath();\n ctx.moveTo(-satHalf + 4.5, -2); ctx.lineTo(-satHalf + 4.5, 2);\n ctx.stroke();\n\n // Solar panel right\n ctx.fillStyle = `${statusColor}BB`;\n ctx.fillRect(satHalf - 7, -2, 5, 4);\n ctx.strokeStyle = `${statusColor}55`;\n ctx.beginPath();\n ctx.moveTo(satHalf - 4.5, -2); ctx.lineTo(satHalf - 4.5, 2);\n ctx.stroke();\n\n // Panel connectors\n ctx.strokeStyle = statusColor;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(-bw / 2, 0); ctx.lineTo(-satHalf + 7, 0);\n ctx.moveTo(bw / 2, 0); ctx.lineTo(satHalf - 7, 0);\n ctx.stroke();\n\n // -- Astro UX Status Badge (top-left of satellite icon) --\n // Shapes per canonical StatusIndicator.tsx:\n // off → small dot, standby → ring, normal → filled circle,\n // caution → square, serious → diamond, critical → triangle DOWN\n const satBadgeX = -satHalf + 2;\n const satBadgeY = -satHalf + 2;\n const satBadgeSize = 7;\n\n // Badge background\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 2 + 2, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.9)';\n ctx.fill();\n\n ctx.fillStyle = statusColor;\n ctx.strokeStyle = statusColor;\n ctx.lineWidth = 1;\n if (satStatus === 'normal') {\n // Filled circle\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 2, 0, Math.PI * 2);\n ctx.fill();\n } else if (satStatus === 'standby') {\n // Ring (hollow circle)\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 2 - 0.5, 0, Math.PI * 2);\n ctx.lineWidth = 2;\n ctx.stroke();\n } else if (satStatus === 'caution') {\n const hs = satBadgeSize / 2;\n ctx.fillRect(satBadgeX - hs, satBadgeY - hs, satBadgeSize, satBadgeSize);\n } else if (satStatus === 'serious') {\n // Diamond\n const hs = satBadgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(satBadgeX, satBadgeY - hs);\n ctx.lineTo(satBadgeX + hs, satBadgeY);\n ctx.lineTo(satBadgeX, satBadgeY + hs);\n ctx.lineTo(satBadgeX - hs, satBadgeY);\n ctx.closePath();\n ctx.fill();\n } else if (satStatus === 'critical') {\n // Triangle pointing DOWN\n const hs = satBadgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(satBadgeX, satBadgeY + hs); // bottom point\n ctx.lineTo(satBadgeX + hs, satBadgeY - hs); // top-right\n ctx.lineTo(satBadgeX - hs, satBadgeY - hs); // top-left\n ctx.closePath();\n ctx.fill();\n } else {\n // Off: small filled dot\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 3, 0, Math.PI * 2);\n ctx.fill();\n }\n\n ctx.restore();\n\n // Satellite label\n ctx.fillStyle = '#fff';\n ctx.font = 'bold 10px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(sat.name, cx, cy - satHalf - 6);\n });\n\n // === Legend ===\n if (showLegend && (allSatellites.length > 0 || groundStations.length > 0)) {\n const legendX = 10;\n const legendY = 10;\n const lineHeight = 14;\n const items: Array<{ color: string; label: string; dash?: boolean }> = [];\n\n allSatellites.forEach((sat, idx) => {\n const c = sat.color || DEFAULT_TRACK_COLORS[idx % DEFAULT_TRACK_COLORS.length];\n items.push({ color: c, label: sat.name });\n });\n if (groundStations.length > 0) {\n items.push({ color: STATUS_COLOR_MAP.standby, label: `${groundStations.length} Ground Station${groundStations.length > 1 ? 's' : ''}` });\n }\n\n const maxLabelWidth = Math.max(...items.map(item => ctx.measureText(item.label).width)) + 28;\n const legendH = items.length * lineHeight + 10;\n\n ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';\n ctx.strokeStyle = 'rgba(100, 116, 139, 0.3)';\n ctx.lineWidth = 1;\n const r = 4;\n ctx.beginPath();\n ctx.moveTo(legendX + r, legendY);\n ctx.lineTo(legendX + maxLabelWidth - r, legendY);\n ctx.arcTo(legendX + maxLabelWidth, legendY, legendX + maxLabelWidth, legendY + r, r);\n ctx.lineTo(legendX + maxLabelWidth, legendY + legendH - r);\n ctx.arcTo(legendX + maxLabelWidth, legendY + legendH, legendX + maxLabelWidth - r, legendY + legendH, r);\n ctx.lineTo(legendX + r, legendY + legendH);\n ctx.arcTo(legendX, legendY + legendH, legendX, legendY + legendH - r, r);\n ctx.lineTo(legendX, legendY + r);\n ctx.arcTo(legendX, legendY, legendX + r, legendY, r);\n ctx.closePath();\n ctx.fill();\n ctx.stroke();\n\n items.forEach((item, i) => {\n const iy = legendY + 8 + i * lineHeight;\n // Color swatch\n ctx.fillStyle = item.color;\n ctx.beginPath();\n ctx.arc(legendX + 10, iy + 3, 4, 0, Math.PI * 2);\n ctx.fill();\n // Label\n ctx.fillStyle = 'rgba(255, 255, 255, 0.85)';\n ctx.font = '10px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'left';\n ctx.fillText(item.label, legendX + 20, iy + 7);\n });\n }\n\n // === Pins (read-only on canvas backend) ===\n if (pins && pins.length > 0) {\n pins.forEach((pin) => {\n const px = lonToX(pin.longitude, W);\n const py = latToY(pin.latitude, H);\n const pinColor = pin.color || tokens.colors.accent.primary;\n\n // Drop shadow\n ctx.save();\n ctx.shadowColor = 'rgba(0,0,0,0.4)';\n ctx.shadowBlur = 6;\n ctx.shadowOffsetY = 2;\n\n // Pin body: inverted teardrop shape\n ctx.beginPath();\n ctx.arc(px, py - 10, 6, Math.PI, 0);\n ctx.lineTo(px, py);\n ctx.closePath();\n ctx.fillStyle = pinColor;\n ctx.fill();\n ctx.restore();\n\n // Inner dot\n ctx.beginPath();\n ctx.arc(px, py - 10, 2.5, 0, Math.PI * 2);\n ctx.fillStyle = '#0d1323';\n ctx.fill();\n\n // Label\n if (pin.label) {\n ctx.fillStyle = 'rgba(255,255,255,0.9)';\n ctx.font = '10px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(pin.label, px, py - 20);\n }\n });\n }\n\n // === No Data Message ===\n if (allSatellites.length === 0 && groundStations.length === 0 && (!pins || pins.length === 0)) {\n ctx.fillStyle = COLORS.text;\n ctx.font = '12px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(emptyMessage, W / 2, H / 2);\n }\n }, [allSatellites, groundStations, height, showTerminator, terminatorTime, showGrid, showLegend, showEquator, lonToX, latToY, COLORS, emptyMessage, pins, lightSources, tokens.colors.accent.primary]);\n\n // Tooltip on mouse move\n const handleMouseMove = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const rect = canvas.getBoundingClientRect();\n const mx = e.clientX - rect.left;\n const my = e.clientY - rect.top;\n const W = rect.width;\n const H = typeof height === 'number' ? height : rect.height;\n\n // Check satellite positions\n for (const sat of allSatellites) {\n if (!sat.groundTrack.length) continue;\n const futureIdx = sat.futureTrackIndex ?? sat.groundTrack.length;\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, sat.groundTrack.length - 1) : sat.groundTrack.length - 1;\n const lastPt = sat.groundTrack[currentIdx];\n const sx = lonToX(lastPt.longitude, W);\n const sy = latToY(lastPt.latitude, H);\n const dist = Math.sqrt((mx - sx) ** 2 + (my - sy) ** 2);\n if (dist < 18) {\n const satStatus = sat.status || 'normal';\n setTooltip({\n x: e.clientX - rect.left + 15,\n y: e.clientY - rect.top - 10,\n type: 'satellite',\n name: sat.name,\n status: satStatus,\n statusColor: STATUS_COLOR_MAP[satStatus] || STATUS_COLOR_MAP.normal,\n lat: lastPt.latitude,\n lon: lastPt.longitude,\n alt: lastPt.altitude,\n trackColor: sat.color || DEFAULT_TRACK_COLORS[allSatellites.indexOf(sat) % DEFAULT_TRACK_COLORS.length],\n hasFootprint: sat.showFootprint,\n futurePoints: sat.groundTrack.length - futureIdx,\n pastPoints: futureIdx,\n });\n return;\n }\n }\n\n // Check ground stations\n for (const gs of groundStations) {\n const gx = lonToX(gs.longitude, W);\n const gy = latToY(gs.latitude, H);\n const dist = Math.sqrt((mx - gx) ** 2 + (my - gy) ** 2);\n if (dist < 16) {\n const enhanced = gs as GroundStationEnhanced;\n const gsStatus = enhanced.status || 'standby';\n setTooltip({\n x: e.clientX - rect.left + 15,\n y: e.clientY - rect.top - 10,\n type: 'station',\n name: gs.name,\n status: gsStatus,\n statusColor: STATUS_COLOR_MAP[gsStatus] || STATUS_COLOR_MAP.standby,\n lat: gs.latitude,\n lon: gs.longitude,\n stationType: enhanced.type || 'dish',\n network: ('network' in gs && gs.network) ? String(gs.network) : undefined,\n coverageRadius: enhanced.coverageRadius,\n });\n return;\n }\n }\n\n setTooltip(null);\n }, [allSatellites, groundStations, height, lonToX, latToY]);\n\n const handleClick = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const rect = canvas.getBoundingClientRect();\n const mx = e.clientX - rect.left;\n const my = e.clientY - rect.top;\n const W = rect.width;\n const H = typeof height === 'number' ? height : rect.height;\n\n for (const sat of allSatellites) {\n if (!sat.groundTrack.length) continue;\n const futureIdx = sat.futureTrackIndex ?? sat.groundTrack.length;\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, sat.groundTrack.length - 1) : sat.groundTrack.length - 1;\n const currentPt = sat.groundTrack[currentIdx];\n const sx = lonToX(currentPt.longitude, W);\n const sy = latToY(currentPt.latitude, H);\n if (Math.sqrt((mx - sx) ** 2 + (my - sy) ** 2) < 15) {\n onSatelliteClick?.(sat.id);\n return;\n }\n }\n\n for (const gs of groundStations) {\n const gx = lonToX(gs.longitude, W);\n const gy = latToY(gs.latitude, H);\n if (Math.sqrt((mx - gx) ** 2 + (my - gy) ** 2) < 12) {\n onStationClick?.('id' in gs ? gs.id : gs.name);\n return;\n }\n }\n }, [allSatellites, groundStations, height, lonToX, latToY, onSatelliteClick, onStationClick]);\n\n useEffect(() => {\n draw();\n window.addEventListener('resize', draw);\n return () => window.removeEventListener('resize', draw);\n }, [draw]);\n\n // Leaflet backend: return after all hooks so hook count is stable\n const resolvedMinHeightForLeaflet = minHeight || (typeof height === 'number' ? `${height}px` : '400px');\n\n if (mapProvider === 'leaflet') {\n if (LeafletMap) {\n return (\n <div\n role=\"img\"\n aria-label={allSatellites.length > 0 || groundStations.length > 0 ? 'Ground track map showing satellite tracks and ground stations' : 'Ground track map'}\n style={{\n display: 'block',\n width: width ?? '100%',\n height: typeof height === 'string' ? height : undefined,\n minHeight: resolvedMinHeightForLeaflet,\n }}\n >\n <LeafletMap\n allSatellites={allSatellites}\n groundStations={groundStations}\n showTerminator={showTerminator}\n terminatorTime={terminatorTime}\n showGrid={showGrid}\n showLegend={showLegend}\n showEquator={showEquator}\n showRecenterButton={showRecenterButton}\n showMapStyleToggle={showMapStyleToggle}\n defaultCenter={leafletDefaultCenter}\n defaultZoom={leafletDefaultZoom}\n height={height}\n width={width}\n minHeight={minHeight}\n emptyMessage={emptyMessage}\n tileUrl={tileUrl}\n nightTileUrl={nightTileUrl}\n lightSources={lightSources}\n className={className}\n onSatelliteClick={onSatelliteClick}\n onStationClick={onStationClick}\n pins={pins}\n pinsEditable={pinsEditable}\n onPinAdd={onPinAdd}\n onPinUpdate={onPinUpdate}\n onPinRemove={onPinRemove}\n customLayers={customLayers}\n onLayerChange={onLayerChange}\n showCelestialMarkers={showCelestialMarkers}\n />\n </div>\n );\n }\n if (!leafletFailed) {\n return (\n <div\n className={`zendir-ground-track-map ${className}`}\n style={{\n width,\n height: typeof height === 'string' ? height : undefined,\n minHeight: resolvedMinHeightForLeaflet,\n backgroundColor: tokens.colors.background.base,\n borderRadius: 8,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ color: tokens.colors.text.secondary, fontSize: 14 }}>Loading map…</span>\n </div>\n );\n }\n }\n\n const resolvedMinHeight = minHeight || (typeof height === 'number' ? `${height}px` : '400px');\n\n // Loading state\n if (isLoading) {\n return (\n <div\n className={`zendir-ground-track-map ${className}`}\n style={{\n width,\n minHeight: resolvedMinHeight,\n backgroundColor: COLORS.background,\n borderRadius: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ color: COLORS.text, fontSize: '14px', letterSpacing: '1px' }}>Loading…</span>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n role=\"img\"\n aria-label={allSatellites.length > 0 || groundStations.length > 0 ? 'Ground track map showing satellite tracks and ground stations' : 'Ground track map'}\n className={`zendir-ground-track-map ${className}`}\n style={{ width, height: typeof height === 'string' ? height : undefined, minHeight: resolvedMinHeight, backgroundColor: COLORS.background, borderRadius: '8px', overflow: 'hidden', position: 'relative' }}\n data-map-backend=\"canvas\"\n >\n {/* Hint when Leaflet was requested but failed (e.g. leaflet not installed) */}\n {mapProvider === 'leaflet' && leafletFailed && (\n <div\n style={{\n position: 'absolute',\n bottom: 8,\n left: 8,\n zIndex: 100,\n padding: '4px 8px',\n background: 'rgba(0,0,0,0.75)',\n color: '#fce83a',\n fontSize: 11,\n borderRadius: 4,\n }}\n >\n Static view (install <code style={{ fontFamily: 'monospace' }}>leaflet</code> for zoom/pan)\n </div>\n )}\n {/* Recenter button (SRO compat) */}\n {showRecenterButton && (\n <button\n type=\"button\"\n onClick={handleRecenter}\n title=\"Recenter Map\"\n aria-label=\"Recenter map\"\n style={{\n position: 'absolute',\n top: '8px',\n right: '8px',\n zIndex: 20,\n background: 'rgba(30, 41, 59, 0.85)',\n border: '1px solid rgba(100, 116, 139, 0.4)',\n borderRadius: '4px',\n color: '#fff',\n cursor: 'pointer',\n padding: '4px 8px',\n fontSize: '12px',\n lineHeight: '1',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M12 2v4M12 18v4M2 12h4M18 12h4\" />\n </svg>\n </button>\n )}\n\n <canvas\n ref={canvasRef}\n style={{ display: 'block', cursor: tooltip ? 'pointer' : 'default' }}\n onMouseMove={handleMouseMove}\n onMouseLeave={() => setTooltip(null)}\n onClick={handleClick}\n />\n {tooltip && (\n <div\n style={{\n position: 'absolute',\n left: tooltip.x,\n top: tooltip.y,\n background: 'rgba(15, 23, 42, 0.95)',\n backdropFilter: 'blur(8px)',\n border: `1px solid ${tooltip.statusColor}40`,\n borderRadius: '8px',\n padding: 0,\n pointerEvents: 'none',\n zIndex: 10,\n color: 'rgba(255, 255, 255, 0.9)',\n fontSize: '11px',\n fontFamily: '\"Inter\", system-ui, sans-serif',\n lineHeight: '1.5',\n boxShadow: `0 4px 16px rgba(0, 0, 0, 0.5), 0 0 12px ${tooltip.statusColor}15`,\n minWidth: 180,\n overflow: 'hidden',\n }}\n >\n {/* Header with status accent */}\n <div style={{\n padding: '6px 10px',\n borderBottom: `1px solid ${tooltip.statusColor}25`,\n background: `${tooltip.statusColor}10`,\n display: 'flex', alignItems: 'center', gap: 6,\n }}>\n <span style={{\n width: 8, height: 8, borderRadius: tooltip.status === 'caution' ? 1 : '50%',\n background: tooltip.statusColor, display: 'inline-block', flexShrink: 0,\n boxShadow: `0 0 4px ${tooltip.statusColor}88`,\n }} />\n <span style={{ fontWeight: 600, fontSize: 12 }}>{tooltip.name}</span>\n <span style={{\n marginLeft: 'auto', fontSize: 9, fontWeight: 600, textTransform: 'uppercase',\n color: tooltip.statusColor, letterSpacing: '0.5px',\n }}>\n {tooltip.status}\n </span>\n </div>\n {/* Details */}\n <div style={{ padding: '6px 10px', display: 'flex', flexDirection: 'column', gap: 3 }}>\n {/* Type badge */}\n <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>\n <span style={{\n fontSize: 9, fontWeight: 600, padding: '1px 5px',\n borderRadius: 3, textTransform: 'uppercase', letterSpacing: '0.3px',\n background: tooltip.type === 'satellite' ? 'rgba(45, 204, 255, 0.15)' : 'rgba(86, 240, 0, 0.15)',\n color: tooltip.type === 'satellite' ? '#2dccff' : '#56f000',\n }}>\n {tooltip.type === 'satellite' ? (\n <>\n <AstroIcon name=\"satellite\" size=\"extra-small\" label=\"Satellite\" style={{ marginRight: 4, verticalAlign: 'middle' }} />\n Satellite\n </>\n ) : (\n <>\n <AstroIcon name=\"antenna\" size=\"extra-small\" label={tooltip.stationType || 'Ground station'} style={{ marginRight: 4, verticalAlign: 'middle' }} />\n {tooltip.stationType || 'dish'}\n </>\n )}\n </span>\n {tooltip.network && (\n <span style={{\n fontSize: 9, padding: '1px 5px', borderRadius: 3,\n background: 'rgba(157, 112, 255, 0.15)', color: '#9D70FF',\n }}>\n {tooltip.network}\n </span>\n )}\n </div>\n {/* Coordinates */}\n <div style={{ display: 'grid', gridTemplateColumns: '52px 1fr', gap: '2px 8px', fontSize: 10 }}>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Lat</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.lat >= 0 ? '+' : ''}{tooltip.lat.toFixed(4)}°\n </span>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Lon</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.lon >= 0 ? '+' : ''}{tooltip.lon.toFixed(4)}°\n </span>\n {tooltip.alt !== undefined && (\n <>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Altitude</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.alt.toFixed(1)} km\n </span>\n </>\n )}\n {tooltip.coverageRadius !== undefined && (\n <>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Coverage</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.coverageRadius.toFixed(1)}° radius\n </span>\n </>\n )}\n </div>\n {/* Satellite extras */}\n {tooltip.type === 'satellite' && (tooltip.pastPoints !== undefined || tooltip.futurePoints !== undefined) && (\n <div style={{ marginTop: 3, paddingTop: 3, borderTop: '1px solid rgba(255,255,255,0.08)', display: 'flex', gap: 10, fontSize: 9 }}>\n {tooltip.pastPoints !== undefined && (\n <span><span style={{ color: tooltip.trackColor }}>━</span> {tooltip.pastPoints} past pts</span>\n )}\n {tooltip.futurePoints !== undefined && tooltip.futurePoints > 0 && (\n <span><span style={{ color: `${tooltip.trackColor}88` }}>╌</span> {tooltip.futurePoints} predicted</span>\n )}\n {tooltip.hasFootprint && <span style={{ color: '#9D70FF' }}>◎ Footprint</span>}\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport default GroundTrackMap;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GroundTrackMap.js","sources":["../../../src/react/charts/GroundTrackMap.tsx"],"sourcesContent":["/**\n * @zendir/ui - GroundTrackMap Component (Enhanced)\n * \n * Full-featured 2D world map showing spacecraft ground tracks, current positions,\n * ground station locations, coverage footprints, satellite icons, and day/night terminator.\n * \n * Inspired by Astro UXDS TT&C Monitor / GRM Dashboard ground map patterns:\n * - Satellite icons with status-colored indicators (not just dots)\n * - Ground station antenna icons with coverage circles\n * - Sensor/antenna footprint cone projections\n * - Future orbit tracks (dashed) vs past tracks (solid)\n * - Day/night terminator\n * - Multi-satellite support\n * - Interactive hover tooltips\n * - AOS/LOS markers on track\n * - Legend with satellite/station counts\n * \n * Astro UX Compliance:\n * - Theme-integrated via useTheme()\n * - Uses official Astro status colors from theme tokens\n * - Uses Astro monitoring icon patterns\n * - 14pt minimum for labels (AstroUXDS guideline)\n * - Consistent with Astro data visualization patterns\n */\n\nimport React, { useRef, useEffect, useCallback, useMemo, useState } from 'react';\nimport { useTheme } from '../theme';\nimport { AstroIcon } from '../core/AstroIcon';\nimport type { GroundTrackPoint, GroundStation } from '../types';\nimport type { GroundTrackMapLeafletProps } from './GroundTrackMapLeaflet';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SatelliteTrack {\n /** Unique satellite identifier */\n id: string;\n /** Satellite display name */\n name: string;\n /** Ground track points */\n groundTrack: GroundTrackPoint[];\n /** Track color */\n color?: string;\n /** Satellite status for icon coloring */\n status?: 'normal' | 'caution' | 'serious' | 'critical' | 'standby' | 'off';\n /** Access mask (true = in contact) */\n accessMask?: boolean[];\n /** Show this satellite's sensor footprint */\n showFootprint?: boolean;\n /** Footprint radius in degrees (sensor cone half-angle on ground) */\n footprintRadius?: number;\n /** Show future (predicted) track as dashed line */\n futureTrackIndex?: number;\n /** AOS/LOS markers */\n passMarkers?: Array<{ type: 'aos' | 'los'; latitude: number; longitude: number; label?: string }>;\n}\n\nexport interface GroundStationEnhanced extends GroundStation {\n /** Station status */\n status?: 'normal' | 'caution' | 'serious' | 'critical' | 'standby' | 'off';\n /** Show coverage circle */\n showCoverage?: boolean;\n /** Coverage radius in degrees (visibility horizon) */\n coverageRadius?: number;\n /** Station type (affects icon) */\n type?: 'dish' | 'phased-array' | 'omni' | 'relay';\n}\n\n/** \n * SRO-compatible team path format (space-range-operator CustomMap data shape).\n * Provide this as an alternative to `satellites` for plug-and-play compatibility.\n */\nexport interface TeamPath {\n /** Team/satellite name */\n name: string;\n /** Track color */\n color?: string;\n /** Ordered position array */\n positions: Array<{\n lat: number;\n lng: number;\n time?: number;\n altitude?: number | null;\n }>;\n}\n\n/** SRO-compatible ground station format */\nexport interface SROGroundStation {\n name: string;\n latitude: number;\n longitude: number;\n altitude?: number | null;\n}\n\n/**\n * User-placed point-of-interest pin on the map.\n * Designed for collaborative scenarios where operators share annotated locations\n * across terminals in real time (e.g. targets, waypoints, hazard markers).\n */\nexport interface MapPin {\n /** Unique identifier (used as key and for update/remove callbacks) */\n id: string;\n /** Latitude in degrees (−90 … 90) */\n latitude: number;\n /** Longitude in degrees (−180 … 180) */\n longitude: number;\n /** Short label displayed next to the pin (e.g. \"Target Alpha\") */\n label?: string;\n /** Pin color — any CSS color string. Defaults to accent primary. */\n color?: string;\n /** Optional description shown in tooltip on hover */\n description?: string;\n /** Who placed the pin (display-only; not enforced) */\n createdBy?: string;\n}\n\n/**\n * A point light source rendered on the night side of the map.\n * Use this to display city lights, base locations, RF emitters,\n * or any glow that should only be visible after sunset.\n *\n * Light sources are masked by the terminator — they fade in\n * through the twilight gradient and reach full brightness in\n * deep night, matching real-world light-pollution behavior.\n */\nexport interface LightSource {\n /** Latitude in degrees (−90 … 90) */\n latitude: number;\n /** Longitude in degrees (−180 … 180) */\n longitude: number;\n /** Glow radius in pixels (default 4). Larger values create wider halos. */\n radius?: number;\n /** Glow intensity 0–1 (default 0.8). Controls the peak alpha of the light dot. */\n intensity?: number;\n /** Light color — any CSS color string (default '#ffeedd', warm white). */\n color?: string;\n /** Optional label shown on hover (Leaflet) or in tooltip (Canvas). */\n label?: string;\n}\n\n/**\n * Developer-defined map layer shown in the Layers panel.\n * The GroundTrackMap does not render the layer content — it only provides\n * the toggle UI. The consumer app should listen to `onLayerChange` and\n * render/hide its own overlay accordingly.\n */\nexport interface MapLayerDef {\n /** Unique identifier for the layer (e.g. 'heatmap', 'coverage') */\n id: string;\n /** Display label in the Layers panel */\n label: string;\n /** Whether the layer is on by default (default true) */\n defaultEnabled?: boolean;\n}\n\nexport interface GroundTrackMapProps {\n /** Single satellite ground track (legacy API) */\n groundTrack?: GroundTrackPoint[];\n /** Multiple satellite tracks */\n satellites?: SatelliteTrack[];\n /** Ground stations to display */\n groundStations?: (GroundStation | GroundStationEnhanced | SROGroundStation)[];\n /** Access mask for single-satellite mode (legacy API) */\n accessMask?: boolean[];\n\n // --- SRO-compatible alternate API (space-range-operator plug-and-play) ---\n /** Team path data (SRO CustomMap format) — auto-converts to satellites internally */\n teamPaths?: TeamPath[];\n\n // --- Display options ---\n /** Show day/night terminator */\n showTerminator?: boolean;\n /** Override the time used for the day/night terminator calculation.\n * Defaults to wall-clock `new Date()` when omitted.\n * Pass a simulation/mission UTC to keep the terminator in sync with a sim clock. */\n terminatorTime?: Date;\n /** Show grid lines */\n showGrid?: boolean;\n /** Show legend */\n showLegend?: boolean;\n /** Show equator highlight */\n showEquator?: boolean;\n /** Show recenter button (SRO compat) */\n showRecenterButton?: boolean;\n /** Show a toggle button to switch between Dark and Satellite tile styles. Default true for Leaflet. */\n showMapStyleToggle?: boolean;\n\n // --- State ---\n /** Whether data is still loading (SRO compat) */\n isLoading?: boolean;\n /** Message when there is no data (SRO compat) */\n emptyMessage?: string;\n\n // --- Sizing ---\n /** Chart width (default: 100%) */\n width?: number | string;\n /** Chart height — number for fixed px, or CSS string like '100%' to fill a flex parent */\n height?: number | string;\n /** Minimum height CSS string (SRO compat, e.g. \"400px\") */\n minHeight?: string;\n\n // --- Centering ---\n /** Default center [lat, lon] (SRO compat) */\n defaultCenter?: [number, number];\n /** Default zoom level 1-10 (SRO compat, affects initial scale) */\n defaultZoom?: number;\n\n /** Custom className */\n className?: string;\n /** Click handler for satellites */\n onSatelliteClick?: (satelliteId: string) => void;\n /** Click handler for ground stations */\n onStationClick?: (stationId: string) => void;\n\n /** Map backend: 'leaflet' (default, requires leaflet peer) or 'canvas' */\n mapProvider?: 'leaflet' | 'canvas';\n /** Tile URL for Leaflet (default: CartoDB dark). Ignored when mapProvider is 'canvas'. */\n tileUrl?: string;\n\n // --- Day/Night Tile Masking (Leaflet only) ---\n /**\n * URL template for a \"night\" tile layer (e.g. NASA Black Marble, VIIRS city lights).\n * When provided, this layer is rendered beneath the terminator overlay so that it\n * appears only on the night side of the map — creating a realistic day/night transition.\n * The day tiles remain visible on the sunlit side.\n *\n * Requires `showTerminator` to be enabled. Leaflet backend only.\n *\n * Example: `'https://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_CityLights_2012/...'`\n */\n nightTileUrl?: string;\n\n // --- Dynamic Light Sources ---\n /**\n * Array of point light sources rendered on the night side of the map.\n * Each light appears as a soft glow dot that is masked by the terminator —\n * invisible in daylight, fading in through twilight, full brightness at night.\n *\n * Use cases: city lights, base indicators, RF emitters, targets, population centers.\n */\n lightSources?: LightSource[];\n\n // --- Collaborative Pins (Points of Interest) ---\n /** Array of user-placed pins displayed on the map */\n pins?: MapPin[];\n /**\n * Allow operators to place new pins by clicking the map.\n * When true, a single-click on an empty area opens a pin creation flow.\n * Requires `onPinAdd` to be set. Default false.\n */\n pinsEditable?: boolean;\n /** Called when the user places a new pin (provides lat/lon; consumer assigns id and persists) */\n onPinAdd?: (pin: Omit<MapPin, 'id'>) => void;\n /** Called when the user edits an existing pin (label, color, description change) */\n onPinUpdate?: (pin: MapPin) => void;\n /** Called when the user removes a pin */\n onPinRemove?: (pinId: string) => void;\n\n // --- Layers Panel ---\n /**\n * Custom overlay layers shown in the Layers panel dropdown.\n * Each layer gets a toggle switch. The GroundTrackMap does NOT render\n * the layer content — it only provides the toggle UI.\n * Listen to `onLayerChange` for state updates and render your own overlays.\n */\n customLayers?: MapLayerDef[];\n /**\n * Called when any layer is toggled (built-in or custom).\n * `layerId` is one of: 'terminator', 'grid', or a custom layer id.\n * `enabled` is the new toggle state.\n */\n onLayerChange?: (layerId: string, enabled: boolean) => void;\n\n /**\n * Show sun and moon position markers on the map.\n * Requires `showTerminator`. Default: true when terminator is enabled.\n */\n showCelestialMarkers?: boolean;\n}\n\n// =============================================================================\n// Constants — aligned with official Astro UXDS status colors\n// These MUST match the STATUS_COLORS in unified/theme.ts and ThemeProvider\n// =============================================================================\n\nconst STATUS_COLOR_MAP: Record<string, string> = {\n normal: '#56f000', // Green — Astro UXDS \"Normal\"\n standby: '#2dccff', // Cyan — Astro UXDS \"Standby\"\n caution: '#fce83a', // Yellow — Astro UXDS \"Caution\"\n serious: '#ffb302', // Orange — Astro UXDS \"Serious\"\n critical: '#ff3838', // Red — Astro UXDS \"Critical\"\n off: '#a4abb6', // Grey — Astro UXDS \"Off\"\n};\n\nconst DEFAULT_TRACK_COLORS = [\n '#2dccff', '#3E3CFF', '#9D70FF', '#56f000', '#fce83a', '#ff7849', '#2dd4bf', '#ff3838',\n];\n\n// Earth constants for realistic coverage calculations\nconst EARTH_RADIUS_KM = 6371;\nconst _DEG_PER_KM = 1 / 111.32; // Approximate degrees per km at equator\n\n// Higher-quality world map coastline paths (Mercator-compatible)\nconst WORLD_MAP_PATHS = [\n // North America\n 'M-168,70 L-168,60 L-145,63 L-140,58 L-130,55 L-125,49 L-122,48 L-117,33 L-115,28 L-105,22 L-97,18 L-88,20 L-82,25 L-82,30 L-80,32 L-67,47 L-60,46 L-55,52 L-56,60 L-65,70 L-85,73 L-100,72 L-130,70 L-168,70',\n // South America\n 'M-82,12 L-77,8 L-73,11 L-65,5 L-60,5 L-50,0 L-45,-5 L-43,-10 L-39,-15 L-38,-22 L-40,-25 L-43,-30 L-48,-33 L-50,-40 L-55,-48 L-57,-52 L-68,-55 L-73,-50 L-78,-42 L-80,-20 L-78,-5 L-82,12',\n // Europe + Africa\n 'M-10,72 L-5,60 L-5,48 L0,44 L3,44 L5,48 L8,44 L3,37 L-5,35 L-17,28 L-17,15 L-8,10 L-4,5 L5,5 L10,2 L15,-3 L22,-12 L28,-22 L33,-30 L30,-35 L22,-35 L18,-27 L12,-20 L8,-10 L3,0 L-5,10 L-12,15 L-15,20 L-13,32 L-10,38 L0,48 L8,55 L15,58 L20,60 L25,65 L30,70 L-10,72',\n // Asia \n 'M30,70 L40,65 L50,60 L60,55 L70,50 L80,45 L90,45 L100,40 L105,35 L110,30 L115,25 L120,30 L125,35 L130,40 L135,45 L140,50 L145,55 L150,60 L155,65 L160,68 L170,70 L180,70 L180,72 L30,72 L30,70',\n // Australia\n 'M112,-12 L118,-14 L125,-15 L132,-13 L138,-15 L143,-17 L148,-20 L152,-23 L153,-28 L150,-33 L147,-37 L140,-38 L134,-36 L130,-33 L126,-30 L120,-30 L116,-28 L114,-24 L113,-18 L112,-12',\n // Antarctica\n 'M-180,-72 L180,-72 L180,-90 L-180,-90 Z',\n];\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Calculate ground station visibility radius in degrees.\n * Uses spherical Earth geometry: for a station with minimum elevation angle `elDeg`\n * and a satellite at altitude `altKm`, the half-angle subtended at Earth center is:\n * ρ = acos(R / (R + h)) − el_rad\n * Then the ground-range in degrees ≈ ρ * (180/π).\n * If no altitude context, coverageRadius prop is used directly (in degrees).\n */\nfunction _visibilityRadiusDeg(altitudeKm: number = 500, minElevationDeg: number = 5): number {\n const elRad = (minElevationDeg * Math.PI) / 180;\n const rho = Math.acos(EARTH_RADIUS_KM / (EARTH_RADIUS_KM + altitudeKm)) - elRad;\n return Math.max(0, (rho * 180) / Math.PI);\n}\n\n/**\n * Draw a ground-circle footprint using great-circle math.\n * Given a center lat/lon and an angular radius (in degrees measured along\n * Earth's surface), compute N points around the circle on the sphere, then\n * project each to equirectangular pixel coordinates.\n *\n * This produces a circle that is geographically correct AND looks natural\n * on the map — at high latitudes the circle is wider in longitude because\n * that's how equirectangular projection works, but it's capped by reality\n * rather than a simple 1/cos blowup.\n */\nfunction drawCoverageEllipse(\n ctx: CanvasRenderingContext2D,\n centerLat: number,\n centerLon: number,\n radiusDeg: number,\n W: number,\n H: number,\n lonToX: (lon: number, w: number) => number,\n latToY: (lat: number, h: number) => number,\n numSegments: number = 72,\n): void {\n const lat0 = (centerLat * Math.PI) / 180;\n const lon0 = (centerLon * Math.PI) / 180;\n const d = (radiusDeg * Math.PI) / 180; // angular radius in radians\n\n // Compute the center pixel once — all points are placed relative to this\n // so the circle never jumps across the date-line seam.\n const cx = lonToX(centerLon, W);\n const cy = latToY(centerLat, H);\n const pxPerDegLon = W / 360;\n const pxPerDegLat = H / 180;\n\n ctx.beginPath();\n for (let i = 0; i <= numSegments; i++) {\n const bearing = (i / numSegments) * 2 * Math.PI;\n\n // Great-circle destination formula\n const sinLat = Math.sin(lat0) * Math.cos(d) + Math.cos(lat0) * Math.sin(d) * Math.cos(bearing);\n const lat = Math.asin(Math.max(-1, Math.min(1, sinLat)));\n const lon = lon0 + Math.atan2(\n Math.sin(bearing) * Math.sin(d) * Math.cos(lat0),\n Math.cos(d) - Math.sin(lat0) * sinLat,\n );\n\n const pLatDeg = (lat * 180) / Math.PI;\n const pLonDeg = (lon * 180) / Math.PI;\n\n // Pixel offset from center — no normalization, so no date-line jump\n const dLon = pLonDeg - centerLon;\n const dLat = pLatDeg - centerLat;\n const px = cx + dLon * pxPerDegLon;\n const py = cy - dLat * pxPerDegLat; // Y inverted (lat goes up, pixels go down)\n\n if (i === 0) ctx.moveTo(px, py);\n else ctx.lineTo(px, py);\n }\n ctx.closePath();\n}\n//sz ee*s \n\n/** Parse a CSS hex color to [r, g, b]. Falls back to warm white. */\nfunction hexToRgb(hex: string): [number, number, number] {\n const h = hex.replace('#', '');\n if (h.length === 3) {\n return [parseInt(h[0] + h[0], 16), parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16)];\n }\n if (h.length >= 6) {\n return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];\n }\n return [255, 238, 221]; // fallback warm white\n}\n\n/**\n * Calculate solar terminator points for a given date and solar depression angle.\n *\n * `depressionDeg` offsets the zenith angle to produce twilight boundaries:\n * - 0° = geometric sunset/sunrise\n * - 6° = civil twilight (IAU/USNO)\n * - 12° = nautical twilight\n * - 18° = astronomical twilight\n */\n\n/** Calculate the sub-solar point (latitude, longitude) for a given UTC Date. */\nfunction calculateSubSolarPoint(date: Date): [number, number] {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const lon = -(solarHours - 12) * 15;\n return [declination, ((lon + 540) % 360) - 180];\n}\n\n/** Calculate the approximate sub-lunar point for a given UTC Date (low-precision). */\nfunction calculateSubLunarPoint(date: Date): [number, number] {\n const J2000 = Date.UTC(2000, 0, 1, 12, 0, 0);\n const d = (date.getTime() - J2000) / 86400000;\n const DEG = Math.PI / 180;\n const L = (218.316 + 13.176396 * d) % 360;\n const M = (134.963 + 13.064993 * d) % 360;\n const F = (93.272 + 13.229350 * d) % 360;\n const lon_ecl = L + 6.289 * Math.sin(M * DEG);\n const lat_ecl = 5.128 * Math.sin(F * DEG);\n const obliquity = 23.439 - 0.00000036 * d;\n const sinRA = Math.sin(lon_ecl * DEG) * Math.cos(obliquity * DEG) - Math.tan(lat_ecl * DEG) * Math.sin(obliquity * DEG);\n const cosRA = Math.cos(lon_ecl * DEG);\n let RA = Math.atan2(sinRA, cosRA) / DEG;\n if (RA < 0) RA += 360;\n const dec = Math.asin(\n Math.sin(lat_ecl * DEG) * Math.cos(obliquity * DEG)\n + Math.cos(lat_ecl * DEG) * Math.sin(obliquity * DEG) * Math.sin(lon_ecl * DEG)\n ) / DEG;\n const GMST = (280.46061837 + 360.98564736629 * d) % 360;\n let geoLon = RA - GMST;\n geoLon = ((geoLon + 540) % 360) - 180;\n return [dec, geoLon];\n}\n\nfunction calculateTerminatorContinuous(\n date: Date,\n depressionDeg: number = 0,\n numPoints: number = 360,\n): { sunset: Array<[number, number]>, sunrise: Array<[number, number]> } {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n\n // Equation of Time correction (minutes) for more accurate solar position\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n\n // Sub-solar longitude: use full UTC time (hours + minutes + seconds) plus EoT\n // Sub-solar longitude: where the sun is directly overhead.\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const subSolarLon = -(solarHours - 12) * 15;\n const depRad = (depressionDeg * Math.PI) / 180;\n\n const sunset: Array<[number, number]> = [];\n const sunrise: Array<[number, number]> = [];\n\n for (let i = 0; i <= numPoints; i++) {\n const lat = -89.999 + (i / numPoints) * 179.998;\n const latRad = lat * (Math.PI / 180);\n const cosH = -(Math.sin(depRad) + Math.sin(latRad) * Math.sin(decRad))\n / (Math.cos(latRad) * Math.cos(decRad));\n \n if (cosH < -1) {\n // All day — midnight sun. No night boundary.\n } else if (cosH > 1) {\n // All night — polar night. Night spans all longitudes.\n sunset.push([lat, subSolarLon]);\n sunrise.push([lat, subSolarLon + 360]);\n } else {\n const H = (Math.acos(cosH) * 180) / Math.PI;\n // Sunset: H degrees east of sub-solar point (afternoon→evening)\n sunset.push([lat, subSolarLon + H]);\n // Sunrise: H degrees west, expressed as +360-H for continuous polygon\n sunrise.push([lat, subSolarLon + 360 - H]);\n }\n }\n \n return { sunset, sunrise };\n}\n\nfunction buildNightPolygon(\n terminator: { sunset: Array<[number, number]>, sunrise: Array<[number, number]> }\n): [number, number][] {\n const { sunset, sunrise } = terminator;\n if (!sunset.length || !sunrise.length) return [];\n\n const poly: [number, number][] = [];\n\n // Left edge of night (sunset): South to North\n poly.push(...sunset);\n\n // Right edge of night (sunrise): North to South\n poly.push(...[...sunrise].reverse());\n\n return poly;\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function GroundTrackMap({\n groundTrack,\n satellites = [],\n groundStations = [],\n accessMask,\n teamPaths,\n showTerminator = true,\n terminatorTime,\n showGrid = true,\n showLegend = true,\n showEquator = true,\n showRecenterButton = false,\n showMapStyleToggle = true,\n isLoading = false,\n emptyMessage = 'No orbital data available',\n width = '100%',\n height = '100%',\n minHeight = '400px',\n defaultCenter,\n defaultZoom,\n className = '',\n onSatelliteClick,\n onStationClick,\n mapProvider = 'leaflet',\n tileUrl,\n nightTileUrl,\n lightSources,\n pins,\n pinsEditable = false,\n onPinAdd,\n onPinUpdate,\n onPinRemove,\n customLayers,\n onLayerChange,\n showCelestialMarkers,\n}: GroundTrackMapProps): React.ReactElement {\n const { tokens } = useTheme();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const [tooltip, setTooltip] = useState<{\n x: number; y: number;\n type: 'satellite' | 'station';\n name: string;\n status: string;\n statusColor: string;\n lat: number;\n lon: number;\n alt?: number;\n // Ground station extras\n stationType?: string;\n network?: string;\n coverageRadius?: number;\n // Satellite extras\n trackColor?: string;\n hasFootprint?: boolean;\n futurePoints?: number;\n pastPoints?: number;\n } | null>(null);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const [_viewOffset, setViewOffset] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n\n // Normalize satellites: support SRO teamPaths, legacy single-track, and native API\n const allSatellites = useMemo<SatelliteTrack[]>(() => {\n // Priority 1: native satellites prop\n if (satellites.length > 0) return satellites;\n // Priority 2: SRO teamPaths format — auto-convert\n if (teamPaths && teamPaths.length > 0) {\n return teamPaths.map((tp, idx) => ({\n id: `team-${idx}`,\n name: tp.name,\n color: tp.color,\n status: 'normal' as const,\n groundTrack: tp.positions\n .filter(p => p.lat != null && p.lng != null)\n .map(p => ({\n latitude: p.lat,\n longitude: p.lng,\n altitude: p.altitude ?? 0,\n timestamp: p.time != null ? new Date(p.time * 1000).toISOString() : new Date().toISOString(),\n })),\n }));\n }\n // Priority 3: legacy single-track API\n if (groundTrack && groundTrack.length > 0) {\n return [{\n id: 'primary',\n name: 'Satellite',\n groundTrack,\n status: 'normal',\n accessMask,\n }];\n }\n return [];\n }, [satellites, groundTrack, accessMask, teamPaths]);\n\n // Stable defaults for Leaflet so animated updates don't get new refs and trigger map recreation\n const leafletDefaultCenter = useMemo<[number, number]>(() => defaultCenter ?? [20, 0], [defaultCenter]);\n const leafletDefaultZoom = useMemo(() => defaultZoom ?? 2, [defaultZoom]);\n\n // Optional Leaflet map: load when mapProvider is 'leaflet'\n const [LeafletMap, setLeafletMap] = useState<React.ComponentType<GroundTrackMapLeafletProps> | null>(null);\n const [leafletFailed, setLeafletFailed] = useState(false);\n\n useEffect(() => {\n if (mapProvider !== 'leaflet') return;\n import('./GroundTrackMapLeaflet')\n .then((m) => setLeafletMap(() => m.GroundTrackMapLeaflet))\n .catch((err) => {\n console.warn('[GroundTrackMap] Leaflet backend failed to load. Install \"leaflet\" and ensure it is resolvable. Falling back to static canvas.', err);\n setLeafletFailed(true);\n });\n }, [mapProvider]);\n\n // All canvas-backend hooks must run unconditionally (same hook count every render)\n // Recenter handler (canvas backend)\n const handleRecenter = useCallback(() => {\n setViewOffset({ x: 0, y: 0 });\n }, []);\n\n const COLORS = useMemo(() => ({\n background: tokens.colors.background.base,\n grid: tokens.colors.border.muted,\n text: tokens.colors.text.secondary,\n accent: tokens.colors.accent.primary,\n land: 'rgba(30, 40, 58, 0.92)',\n ocean: tokens.colors.background.base,\n night: 'rgba(0, 10, 40, 0.35)',\n equator: 'rgba(88, 166, 255, 0.25)',\n }), [tokens]);\n\n const lonToX = useCallback((lon: number, w: number) => {\n let normalizedLon = lon;\n while (normalizedLon > 180) normalizedLon -= 360;\n while (normalizedLon < -180) normalizedLon += 360;\n return ((normalizedLon + 180) / 360) * w;\n }, []);\n\n const latToY = useCallback((lat: number, h: number) => {\n return ((90 - lat) / 180) * h;\n }, []);\n\n const draw = useCallback(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const dpr = window.devicePixelRatio || 1;\n const rect = container.getBoundingClientRect();\n const W = rect.width;\n // When height is a CSS string ('100%'), use the measured container height\n const H = typeof height === 'number' ? height : rect.height || 400;\n\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n ctx.scale(dpr, dpr);\n\n // === Background ===\n ctx.fillStyle = COLORS.background;\n ctx.fillRect(0, 0, W, H);\n\n // === Day/Night Terminator with smooth graduated twilight ===\n // Many thin bands (every 2° of solar depression) produce a seamless\n // day→night gradient instead of hard-edged zones.\n if (showTerminator) {\n const now = terminatorTime ?? new Date();\n\n const BAND_STEP = 1.5;\n const MAX_DEP = 30;\n const NIGHT_ALPHA = 0.38;\n const bandSteps: Array<{ depression: number; alpha: number }> = [];\n for (let d = 0; d <= MAX_DEP; d += BAND_STEP) {\n const t = Math.min(d / 18, 1);\n const alpha = Math.pow(t, 1.6) * (NIGHT_ALPHA * 0.85) + (d > 18 ? (d - 18) / 12 * (NIGHT_ALPHA * 0.15) : 0);\n bandSteps.push({ depression: d, alpha: Math.min(alpha, NIGHT_ALPHA) });\n }\n bandSteps.push({ depression: 90, alpha: NIGHT_ALPHA });\n\n let prevAlpha = 0;\n for (const zone of bandSteps) {\n const dep = Math.min(zone.depression, 89);\n const bandAlpha = zone.alpha - prevAlpha;\n if (bandAlpha < 0.002) { prevAlpha = zone.alpha; continue; }\n\n const terminator = calculateTerminatorContinuous(now, dep);\n if (terminator.sunset.length === 0) { prevAlpha = zone.alpha; continue; }\n \n const poly = buildNightPolygon(terminator);\n if (poly.length < 3) { prevAlpha = zone.alpha; continue; }\n\n ctx.fillStyle = `rgba(42, 58, 82, ${bandAlpha.toFixed(4)})`;\n \n // Draw the polygon (wrapping around longitude boundaries by drawing 3 copies)\n for (const offset of [-360, 0, 360]) {\n ctx.beginPath();\n for (let i = 0; i < poly.length; i++) {\n const lat = poly[i][0];\n const lon = poly[i][1] + offset;\n const x = lonToX(lon, W);\n const y = latToY(lat, H);\n \n // To prevent lines jumping completely across the canvas from right to left\n // if a polygon crosses the map boundary, we should probably handle it.\n // But since we draw 3 full copies (-360, 0, +360), they overlap seamlessly.\n if (i === 0) {\n ctx.moveTo(x, y);\n } else {\n // If distance is huge (e.g. > W/2), it means it's wrapping around the map edge.\n // Move instead of line to avoid a horizontal streak.\n // (Actually, since we unwrap longitude continuously in calculateTerminatorContinuous,\n // there are NO jumps in longitude inside the polygon! It's one continuous shape.)\n ctx.lineTo(x, y);\n }\n }\n ctx.closePath();\n ctx.fill();\n }\n \n prevAlpha = zone.alpha;\n }\n\n // Draw a smooth terminator boundary line (0° depression)\n const terminatorEdge = calculateTerminatorContinuous(now, 0);\n if (terminatorEdge.sunset.length > 2) {\n ctx.save();\n // Soft outer glow\n ctx.strokeStyle = 'rgba(160, 160, 160, 0.08)';\n ctx.lineWidth = 3;\n for (const curve of [terminatorEdge.sunset, terminatorEdge.sunrise]) {\n for (const offset of [-360, 0, 360]) {\n ctx.beginPath();\n for (let i = 0; i < curve.length; i++) {\n const x = lonToX(curve[i][1] + offset, W);\n const y = latToY(curve[i][0], H);\n if (i === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n }\n // Fine core line\n ctx.strokeStyle = 'rgba(168, 168, 168, 0.30)';\n ctx.lineWidth = 1;\n for (const curve of [terminatorEdge.sunset, terminatorEdge.sunrise]) {\n for (const offset of [-360, 0, 360]) {\n ctx.beginPath();\n for (let i = 0; i < curve.length; i++) {\n const x = lonToX(curve[i][1] + offset, W);\n const y = latToY(curve[i][0], H);\n if (i === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n }\n }\n ctx.restore();\n }\n\n // TODO: Re-enable sun/moon celestial markers once visual design is finalized.\n // Uncomment to restore: const celestialEnabled = showCelestialMarkers !== undefined ? showCelestialMarkers : true;\n const celestialEnabled = false;\n if (celestialEnabled) {\n const [sunLat, sunLon] = calculateSubSolarPoint(now);\n const sx = lonToX(sunLon, W), sy = latToY(sunLat, H);\n ctx.save();\n ctx.shadowColor = 'rgba(255, 179, 0, 0.5)';\n ctx.shadowBlur = 8;\n ctx.fillStyle = '#FFB300';\n ctx.strokeStyle = '#FF8F00';\n ctx.lineWidth = 1.2;\n ctx.beginPath();\n ctx.arc(sx, sy, 6, 0, Math.PI * 2);\n ctx.fill();\n ctx.stroke();\n ctx.shadowBlur = 0;\n ctx.strokeStyle = 'rgba(255, 179, 0, 0.85)';\n ctx.lineWidth = 1.4;\n for (let a = 0; a < 360; a += 45) {\n const rad = (a * Math.PI) / 180;\n ctx.beginPath();\n ctx.moveTo(sx + 8 * Math.cos(rad), sy + 8 * Math.sin(rad));\n ctx.lineTo(sx + 12 * Math.cos(rad), sy + 12 * Math.sin(rad));\n ctx.stroke();\n }\n ctx.restore();\n\n const [moonLat, moonLon] = calculateSubLunarPoint(now);\n const mx = lonToX(moonLon, W), my = latToY(moonLat, H);\n ctx.save();\n ctx.shadowColor = 'rgba(224, 224, 224, 0.4)';\n ctx.shadowBlur = 6;\n ctx.fillStyle = '#e0e0e0';\n ctx.strokeStyle = '#9e9e9e';\n ctx.lineWidth = 0.8;\n ctx.beginPath();\n ctx.arc(mx, my, 5.5, 0, Math.PI * 2);\n ctx.fill();\n ctx.stroke();\n ctx.shadowBlur = 0;\n ctx.fillStyle = 'rgba(189, 189, 189, 0.5)';\n ctx.beginPath(); ctx.arc(mx - 1.5, my - 1, 1.4, 0, Math.PI * 2); ctx.fill();\n ctx.fillStyle = 'rgba(189, 189, 189, 0.4)';\n ctx.beginPath(); ctx.arc(mx + 2, my + 1.5, 0.9, 0, Math.PI * 2); ctx.fill();\n ctx.restore();\n }\n }\n\n // === World Map (land visible against ocean) ===\n ctx.fillStyle = COLORS.land;\n ctx.strokeStyle = 'rgba(100, 120, 160, 0.25)';\n ctx.lineWidth = 1;\n\n for (const pathStr of WORLD_MAP_PATHS) {\n const commands = pathStr.split(' ');\n ctx.beginPath();\n for (const cmd of commands) {\n if (cmd.startsWith('M') || cmd.startsWith('L')) {\n const coords = cmd.substring(1).split(',');\n const lon = parseFloat(coords[0]);\n const lat = parseFloat(coords[1]);\n const x = lonToX(lon, W);\n const y = latToY(lat, H);\n if (cmd.startsWith('M')) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n } else if (cmd === 'Z') {\n ctx.closePath();\n }\n }\n ctx.fill();\n ctx.stroke();\n }\n\n // === Grid ===\n if (showGrid) {\n ctx.strokeStyle = COLORS.grid;\n ctx.lineWidth = 0.4;\n for (let lon = -180; lon <= 180; lon += 30) {\n const x = lonToX(lon, W);\n ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke();\n }\n for (let lat = -90; lat <= 90; lat += 30) {\n const y = latToY(lat, H);\n ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke();\n }\n }\n\n // === Equator ===\n if (showEquator) {\n const eqY = latToY(0, H);\n ctx.strokeStyle = COLORS.equator;\n ctx.lineWidth = 1;\n ctx.setLineDash([6, 4]);\n ctx.beginPath(); ctx.moveTo(0, eqY); ctx.lineTo(W, eqY); ctx.stroke();\n ctx.setLineDash([]);\n }\n\n // === Ground Station Coverage Circles (latitude-corrected ellipses) ===\n for (const gs of groundStations) {\n const enhanced = gs as GroundStationEnhanced;\n if (enhanced.showCoverage && enhanced.coverageRadius) {\n const statusColor = STATUS_COLOR_MAP[enhanced.status || 'standby'] || STATUS_COLOR_MAP.standby;\n\n // Use the coverage radius as-is (in degrees) — caller can compute\n // from visibilityRadiusDeg() or provide a direct value\n drawCoverageEllipse(ctx, gs.latitude, gs.longitude, enhanced.coverageRadius, W, H, lonToX, latToY);\n ctx.fillStyle = `${statusColor}15`;\n ctx.fill();\n ctx.strokeStyle = `${statusColor}40`;\n ctx.lineWidth = 1;\n ctx.setLineDash([4, 3]);\n ctx.stroke();\n ctx.setLineDash([]);\n }\n }\n\n // === Ground Stations (Astro UX Icons + Status Badges) ===\n for (const gs of groundStations) {\n const enhanced = gs as GroundStationEnhanced;\n const x = lonToX(gs.longitude, W);\n const y = latToY(gs.latitude, H);\n const status = enhanced.status || 'standby';\n const statusColor = STATUS_COLOR_MAP[status] || STATUS_COLOR_MAP.standby;\n const stationType = enhanced.type || 'dish';\n const iconSize = 20;\n const halfIcon = iconSize / 2;\n\n ctx.save();\n ctx.translate(x, y);\n\n // -- Background circle (subtle glow) --\n ctx.beginPath();\n ctx.arc(0, 0, halfIcon + 2, 0, Math.PI * 2);\n ctx.fillStyle = `${statusColor}18`;\n ctx.fill();\n\n // -- Icon background pill --\n ctx.beginPath();\n ctx.arc(0, 0, halfIcon, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.85)';\n ctx.fill();\n ctx.strokeStyle = `${statusColor}66`;\n ctx.lineWidth = 1.5;\n ctx.stroke();\n\n // -- Draw Astro UX icon via SVG paths scaled to icon size --\n ctx.save();\n const iconScale = iconSize / 24;\n ctx.translate(-halfIcon, -halfIcon);\n ctx.scale(iconScale, iconScale);\n\n if (stationType === 'dish' || stationType === 'omni') {\n // Antenna icon (concentric arcs — Astro antenna pattern)\n ctx.strokeStyle = statusColor;\n ctx.fillStyle = statusColor;\n ctx.lineWidth = 2 / iconScale;\n // Outer arc\n ctx.beginPath(); ctx.arc(12, 12, 10, Math.PI * 1.25, Math.PI * 1.75); ctx.stroke();\n // Middle arc\n ctx.beginPath(); ctx.arc(12, 12, 6.5, Math.PI * 1.2, Math.PI * 1.8); ctx.stroke();\n // Inner arc\n ctx.beginPath(); ctx.arc(12, 12, 3, Math.PI * 1.15, Math.PI * 1.85); ctx.stroke();\n // Center dot (feed point)\n ctx.beginPath(); ctx.arc(12, 12, 1.5, 0, Math.PI * 2); ctx.fill();\n // Stand\n ctx.lineWidth = 1.5 / iconScale;\n ctx.beginPath(); ctx.moveTo(12, 14); ctx.lineTo(12, 20); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(8, 20); ctx.lineTo(16, 20); ctx.stroke();\n } else if (stationType === 'phased-array') {\n // Phased array icon (grid pattern)\n ctx.strokeStyle = statusColor;\n ctx.fillStyle = statusColor;\n ctx.lineWidth = 1.5 / iconScale;\n ctx.strokeRect(5, 4, 14, 12);\n // Grid lines\n for (let gx = 8; gx <= 16; gx += 4) {\n ctx.beginPath(); ctx.moveTo(gx, 4); ctx.lineTo(gx, 16); ctx.stroke();\n }\n for (let gy = 8; gy <= 12; gy += 4) {\n ctx.beginPath(); ctx.moveTo(5, gy); ctx.lineTo(19, gy); ctx.stroke();\n }\n // Stand\n ctx.beginPath(); ctx.moveTo(12, 16); ctx.lineTo(12, 21); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(8, 21); ctx.lineTo(16, 21); ctx.stroke();\n } else {\n // Relay: satellite dish with signal waves\n ctx.strokeStyle = statusColor;\n ctx.fillStyle = statusColor;\n ctx.lineWidth = 2 / iconScale;\n // Dish bowl\n ctx.beginPath(); ctx.arc(10, 12, 7, Math.PI * 0.8, Math.PI * 1.7); ctx.stroke();\n // Feed arm\n ctx.lineWidth = 1.5 / iconScale;\n ctx.beginPath(); ctx.moveTo(10, 12); ctx.lineTo(16, 6); ctx.stroke();\n // Signal waves\n ctx.lineWidth = 1.2 / iconScale;\n ctx.beginPath(); ctx.arc(17, 5, 2.5, Math.PI * 1.2, Math.PI * 1.7); ctx.stroke();\n ctx.beginPath(); ctx.arc(17, 5, 4.5, Math.PI * 1.15, Math.PI * 1.75); ctx.stroke();\n // Base\n ctx.lineWidth = 1.5 / iconScale;\n ctx.beginPath(); ctx.moveTo(10, 14); ctx.lineTo(10, 20); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(6, 20); ctx.lineTo(14, 20); ctx.stroke();\n }\n\n ctx.restore(); // icon scaling\n\n // -- Astro UX Status Badge (top-left of icon) --\n const badgeX = -halfIcon + 1;\n const badgeY = -halfIcon + 1;\n const badgeSize = 7;\n\n // Badge background ring\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 2 + 2, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.9)';\n ctx.fill();\n\n // Status shape per Astro UX spec (StatusIndicator.tsx canonical reference):\n // off → small filled dot, standby → ring (hollow circle),\n // normal → filled circle, caution → square,\n // serious → diamond, critical → triangle pointing DOWN\n ctx.fillStyle = statusColor;\n ctx.strokeStyle = statusColor;\n ctx.lineWidth = 1;\n if (status === 'normal') {\n // Filled circle for normal\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 2, 0, Math.PI * 2);\n ctx.fill();\n } else if (status === 'standby') {\n // Ring (hollow circle) for standby\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 2 - 0.5, 0, Math.PI * 2);\n ctx.lineWidth = 2;\n ctx.stroke();\n } else if (status === 'caution') {\n // Square for caution\n const hs = badgeSize / 2;\n ctx.fillRect(badgeX - hs, badgeY - hs, badgeSize, badgeSize);\n } else if (status === 'serious') {\n // Diamond for serious\n const hs = badgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(badgeX, badgeY - hs);\n ctx.lineTo(badgeX + hs, badgeY);\n ctx.lineTo(badgeX, badgeY + hs);\n ctx.lineTo(badgeX - hs, badgeY);\n ctx.closePath();\n ctx.fill();\n } else if (status === 'critical') {\n // Triangle pointing DOWN for critical\n const hs = badgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(badgeX, badgeY + hs); // bottom point\n ctx.lineTo(badgeX + hs, badgeY - hs); // top-right\n ctx.lineTo(badgeX - hs, badgeY - hs); // top-left\n ctx.closePath();\n ctx.fill();\n } else {\n // Off: small filled dot\n ctx.beginPath();\n ctx.arc(badgeX, badgeY, badgeSize / 3, 0, Math.PI * 2);\n ctx.fill();\n }\n\n ctx.restore();\n\n // Label\n ctx.fillStyle = COLORS.text;\n ctx.font = '9px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(gs.name.length > 14 ? gs.name.slice(0, 14) + '…' : gs.name, x, y + halfIcon + 12);\n }\n\n // === Light Sources (visible only on the night side of the terminator) ===\n if (lightSources && lightSources.length > 0 && showTerminator) {\n const now = terminatorTime ?? new Date();\n\n for (const light of lightSources) {\n const lx = lonToX(light.longitude, W);\n const ly = latToY(light.latitude, H);\n const r = light.radius ?? 4;\n const intensity = light.intensity ?? 0.8;\n const color = light.color ?? '#ffeedd';\n\n // Compute night factor: how deeply this point is inside the night zone.\n // We use the geometric terminator (0°) and astronomical (18°) as endpoints\n // for a 0→1 ramp.\n const dayOfYear = Math.floor((now.getTime() - Date.UTC(now.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n const lsSubSolarLon = -((now.getUTCHours() + now.getUTCMinutes() / 60) - 12) * 15;\n const latRad = (light.latitude * Math.PI) / 180;\n\n // Solar elevation angle at the light's position\n const sinAlt = Math.sin(latRad) * Math.sin(decRad) +\n Math.cos(latRad) * Math.cos(decRad) *\n Math.cos(((light.longitude - lsSubSolarLon) * Math.PI) / 180);\n const solarAltDeg = (Math.asin(sinAlt) * 180) / Math.PI;\n\n // Lights fade in: full day (alt > 0°) = invisible, deep night (alt < -18°) = full brightness\n let nightFactor: number;\n if (solarAltDeg >= 0) nightFactor = 0;\n else if (solarAltDeg <= -18) nightFactor = 1;\n else nightFactor = Math.min(1, -solarAltDeg / 18);\n\n if (nightFactor < 0.01) continue;\n\n const alpha = intensity * nightFactor;\n const [cr, cg, cb] = hexToRgb(color);\n const grad = ctx.createRadialGradient(lx, ly, 0, lx, ly, r * 2);\n grad.addColorStop(0, `rgba(${cr}, ${cg}, ${cb}, ${alpha})`);\n grad.addColorStop(0.4, `rgba(${cr}, ${cg}, ${cb}, ${alpha * 0.6})`);\n grad.addColorStop(1, `rgba(${cr}, ${cg}, ${cb}, 0)`);\n\n ctx.fillStyle = grad;\n ctx.beginPath();\n ctx.arc(lx, ly, r * 2, 0, Math.PI * 2);\n ctx.fill();\n\n // Bright core\n ctx.fillStyle = `rgba(${cr}, ${cg}, ${cb}, ${Math.min(1, alpha * 1.3)})`;\n ctx.beginPath();\n ctx.arc(lx, ly, Math.max(1, r * 0.4), 0, Math.PI * 2);\n ctx.fill();\n }\n }\n\n // === Satellite Tracks ===\n allSatellites.forEach((sat, satIdx) => {\n const track = sat.groundTrack;\n if (!track || track.length === 0) return;\n\n const trackColor = sat.color || DEFAULT_TRACK_COLORS[satIdx % DEFAULT_TRACK_COLORS.length];\n const futureIdx = sat.futureTrackIndex ?? track.length;\n\n // Draw past track (solid)\n ctx.strokeStyle = trackColor;\n ctx.lineWidth = 2;\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n ctx.setLineDash([]);\n ctx.beginPath();\n\n let prevX = lonToX(track[0].longitude, W);\n let prevY = latToY(track[0].latitude, H);\n ctx.moveTo(prevX, prevY);\n\n for (let i = 1; i < Math.min(futureIdx, track.length); i++) {\n const x = lonToX(track[i].longitude, W);\n const y = latToY(track[i].latitude, H);\n const crossesDateLine = Math.abs(x - prevX) > W / 2;\n if (crossesDateLine) {\n ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y);\n } else {\n ctx.lineTo(x, y);\n }\n prevX = x; prevY = y;\n }\n ctx.stroke();\n\n // Draw future track (dashed)\n if (futureIdx < track.length) {\n ctx.strokeStyle = `${trackColor}88`;\n ctx.lineWidth = 1.5;\n ctx.setLineDash([6, 4]);\n ctx.beginPath();\n ctx.moveTo(lonToX(track[futureIdx].longitude, W), latToY(track[futureIdx].latitude, H));\n let fpx = lonToX(track[futureIdx].longitude, W);\n\n for (let i = futureIdx + 1; i < track.length; i++) {\n const x = lonToX(track[i].longitude, W);\n const y = latToY(track[i].latitude, H);\n if (Math.abs(x - fpx) > W / 2) {\n ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y);\n } else {\n ctx.lineTo(x, y);\n }\n fpx = x;\n }\n ctx.stroke();\n ctx.setLineDash([]);\n }\n\n // Draw access segments (contact passes)\n if (sat.accessMask && sat.accessMask.some(Boolean)) {\n ctx.strokeStyle = STATUS_COLOR_MAP.normal;\n ctx.lineWidth = 3;\n ctx.setLineDash([]);\n ctx.beginPath();\n let drawing = false;\n let apx = lonToX(track[0].longitude, W);\n\n for (let i = 0; i < track.length; i++) {\n const x = lonToX(track[i].longitude, W);\n const y = latToY(track[i].latitude, H);\n const active = sat.accessMask[i];\n const crossesDateLine = i > 0 && Math.abs(x - apx) > W / 2;\n\n if (active && !crossesDateLine) {\n if (!drawing) { ctx.moveTo(x, y); drawing = true; }\n else ctx.lineTo(x, y);\n } else {\n if (drawing) { ctx.stroke(); ctx.beginPath(); drawing = false; }\n }\n apx = x;\n }\n if (drawing) ctx.stroke();\n }\n\n // AOS/LOS markers\n if (sat.passMarkers) {\n for (const marker of sat.passMarkers) {\n const mx = lonToX(marker.longitude, W);\n const my = latToY(marker.latitude, H);\n const markerColor = marker.type === 'aos' ? STATUS_COLOR_MAP.normal : STATUS_COLOR_MAP.critical;\n\n ctx.save();\n ctx.translate(mx, my);\n // Triangle marker\n ctx.beginPath();\n if (marker.type === 'aos') {\n ctx.moveTo(0, -6); ctx.lineTo(4, 2); ctx.lineTo(-4, 2);\n } else {\n ctx.moveTo(0, 6); ctx.lineTo(4, -2); ctx.lineTo(-4, -2);\n }\n ctx.closePath();\n ctx.fillStyle = markerColor;\n ctx.fill();\n ctx.restore();\n\n if (marker.label) {\n ctx.fillStyle = markerColor;\n ctx.font = '8px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(marker.label, mx, marker.type === 'aos' ? my - 9 : my + 13);\n }\n }\n }\n\n // Satellite footprint (latitude-corrected ellipse)\n if (sat.showFootprint && sat.footprintRadius) {\n const lastPt = futureIdx > 0 ? track[Math.min(futureIdx - 1, track.length - 1)] : track[track.length - 1];\n\n drawCoverageEllipse(ctx, lastPt.latitude, lastPt.longitude, sat.footprintRadius, W, H, lonToX, latToY);\n ctx.fillStyle = `${trackColor}12`;\n ctx.fill();\n ctx.strokeStyle = `${trackColor}50`;\n ctx.lineWidth = 1;\n ctx.setLineDash([3, 3]);\n ctx.stroke();\n ctx.setLineDash([]);\n }\n\n // Current position satellite icon (Astro UX style)\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, track.length - 1) : track.length - 1;\n const current = track[currentIdx];\n const cx = lonToX(current.longitude, W);\n const cy = latToY(current.latitude, H);\n const satStatus = sat.status || 'normal';\n const statusColor = STATUS_COLOR_MAP[satStatus] || STATUS_COLOR_MAP.normal;\n const satIconSize = 22;\n const satHalf = satIconSize / 2;\n\n // Outer pulsing glow\n ctx.beginPath();\n ctx.arc(cx, cy, satHalf + 6, 0, Math.PI * 2);\n ctx.fillStyle = `${statusColor}12`;\n ctx.fill();\n\n ctx.beginPath();\n ctx.arc(cx, cy, satHalf + 3, 0, Math.PI * 2);\n ctx.fillStyle = `${statusColor}20`;\n ctx.fill();\n\n // Icon background\n ctx.save();\n ctx.translate(cx, cy);\n\n ctx.beginPath();\n ctx.arc(0, 0, satHalf, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.88)';\n ctx.fill();\n ctx.strokeStyle = `${statusColor}88`;\n ctx.lineWidth = 1.5;\n ctx.stroke();\n\n // Draw satellite shape (body + solar panels)\n ctx.fillStyle = statusColor;\n // Body (rounded rect approximation)\n const bw = 5, bh = 3.5;\n ctx.beginPath();\n ctx.moveTo(-bw / 2 + 0.5, -bh / 2);\n ctx.lineTo(bw / 2 - 0.5, -bh / 2);\n ctx.arcTo(bw / 2, -bh / 2, bw / 2, -bh / 2 + 0.5, 0.5);\n ctx.lineTo(bw / 2, bh / 2 - 0.5);\n ctx.arcTo(bw / 2, bh / 2, bw / 2 - 0.5, bh / 2, 0.5);\n ctx.lineTo(-bw / 2 + 0.5, bh / 2);\n ctx.arcTo(-bw / 2, bh / 2, -bw / 2, bh / 2 - 0.5, 0.5);\n ctx.lineTo(-bw / 2, -bh / 2 + 0.5);\n ctx.arcTo(-bw / 2, -bh / 2, -bw / 2 + 0.5, -bh / 2, 0.5);\n ctx.closePath();\n ctx.fill();\n\n // Solar panel left\n ctx.fillStyle = `${statusColor}BB`;\n ctx.fillRect(-satHalf + 2, -2, 5, 4);\n // Panel lines\n ctx.strokeStyle = `${statusColor}55`;\n ctx.lineWidth = 0.5;\n ctx.beginPath();\n ctx.moveTo(-satHalf + 4.5, -2); ctx.lineTo(-satHalf + 4.5, 2);\n ctx.stroke();\n\n // Solar panel right\n ctx.fillStyle = `${statusColor}BB`;\n ctx.fillRect(satHalf - 7, -2, 5, 4);\n ctx.strokeStyle = `${statusColor}55`;\n ctx.beginPath();\n ctx.moveTo(satHalf - 4.5, -2); ctx.lineTo(satHalf - 4.5, 2);\n ctx.stroke();\n\n // Panel connectors\n ctx.strokeStyle = statusColor;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(-bw / 2, 0); ctx.lineTo(-satHalf + 7, 0);\n ctx.moveTo(bw / 2, 0); ctx.lineTo(satHalf - 7, 0);\n ctx.stroke();\n\n // -- Astro UX Status Badge (top-left of satellite icon) --\n // Shapes per canonical StatusIndicator.tsx:\n // off → small dot, standby → ring, normal → filled circle,\n // caution → square, serious → diamond, critical → triangle DOWN\n const satBadgeX = -satHalf + 2;\n const satBadgeY = -satHalf + 2;\n const satBadgeSize = 7;\n\n // Badge background\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 2 + 2, 0, Math.PI * 2);\n ctx.fillStyle = 'rgba(15, 23, 42, 0.9)';\n ctx.fill();\n\n ctx.fillStyle = statusColor;\n ctx.strokeStyle = statusColor;\n ctx.lineWidth = 1;\n if (satStatus === 'normal') {\n // Filled circle\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 2, 0, Math.PI * 2);\n ctx.fill();\n } else if (satStatus === 'standby') {\n // Ring (hollow circle)\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 2 - 0.5, 0, Math.PI * 2);\n ctx.lineWidth = 2;\n ctx.stroke();\n } else if (satStatus === 'caution') {\n const hs = satBadgeSize / 2;\n ctx.fillRect(satBadgeX - hs, satBadgeY - hs, satBadgeSize, satBadgeSize);\n } else if (satStatus === 'serious') {\n // Diamond\n const hs = satBadgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(satBadgeX, satBadgeY - hs);\n ctx.lineTo(satBadgeX + hs, satBadgeY);\n ctx.lineTo(satBadgeX, satBadgeY + hs);\n ctx.lineTo(satBadgeX - hs, satBadgeY);\n ctx.closePath();\n ctx.fill();\n } else if (satStatus === 'critical') {\n // Triangle pointing DOWN\n const hs = satBadgeSize / 2;\n ctx.beginPath();\n ctx.moveTo(satBadgeX, satBadgeY + hs); // bottom point\n ctx.lineTo(satBadgeX + hs, satBadgeY - hs); // top-right\n ctx.lineTo(satBadgeX - hs, satBadgeY - hs); // top-left\n ctx.closePath();\n ctx.fill();\n } else {\n // Off: small filled dot\n ctx.beginPath();\n ctx.arc(satBadgeX, satBadgeY, satBadgeSize / 3, 0, Math.PI * 2);\n ctx.fill();\n }\n\n ctx.restore();\n\n // Satellite label\n ctx.fillStyle = '#fff';\n ctx.font = 'bold 10px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(sat.name, cx, cy - satHalf - 6);\n });\n\n // === Legend ===\n if (showLegend && (allSatellites.length > 0 || groundStations.length > 0)) {\n const legendX = 10;\n const legendY = 10;\n const lineHeight = 14;\n const items: Array<{ color: string; label: string; dash?: boolean }> = [];\n\n allSatellites.forEach((sat, idx) => {\n const c = sat.color || DEFAULT_TRACK_COLORS[idx % DEFAULT_TRACK_COLORS.length];\n items.push({ color: c, label: sat.name });\n });\n if (groundStations.length > 0) {\n items.push({ color: STATUS_COLOR_MAP.standby, label: `${groundStations.length} Ground Station${groundStations.length > 1 ? 's' : ''}` });\n }\n\n const maxLabelWidth = Math.max(...items.map(item => ctx.measureText(item.label).width)) + 28;\n const legendH = items.length * lineHeight + 10;\n\n ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';\n ctx.strokeStyle = 'rgba(100, 116, 139, 0.3)';\n ctx.lineWidth = 1;\n const r = 4;\n ctx.beginPath();\n ctx.moveTo(legendX + r, legendY);\n ctx.lineTo(legendX + maxLabelWidth - r, legendY);\n ctx.arcTo(legendX + maxLabelWidth, legendY, legendX + maxLabelWidth, legendY + r, r);\n ctx.lineTo(legendX + maxLabelWidth, legendY + legendH - r);\n ctx.arcTo(legendX + maxLabelWidth, legendY + legendH, legendX + maxLabelWidth - r, legendY + legendH, r);\n ctx.lineTo(legendX + r, legendY + legendH);\n ctx.arcTo(legendX, legendY + legendH, legendX, legendY + legendH - r, r);\n ctx.lineTo(legendX, legendY + r);\n ctx.arcTo(legendX, legendY, legendX + r, legendY, r);\n ctx.closePath();\n ctx.fill();\n ctx.stroke();\n\n items.forEach((item, i) => {\n const iy = legendY + 8 + i * lineHeight;\n // Color swatch\n ctx.fillStyle = item.color;\n ctx.beginPath();\n ctx.arc(legendX + 10, iy + 3, 4, 0, Math.PI * 2);\n ctx.fill();\n // Label\n ctx.fillStyle = 'rgba(255, 255, 255, 0.85)';\n ctx.font = '10px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'left';\n ctx.fillText(item.label, legendX + 20, iy + 7);\n });\n }\n\n // === Pins (read-only on canvas backend) ===\n if (pins && pins.length > 0) {\n pins.forEach((pin) => {\n const px = lonToX(pin.longitude, W);\n const py = latToY(pin.latitude, H);\n const pinColor = pin.color || tokens.colors.accent.primary;\n\n // Drop shadow\n ctx.save();\n ctx.shadowColor = 'rgba(0,0,0,0.4)';\n ctx.shadowBlur = 6;\n ctx.shadowOffsetY = 2;\n\n // Pin body: inverted teardrop shape\n ctx.beginPath();\n ctx.arc(px, py - 10, 6, Math.PI, 0);\n ctx.lineTo(px, py);\n ctx.closePath();\n ctx.fillStyle = pinColor;\n ctx.fill();\n ctx.restore();\n\n // Inner dot\n ctx.beginPath();\n ctx.arc(px, py - 10, 2.5, 0, Math.PI * 2);\n ctx.fillStyle = '#0d1323';\n ctx.fill();\n\n // Label\n if (pin.label) {\n ctx.fillStyle = 'rgba(255,255,255,0.9)';\n ctx.font = '10px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(pin.label, px, py - 20);\n }\n });\n }\n\n // === No Data Message ===\n if (allSatellites.length === 0 && groundStations.length === 0 && (!pins || pins.length === 0)) {\n ctx.fillStyle = COLORS.text;\n ctx.font = '12px \"Inter\", system-ui, sans-serif';\n ctx.textAlign = 'center';\n ctx.fillText(emptyMessage, W / 2, H / 2);\n }\n }, [allSatellites, groundStations, height, showTerminator, terminatorTime, showGrid, showLegend, showEquator, lonToX, latToY, COLORS, emptyMessage, pins, lightSources, tokens.colors.accent.primary]);\n\n // Tooltip on mouse move\n const handleMouseMove = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const rect = canvas.getBoundingClientRect();\n const mx = e.clientX - rect.left;\n const my = e.clientY - rect.top;\n const W = rect.width;\n const H = typeof height === 'number' ? height : rect.height;\n\n // Check satellite positions\n for (const sat of allSatellites) {\n if (!sat.groundTrack.length) continue;\n const futureIdx = sat.futureTrackIndex ?? sat.groundTrack.length;\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, sat.groundTrack.length - 1) : sat.groundTrack.length - 1;\n const lastPt = sat.groundTrack[currentIdx];\n const sx = lonToX(lastPt.longitude, W);\n const sy = latToY(lastPt.latitude, H);\n const dist = Math.sqrt((mx - sx) ** 2 + (my - sy) ** 2);\n if (dist < 18) {\n const satStatus = sat.status || 'normal';\n setTooltip({\n x: e.clientX - rect.left + 15,\n y: e.clientY - rect.top - 10,\n type: 'satellite',\n name: sat.name,\n status: satStatus,\n statusColor: STATUS_COLOR_MAP[satStatus] || STATUS_COLOR_MAP.normal,\n lat: lastPt.latitude,\n lon: lastPt.longitude,\n alt: lastPt.altitude,\n trackColor: sat.color || DEFAULT_TRACK_COLORS[allSatellites.indexOf(sat) % DEFAULT_TRACK_COLORS.length],\n hasFootprint: sat.showFootprint,\n futurePoints: sat.groundTrack.length - futureIdx,\n pastPoints: futureIdx,\n });\n return;\n }\n }\n\n // Check ground stations\n for (const gs of groundStations) {\n const gx = lonToX(gs.longitude, W);\n const gy = latToY(gs.latitude, H);\n const dist = Math.sqrt((mx - gx) ** 2 + (my - gy) ** 2);\n if (dist < 16) {\n const enhanced = gs as GroundStationEnhanced;\n const gsStatus = enhanced.status || 'standby';\n setTooltip({\n x: e.clientX - rect.left + 15,\n y: e.clientY - rect.top - 10,\n type: 'station',\n name: gs.name,\n status: gsStatus,\n statusColor: STATUS_COLOR_MAP[gsStatus] || STATUS_COLOR_MAP.standby,\n lat: gs.latitude,\n lon: gs.longitude,\n stationType: enhanced.type || 'dish',\n network: ('network' in gs && gs.network) ? String(gs.network) : undefined,\n coverageRadius: enhanced.coverageRadius,\n });\n return;\n }\n }\n\n setTooltip(null);\n }, [allSatellites, groundStations, height, lonToX, latToY]);\n\n const handleClick = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const rect = canvas.getBoundingClientRect();\n const mx = e.clientX - rect.left;\n const my = e.clientY - rect.top;\n const W = rect.width;\n const H = typeof height === 'number' ? height : rect.height;\n\n for (const sat of allSatellites) {\n if (!sat.groundTrack.length) continue;\n const futureIdx = sat.futureTrackIndex ?? sat.groundTrack.length;\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, sat.groundTrack.length - 1) : sat.groundTrack.length - 1;\n const currentPt = sat.groundTrack[currentIdx];\n const sx = lonToX(currentPt.longitude, W);\n const sy = latToY(currentPt.latitude, H);\n if (Math.sqrt((mx - sx) ** 2 + (my - sy) ** 2) < 15) {\n onSatelliteClick?.(sat.id);\n return;\n }\n }\n\n for (const gs of groundStations) {\n const gx = lonToX(gs.longitude, W);\n const gy = latToY(gs.latitude, H);\n if (Math.sqrt((mx - gx) ** 2 + (my - gy) ** 2) < 12) {\n onStationClick?.('id' in gs ? gs.id : gs.name);\n return;\n }\n }\n }, [allSatellites, groundStations, height, lonToX, latToY, onSatelliteClick, onStationClick]);\n\n useEffect(() => {\n draw();\n window.addEventListener('resize', draw);\n return () => window.removeEventListener('resize', draw);\n }, [draw]);\n\n // Leaflet backend: return after all hooks so hook count is stable\n const resolvedMinHeightForLeaflet = minHeight || (typeof height === 'number' ? `${height}px` : '400px');\n\n if (mapProvider === 'leaflet') {\n if (LeafletMap) {\n return (\n <div\n role=\"img\"\n aria-label={allSatellites.length > 0 || groundStations.length > 0 ? 'Ground track map showing satellite tracks and ground stations' : 'Ground track map'}\n style={{\n display: 'block',\n width: width ?? '100%',\n height: typeof height === 'string' ? height : undefined,\n minHeight: resolvedMinHeightForLeaflet,\n }}\n >\n <LeafletMap\n allSatellites={allSatellites}\n groundStations={groundStations}\n showTerminator={showTerminator}\n terminatorTime={terminatorTime}\n showGrid={showGrid}\n showLegend={showLegend}\n showEquator={showEquator}\n showRecenterButton={showRecenterButton}\n showMapStyleToggle={showMapStyleToggle}\n defaultCenter={leafletDefaultCenter}\n defaultZoom={leafletDefaultZoom}\n height={height}\n width={width}\n minHeight={minHeight}\n emptyMessage={emptyMessage}\n tileUrl={tileUrl}\n nightTileUrl={nightTileUrl}\n lightSources={lightSources}\n className={className}\n onSatelliteClick={onSatelliteClick}\n onStationClick={onStationClick}\n pins={pins}\n pinsEditable={pinsEditable}\n onPinAdd={onPinAdd}\n onPinUpdate={onPinUpdate}\n onPinRemove={onPinRemove}\n customLayers={customLayers}\n onLayerChange={onLayerChange}\n showCelestialMarkers={showCelestialMarkers}\n />\n </div>\n );\n }\n if (!leafletFailed) {\n return (\n <div\n className={`zendir-ground-track-map ${className}`}\n style={{\n width,\n height: typeof height === 'string' ? height : undefined,\n minHeight: resolvedMinHeightForLeaflet,\n backgroundColor: tokens.colors.background.base,\n borderRadius: 8,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ color: tokens.colors.text.secondary, fontSize: 14 }}>Loading map…</span>\n </div>\n );\n }\n }\n\n const resolvedMinHeight = minHeight || (typeof height === 'number' ? `${height}px` : '400px');\n\n // Loading state\n if (isLoading) {\n return (\n <div\n className={`zendir-ground-track-map ${className}`}\n style={{\n width,\n minHeight: resolvedMinHeight,\n backgroundColor: COLORS.background,\n borderRadius: '8px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ color: COLORS.text, fontSize: '14px', letterSpacing: '1px' }}>Loading…</span>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n role=\"img\"\n aria-label={allSatellites.length > 0 || groundStations.length > 0 ? 'Ground track map showing satellite tracks and ground stations' : 'Ground track map'}\n className={`zendir-ground-track-map ${className}`}\n style={{ width, height: typeof height === 'string' ? height : undefined, minHeight: resolvedMinHeight, backgroundColor: COLORS.background, borderRadius: '8px', overflow: 'hidden', position: 'relative' }}\n data-map-backend=\"canvas\"\n >\n {/* Hint when Leaflet was requested but failed (e.g. leaflet not installed) */}\n {mapProvider === 'leaflet' && leafletFailed && (\n <div\n style={{\n position: 'absolute',\n bottom: 8,\n left: 8,\n zIndex: 100,\n padding: '4px 8px',\n background: 'rgba(0,0,0,0.75)',\n color: '#fce83a',\n fontSize: 11,\n borderRadius: 4,\n }}\n >\n Static view (install <code style={{ fontFamily: 'monospace' }}>leaflet</code> for zoom/pan)\n </div>\n )}\n {/* Recenter button (SRO compat) */}\n {showRecenterButton && (\n <button\n type=\"button\"\n onClick={handleRecenter}\n title=\"Recenter Map\"\n aria-label=\"Recenter map\"\n style={{\n position: 'absolute',\n top: '8px',\n right: '8px',\n zIndex: 20,\n background: 'rgba(30, 41, 59, 0.85)',\n border: '1px solid rgba(100, 116, 139, 0.4)',\n borderRadius: '4px',\n color: '#fff',\n cursor: 'pointer',\n padding: '4px 8px',\n fontSize: '12px',\n lineHeight: '1',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M12 2v4M12 18v4M2 12h4M18 12h4\" />\n </svg>\n </button>\n )}\n\n <canvas\n ref={canvasRef}\n style={{ display: 'block', cursor: tooltip ? 'pointer' : 'default' }}\n onMouseMove={handleMouseMove}\n onMouseLeave={() => setTooltip(null)}\n onClick={handleClick}\n />\n {tooltip && (\n <div\n style={{\n position: 'absolute',\n left: tooltip.x,\n top: tooltip.y,\n background: 'rgba(15, 23, 42, 0.95)',\n backdropFilter: 'blur(8px)',\n border: `1px solid ${tooltip.statusColor}40`,\n borderRadius: '8px',\n padding: 0,\n pointerEvents: 'none',\n zIndex: 10,\n color: 'rgba(255, 255, 255, 0.9)',\n fontSize: '11px',\n fontFamily: '\"Inter\", system-ui, sans-serif',\n lineHeight: '1.5',\n boxShadow: `0 4px 16px rgba(0, 0, 0, 0.5), 0 0 12px ${tooltip.statusColor}15`,\n minWidth: 180,\n overflow: 'hidden',\n }}\n >\n {/* Header with status accent */}\n <div style={{\n padding: '6px 10px',\n borderBottom: `1px solid ${tooltip.statusColor}25`,\n background: `${tooltip.statusColor}10`,\n display: 'flex', alignItems: 'center', gap: 6,\n }}>\n <span style={{\n width: 8, height: 8, borderRadius: tooltip.status === 'caution' ? 1 : '50%',\n background: tooltip.statusColor, display: 'inline-block', flexShrink: 0,\n boxShadow: `0 0 4px ${tooltip.statusColor}88`,\n }} />\n <span style={{ fontWeight: 600, fontSize: 12 }}>{tooltip.name}</span>\n <span style={{\n marginLeft: 'auto', fontSize: 9, fontWeight: 600, textTransform: 'uppercase',\n color: tooltip.statusColor, letterSpacing: '0.5px',\n }}>\n {tooltip.status}\n </span>\n </div>\n {/* Details */}\n <div style={{ padding: '6px 10px', display: 'flex', flexDirection: 'column', gap: 3 }}>\n {/* Type badge */}\n <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>\n <span style={{\n fontSize: 9, fontWeight: 600, padding: '1px 5px',\n borderRadius: 3, textTransform: 'uppercase', letterSpacing: '0.3px',\n background: tooltip.type === 'satellite' ? 'rgba(45, 204, 255, 0.15)' : 'rgba(86, 240, 0, 0.15)',\n color: tooltip.type === 'satellite' ? '#2dccff' : '#56f000',\n }}>\n {tooltip.type === 'satellite' ? (\n <>\n <AstroIcon name=\"satellite\" size=\"extra-small\" label=\"Satellite\" style={{ marginRight: 4, verticalAlign: 'middle' }} />\n Satellite\n </>\n ) : (\n <>\n <AstroIcon name=\"antenna\" size=\"extra-small\" label={tooltip.stationType || 'Ground station'} style={{ marginRight: 4, verticalAlign: 'middle' }} />\n {tooltip.stationType || 'dish'}\n </>\n )}\n </span>\n {tooltip.network && (\n <span style={{\n fontSize: 9, padding: '1px 5px', borderRadius: 3,\n background: 'rgba(157, 112, 255, 0.15)', color: '#9D70FF',\n }}>\n {tooltip.network}\n </span>\n )}\n </div>\n {/* Coordinates */}\n <div style={{ display: 'grid', gridTemplateColumns: '52px 1fr', gap: '2px 8px', fontSize: 10 }}>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Lat</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.lat >= 0 ? '+' : ''}{tooltip.lat.toFixed(4)}°\n </span>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Lon</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.lon >= 0 ? '+' : ''}{tooltip.lon.toFixed(4)}°\n </span>\n {tooltip.alt !== undefined && (\n <>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Altitude</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.alt.toFixed(1)} km\n </span>\n </>\n )}\n {tooltip.coverageRadius !== undefined && (\n <>\n <span style={{ color: 'rgba(255,255,255,0.5)' }}>Coverage</span>\n <span style={{ fontFamily: '\"Roboto Mono\", monospace', fontWeight: 500 }}>\n {tooltip.coverageRadius.toFixed(1)}° radius\n </span>\n </>\n )}\n </div>\n {/* Satellite extras */}\n {tooltip.type === 'satellite' && (tooltip.pastPoints !== undefined || tooltip.futurePoints !== undefined) && (\n <div style={{ marginTop: 3, paddingTop: 3, borderTop: '1px solid rgba(255,255,255,0.08)', display: 'flex', gap: 10, fontSize: 9 }}>\n {tooltip.pastPoints !== undefined && (\n <span><span style={{ color: tooltip.trackColor }}>━</span> {tooltip.pastPoints} past pts</span>\n )}\n {tooltip.futurePoints !== undefined && tooltip.futurePoints > 0 && (\n <span><span style={{ color: `${tooltip.trackColor}88` }}>╌</span> {tooltip.futurePoints} predicted</span>\n )}\n {tooltip.hasFootprint && <span style={{ color: '#9D70FF' }}>◎ Footprint</span>}\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport default GroundTrackMap;\n"],"names":[],"mappings":";;;;AA8RA,MAAM,mBAA2C;AAAA,EAC/C,QAAQ;AAAA;AAAA,EACR,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,UAAU;AAAA;AAAA,EACV,KAAK;AAAA;AACP;AAEA,MAAM,uBAAuB;AAAA,EAC3B;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAC/E;AAOA,MAAM,kBAAkB;AAAA;AAAA,EAEtB;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AACF;AA+BA,SAAS,oBACP,KACA,WACA,WACA,WACA,GACA,GACA,QACA,QACA,cAAsB,IAChB;AACN,QAAM,OAAQ,YAAY,KAAK,KAAM;AACrC,QAAM,OAAQ,YAAY,KAAK,KAAM;AACrC,QAAM,IAAK,YAAY,KAAK,KAAM;AAIlC,QAAM,KAAK,OAAO,WAAW,CAAC;AAC9B,QAAM,KAAK,OAAO,WAAW,CAAC;AAC9B,QAAM,cAAc,IAAI;AACxB,QAAM,cAAc,IAAI;AAExB,MAAI,UAAA;AACJ,WAAS,IAAI,GAAG,KAAK,aAAa,KAAK;AACrC,UAAM,UAAW,IAAI,cAAe,IAAI,KAAK;AAG7C,UAAM,SAAS,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,OAAO;AAC7F,UAAM,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,MAAM,CAAC,CAAC;AACvD,UAAM,MAAM,OAAO,KAAK;AAAA,MACtB,KAAK,IAAI,OAAO,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI;AAAA,MAC/C,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI;AAAA,IAAA;AAGjC,UAAM,UAAW,MAAM,MAAO,KAAK;AACnC,UAAM,UAAW,MAAM,MAAO,KAAK;AAGnC,UAAM,OAAO,UAAU;AACvB,UAAM,OAAO,UAAU;AACvB,UAAM,KAAK,KAAK,OAAO;AACvB,UAAM,KAAK,KAAK,OAAO;AAEvB,QAAI,MAAM,EAAG,KAAI,OAAO,IAAI,EAAE;AAAA,QACzB,KAAI,OAAO,IAAI,EAAE;AAAA,EACxB;AACA,MAAI,UAAA;AACN;AAIA,SAAS,SAAS,KAAuC;AACvD,QAAM,IAAI,IAAI,QAAQ,KAAK,EAAE;AAC7B,MAAI,EAAE,WAAW,GAAG;AAClB,WAAO,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;AAAA,EACzF;AACA,MAAI,EAAE,UAAU,GAAG;AACjB,WAAO,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;AAAA,EAC/F;AACA,SAAO,CAAC,KAAK,KAAK,GAAG;AACvB;AAiDA,SAAS,8BACP,MACA,gBAAwB,GACxB,YAAoB,KACmD;AACvE,QAAM,YAAY,KAAK,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,eAAA,GAAkB,GAAG,CAAC,KAAK,KAAQ;AAChG,QAAM,cAAc,SAAS,KAAK,IAAK,IAAI,KAAK,KAAK,OAAQ,YAAY,GAAG;AAC5E,QAAM,SAAU,cAAc,KAAK,KAAM;AAGzC,QAAM,IAAK,IAAI,KAAK,KAAK,OAAQ,YAAY;AAC7C,QAAM,aAAa,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,MAAM,KAAK,IAAI,CAAC;AAIjF,QAAM,WAAW,KAAK,YAAA,IAAgB,KAAK,kBAAkB,KAAK,KAAK,cAAA,IAAkB;AACzF,QAAM,aAAa,WAAW,aAAa;AAC3C,QAAM,cAAc,EAAE,aAAa,MAAM;AACzC,QAAM,SAAU,gBAAgB,KAAK,KAAM;AAE3C,QAAM,SAAkC,CAAA;AACxC,QAAM,UAAmC,CAAA;AAEzC,WAAS,IAAI,GAAG,KAAK,WAAW,KAAK;AACnC,UAAM,MAAM,UAAW,IAAI,YAAa;AACxC,UAAM,SAAS,OAAO,KAAK,KAAK;AAChC,UAAM,OAAO,EAAE,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,MACnD,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM;AAEnD,QAAI,OAAO,GAAI;AAAA,aAEJ,OAAO,GAAG;AAEnB,aAAO,KAAK,CAAC,KAAK,WAAW,CAAC;AAC9B,cAAQ,KAAK,CAAC,KAAK,cAAc,GAAG,CAAC;AAAA,IACvC,OAAO;AACL,YAAM,IAAK,KAAK,KAAK,IAAI,IAAI,MAAO,KAAK;AAEzC,aAAO,KAAK,CAAC,KAAK,cAAc,CAAC,CAAC;AAElC,cAAQ,KAAK,CAAC,KAAK,cAAc,MAAM,CAAC,CAAC;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,QAAA;AACnB;AAEA,SAAS,kBACP,YACoB;AACpB,QAAM,EAAE,QAAQ,QAAA,IAAY;AAC5B,MAAI,CAAC,OAAO,UAAU,CAAC,QAAQ,eAAe,CAAA;AAE9C,QAAM,OAA2B,CAAA;AAGjC,OAAK,KAAK,GAAG,MAAM;AAGnB,OAAK,KAAK,GAAG,CAAC,GAAG,OAAO,EAAE,SAAS;AAEnC,SAAO;AACT;AAMO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,aAAa,CAAA;AAAA,EACb,iBAAiB,CAAA;AAAA,EACjB;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4C;AAC1C,QAAM,EAAE,OAAA,IAAW,SAAA;AACnB,QAAM,YAAY,OAA0B,IAAI;AAChD,QAAM,eAAe,OAAuB,IAAI;AAChD,QAAM,CAAC,SAAS,UAAU,IAAI,SAkBpB,IAAI;AAEd,QAAM,CAAC,aAAa,aAAa,IAAI,SAAmC,EAAE,GAAG,GAAG,GAAG,GAAG;AAGtF,QAAM,gBAAgB,QAA0B,MAAM;AAEpD,QAAI,WAAW,SAAS,EAAG,QAAO;AAElC,QAAI,aAAa,UAAU,SAAS,GAAG;AACrC,aAAO,UAAU,IAAI,CAAC,IAAI,SAAS;AAAA,QACjC,IAAI,QAAQ,GAAG;AAAA,QACf,MAAM,GAAG;AAAA,QACT,OAAO,GAAG;AAAA,QACV,QAAQ;AAAA,QACR,aAAa,GAAG,UACb,OAAO,CAAA,MAAK,EAAE,OAAO,QAAQ,EAAE,OAAO,IAAI,EAC1C,IAAI,CAAA,OAAM;AAAA,UACT,UAAU,EAAE;AAAA,UACZ,WAAW,EAAE;AAAA,UACb,UAAU,EAAE,YAAY;AAAA,UACxB,WAAW,EAAE,QAAQ,OAAO,IAAI,KAAK,EAAE,OAAO,GAAI,EAAE,YAAA,KAAgB,oBAAI,KAAA,GAAO,YAAA;AAAA,QAAY,EAC3F;AAAA,MAAA,EACJ;AAAA,IACJ;AAEA,QAAI,eAAe,YAAY,SAAS,GAAG;AACzC,aAAO,CAAC;AAAA,QACN,IAAI;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MAAA,CACD;AAAA,IACH;AACA,WAAO,CAAA;AAAA,EACT,GAAG,CAAC,YAAY,aAAa,YAAY,SAAS,CAAC;AAGnD,QAAM,uBAAuB,QAA0B,MAAM,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC;AACtG,QAAM,qBAAqB,QAAQ,MAAM,eAAe,GAAG,CAAC,WAAW,CAAC;AAGxE,QAAM,CAAC,YAAY,aAAa,IAAI,SAAiE,IAAI;AACzG,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AAExD,YAAU,MAAM;AACd,QAAI,gBAAgB,UAAW;AAC/B,WAAO,4BAAyB,EAC7B,KAAK,CAAC,MAAM,cAAc,MAAM,EAAE,qBAAqB,CAAC,EACxD,MAAM,CAAC,QAAQ;AACd,cAAQ,KAAK,kIAAkI,GAAG;AAClJ,uBAAiB,IAAI;AAAA,IACvB,CAAC;AAAA,EACL,GAAG,CAAC,WAAW,CAAC;AAIhB,QAAM,iBAAiB,YAAY,MAAM;AACvC,kBAAc,EAAE,GAAG,GAAG,GAAG,GAAG;AAAA,EAC9B,GAAG,CAAA,CAAE;AAEL,QAAM,SAAS,QAAQ,OAAO;AAAA,IAC5B,YAAY,OAAO,OAAO,WAAW;AAAA,IACrC,MAAM,OAAO,OAAO,OAAO;AAAA,IAC3B,MAAM,OAAO,OAAO,KAAK;AAAA,IACzB,QAAQ,OAAO,OAAO,OAAO;AAAA,IAC7B,MAAM;AAAA,IACN,OAAO,OAAO,OAAO,WAAW;AAAA,IAChC,OAAO;AAAA,IACP,SAAS;AAAA,EAAA,IACP,CAAC,MAAM,CAAC;AAEZ,QAAM,SAAS,YAAY,CAAC,KAAa,MAAc;AACrD,QAAI,gBAAgB;AACpB,WAAO,gBAAgB,IAAK,kBAAiB;AAC7C,WAAO,gBAAgB,KAAM,kBAAiB;AAC9C,YAAS,gBAAgB,OAAO,MAAO;AAAA,EACzC,GAAG,CAAA,CAAE;AAEL,QAAM,SAAS,YAAY,CAAC,KAAa,MAAc;AACrD,YAAS,KAAK,OAAO,MAAO;AAAA,EAC9B,GAAG,CAAA,CAAE;AAEL,QAAM,OAAO,YAAY,MAAM;AAC7B,UAAM,SAAS,UAAU;AACzB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,UAAU,CAAC,UAAW;AAE3B,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK;AAEV,UAAM,MAAM,OAAO,oBAAoB;AACvC,UAAM,OAAO,UAAU,sBAAA;AACvB,UAAM,IAAI,KAAK;AAEf,UAAM,IAAI,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU;AAE/D,WAAO,QAAQ,IAAI;AACnB,WAAO,SAAS,IAAI;AACpB,WAAO,MAAM,QAAQ,GAAG,CAAC;AACzB,WAAO,MAAM,SAAS,GAAG,CAAC;AAC1B,QAAI,MAAM,KAAK,GAAG;AAGlB,QAAI,YAAY,OAAO;AACvB,QAAI,SAAS,GAAG,GAAG,GAAG,CAAC;AAKvB,QAAI,gBAAgB;AAClB,YAAM,MAAM,kBAAkB,oBAAI,KAAA;AAElC,YAAM,YAAY;AAClB,YAAM,UAAU;AAChB,YAAM,cAAc;AACpB,YAAM,YAA0D,CAAA;AAChE,eAAS,IAAI,GAAG,KAAK,SAAS,KAAK,WAAW;AAC5C,cAAM,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC;AAC5B,cAAM,QAAQ,KAAK,IAAI,GAAG,GAAG,KAAK,cAAc,SAAS,IAAI,MAAM,IAAI,MAAM,MAAM,cAAc,QAAQ;AACzG,kBAAU,KAAK,EAAE,YAAY,GAAG,OAAO,KAAK,IAAI,OAAO,WAAW,GAAG;AAAA,MACvE;AACA,gBAAU,KAAK,EAAE,YAAY,IAAI,OAAO,aAAa;AAErD,UAAI,YAAY;AAChB,iBAAW,QAAQ,WAAW;AAC5B,cAAM,MAAM,KAAK,IAAI,KAAK,YAAY,EAAE;AACxC,cAAM,YAAY,KAAK,QAAQ;AAC/B,YAAI,YAAY,MAAO;AAAE,sBAAY,KAAK;AAAO;AAAA,QAAU;AAE3D,cAAM,aAAa,8BAA8B,KAAK,GAAG;AACzD,YAAI,WAAW,OAAO,WAAW,GAAG;AAAE,sBAAY,KAAK;AAAO;AAAA,QAAU;AAExE,cAAM,OAAO,kBAAkB,UAAU;AACzC,YAAI,KAAK,SAAS,GAAG;AAAE,sBAAY,KAAK;AAAO;AAAA,QAAU;AAEzD,YAAI,YAAY,oBAAoB,UAAU,QAAQ,CAAC,CAAC;AAGxD,mBAAW,UAAU,CAAC,MAAM,GAAG,GAAG,GAAG;AACnC,cAAI,UAAA;AACJ,mBAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,kBAAM,MAAM,KAAK,CAAC,EAAE,CAAC;AACrB,kBAAM,MAAM,KAAK,CAAC,EAAE,CAAC,IAAI;AACzB,kBAAM,IAAI,OAAO,KAAK,CAAC;AACvB,kBAAM,IAAI,OAAO,KAAK,CAAC;AAKvB,gBAAI,MAAM,GAAG;AACX,kBAAI,OAAO,GAAG,CAAC;AAAA,YACjB,OAAO;AAKL,kBAAI,OAAO,GAAG,CAAC;AAAA,YACjB;AAAA,UACF;AACA,cAAI,UAAA;AACJ,cAAI,KAAA;AAAA,QACN;AAEA,oBAAY,KAAK;AAAA,MACnB;AAGA,YAAM,iBAAiB,8BAA8B,KAAK,CAAC;AAC3D,UAAI,eAAe,OAAO,SAAS,GAAG;AACpC,YAAI,KAAA;AAEJ,YAAI,cAAc;AAClB,YAAI,YAAY;AAChB,mBAAW,SAAS,CAAC,eAAe,QAAQ,eAAe,OAAO,GAAG;AACnE,qBAAW,UAAU,CAAC,MAAM,GAAG,GAAG,GAAG;AACnC,gBAAI,UAAA;AACJ,qBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,oBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC;AACxC,oBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC/B,kBAAI,MAAM,EAAG,KAAI,OAAO,GAAG,CAAC;AAAA,kBACvB,KAAI,OAAO,GAAG,CAAC;AAAA,YACtB;AACA,gBAAI,OAAA;AAAA,UACN;AAAA,QACF;AAEA,YAAI,cAAc;AAClB,YAAI,YAAY;AAChB,mBAAW,SAAS,CAAC,eAAe,QAAQ,eAAe,OAAO,GAAG;AACnE,qBAAW,UAAU,CAAC,MAAM,GAAG,GAAG,GAAG;AACnC,gBAAI,UAAA;AACJ,qBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,oBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC;AACxC,oBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC;AAC/B,kBAAI,MAAM,EAAG,KAAI,OAAO,GAAG,CAAC;AAAA,kBACvB,KAAI,OAAO,GAAG,CAAC;AAAA,YACtB;AACA,gBAAI,OAAA;AAAA,UACN;AAAA,QACF;AACA,YAAI,QAAA;AAAA,MACN;AAAA,IAiDF;AAGA,QAAI,YAAY,OAAO;AACvB,QAAI,cAAc;AAClB,QAAI,YAAY;AAEhB,eAAW,WAAW,iBAAiB;AACrC,YAAM,WAAW,QAAQ,MAAM,GAAG;AAClC,UAAI,UAAA;AACJ,iBAAW,OAAO,UAAU;AAC1B,YAAI,IAAI,WAAW,GAAG,KAAK,IAAI,WAAW,GAAG,GAAG;AAC9C,gBAAM,SAAS,IAAI,UAAU,CAAC,EAAE,MAAM,GAAG;AACzC,gBAAM,MAAM,WAAW,OAAO,CAAC,CAAC;AAChC,gBAAM,MAAM,WAAW,OAAO,CAAC,CAAC;AAChC,gBAAM,IAAI,OAAO,KAAK,CAAC;AACvB,gBAAM,IAAI,OAAO,KAAK,CAAC;AACvB,cAAI,IAAI,WAAW,GAAG,EAAG,KAAI,OAAO,GAAG,CAAC;AAAA,cACnC,KAAI,OAAO,GAAG,CAAC;AAAA,QACtB,WAAW,QAAQ,KAAK;AACtB,cAAI,UAAA;AAAA,QACN;AAAA,MACF;AACA,UAAI,KAAA;AACJ,UAAI,OAAA;AAAA,IACN;AAGA,QAAI,UAAU;AACZ,UAAI,cAAc,OAAO;AACzB,UAAI,YAAY;AAChB,eAAS,MAAM,MAAM,OAAO,KAAK,OAAO,IAAI;AAC1C,cAAM,IAAI,OAAO,KAAK,CAAC;AACvB,YAAI,UAAA;AAAa,YAAI,OAAO,GAAG,CAAC;AAAG,YAAI,OAAO,GAAG,CAAC;AAAG,YAAI,OAAA;AAAA,MAC3D;AACA,eAAS,MAAM,KAAK,OAAO,IAAI,OAAO,IAAI;AACxC,cAAM,IAAI,OAAO,KAAK,CAAC;AACvB,YAAI,UAAA;AAAa,YAAI,OAAO,GAAG,CAAC;AAAG,YAAI,OAAO,GAAG,CAAC;AAAG,YAAI,OAAA;AAAA,MAC3D;AAAA,IACF;AAGA,QAAI,aAAa;AACf,YAAM,MAAM,OAAO,GAAG,CAAC;AACvB,UAAI,cAAc,OAAO;AACzB,UAAI,YAAY;AAChB,UAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AACtB,UAAI,UAAA;AAAa,UAAI,OAAO,GAAG,GAAG;AAAG,UAAI,OAAO,GAAG,GAAG;AAAG,UAAI,OAAA;AAC7D,UAAI,YAAY,EAAE;AAAA,IACpB;AAGA,eAAW,MAAM,gBAAgB;AAC/B,YAAM,WAAW;AACjB,UAAI,SAAS,gBAAgB,SAAS,gBAAgB;AACpD,cAAM,cAAc,iBAAiB,SAAS,UAAU,SAAS,KAAK,iBAAiB;AAIvF,4BAAoB,KAAK,GAAG,UAAU,GAAG,WAAW,SAAS,gBAAgB,GAAG,GAAG,QAAQ,MAAM;AACjG,YAAI,YAAY,GAAG,WAAW;AAC9B,YAAI,KAAA;AACJ,YAAI,cAAc,GAAG,WAAW;AAChC,YAAI,YAAY;AAChB,YAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AACtB,YAAI,OAAA;AACJ,YAAI,YAAY,EAAE;AAAA,MACpB;AAAA,IACF;AAGA,eAAW,MAAM,gBAAgB;AAC/B,YAAM,WAAW;AACjB,YAAM,IAAI,OAAO,GAAG,WAAW,CAAC;AAChC,YAAM,IAAI,OAAO,GAAG,UAAU,CAAC;AAC/B,YAAM,SAAS,SAAS,UAAU;AAClC,YAAM,cAAc,iBAAiB,MAAM,KAAK,iBAAiB;AACjE,YAAM,cAAc,SAAS,QAAQ;AACrC,YAAM,WAAW;AACjB,YAAM,WAAW,WAAW;AAE5B,UAAI,KAAA;AACJ,UAAI,UAAU,GAAG,CAAC;AAGlB,UAAI,UAAA;AACJ,UAAI,IAAI,GAAG,GAAG,WAAW,GAAG,GAAG,KAAK,KAAK,CAAC;AAC1C,UAAI,YAAY,GAAG,WAAW;AAC9B,UAAI,KAAA;AAGJ,UAAI,UAAA;AACJ,UAAI,IAAI,GAAG,GAAG,UAAU,GAAG,KAAK,KAAK,CAAC;AACtC,UAAI,YAAY;AAChB,UAAI,KAAA;AACJ,UAAI,cAAc,GAAG,WAAW;AAChC,UAAI,YAAY;AAChB,UAAI,OAAA;AAGJ,UAAI,KAAA;AACJ,YAAM,YAAY,WAAW;AAC7B,UAAI,UAAU,CAAC,UAAU,CAAC,QAAQ;AAClC,UAAI,MAAM,WAAW,SAAS;AAE9B,UAAI,gBAAgB,UAAU,gBAAgB,QAAQ;AAEpD,YAAI,cAAc;AAClB,YAAI,YAAY;AAChB,YAAI,YAAY,IAAI;AAEpB,YAAI,UAAA;AAAa,YAAI,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK,MAAM,KAAK,KAAK,IAAI;AAAG,YAAI,OAAA;AAE1E,YAAI,UAAA;AAAa,YAAI,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAAG,YAAI,OAAA;AAEzE,YAAI,UAAA;AAAa,YAAI,IAAI,IAAI,IAAI,GAAG,KAAK,KAAK,MAAM,KAAK,KAAK,IAAI;AAAG,YAAI,OAAA;AAEzE,YAAI,UAAA;AAAa,YAAI,IAAI,IAAI,IAAI,KAAK,GAAG,KAAK,KAAK,CAAC;AAAG,YAAI,KAAA;AAE3D,YAAI,YAAY,MAAM;AACtB,YAAI,UAAA;AAAa,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAA;AAC7D,YAAI,UAAA;AAAa,YAAI,OAAO,GAAG,EAAE;AAAG,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAA;AAAA,MAC9D,WAAW,gBAAgB,gBAAgB;AAEzC,YAAI,cAAc;AAClB,YAAI,YAAY;AAChB,YAAI,YAAY,MAAM;AACtB,YAAI,WAAW,GAAG,GAAG,IAAI,EAAE;AAE3B,iBAAS,KAAK,GAAG,MAAM,IAAI,MAAM,GAAG;AAClC,cAAI,UAAA;AAAa,cAAI,OAAO,IAAI,CAAC;AAAG,cAAI,OAAO,IAAI,EAAE;AAAG,cAAI,OAAA;AAAA,QAC9D;AACA,iBAAS,KAAK,GAAG,MAAM,IAAI,MAAM,GAAG;AAClC,cAAI,UAAA;AAAa,cAAI,OAAO,GAAG,EAAE;AAAG,cAAI,OAAO,IAAI,EAAE;AAAG,cAAI,OAAA;AAAA,QAC9D;AAEA,YAAI,UAAA;AAAa,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAA;AAC7D,YAAI,UAAA;AAAa,YAAI,OAAO,GAAG,EAAE;AAAG,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAA;AAAA,MAC9D,OAAO;AAEL,YAAI,cAAc;AAClB,YAAI,YAAY;AAChB,YAAI,YAAY,IAAI;AAEpB,YAAI,UAAA;AAAa,YAAI,IAAI,IAAI,IAAI,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAAG,YAAI,OAAA;AAEvE,YAAI,YAAY,MAAM;AACtB,YAAI,UAAA;AAAa,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAO,IAAI,CAAC;AAAG,YAAI,OAAA;AAE5D,YAAI,YAAY,MAAM;AACtB,YAAI,UAAA;AAAa,YAAI,IAAI,IAAI,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAAG,YAAI,OAAA;AACxE,YAAI,UAAA;AAAa,YAAI,IAAI,IAAI,GAAG,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,IAAI;AAAG,YAAI,OAAA;AAE1E,YAAI,YAAY,MAAM;AACtB,YAAI,UAAA;AAAa,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAA;AAC7D,YAAI,UAAA;AAAa,YAAI,OAAO,GAAG,EAAE;AAAG,YAAI,OAAO,IAAI,EAAE;AAAG,YAAI,OAAA;AAAA,MAC9D;AAEA,UAAI,QAAA;AAGJ,YAAM,SAAS,CAAC,WAAW;AAC3B,YAAM,SAAS,CAAC,WAAW;AAC3B,YAAM,YAAY;AAGlB,UAAI,UAAA;AACJ,UAAI,IAAI,QAAQ,QAAQ,YAAY,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AACzD,UAAI,YAAY;AAChB,UAAI,KAAA;AAMJ,UAAI,YAAY;AAChB,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,WAAW,UAAU;AAEvB,YAAI,UAAA;AACJ,YAAI,IAAI,QAAQ,QAAQ,YAAY,GAAG,GAAG,KAAK,KAAK,CAAC;AACrD,YAAI,KAAA;AAAA,MACN,WAAW,WAAW,WAAW;AAE/B,YAAI,UAAA;AACJ,YAAI,IAAI,QAAQ,QAAQ,YAAY,IAAI,KAAK,GAAG,KAAK,KAAK,CAAC;AAC3D,YAAI,YAAY;AAChB,YAAI,OAAA;AAAA,MACN,WAAW,WAAW,WAAW;AAE/B,cAAM,KAAK,YAAY;AACvB,YAAI,SAAS,SAAS,IAAI,SAAS,IAAI,WAAW,SAAS;AAAA,MAC7D,WAAW,WAAW,WAAW;AAE/B,cAAM,KAAK,YAAY;AACvB,YAAI,UAAA;AACJ,YAAI,OAAO,QAAQ,SAAS,EAAE;AAC9B,YAAI,OAAO,SAAS,IAAI,MAAM;AAC9B,YAAI,OAAO,QAAQ,SAAS,EAAE;AAC9B,YAAI,OAAO,SAAS,IAAI,MAAM;AAC9B,YAAI,UAAA;AACJ,YAAI,KAAA;AAAA,MACN,WAAW,WAAW,YAAY;AAEhC,cAAM,KAAK,YAAY;AACvB,YAAI,UAAA;AACJ,YAAI,OAAO,QAAQ,SAAS,EAAE;AAC9B,YAAI,OAAO,SAAS,IAAI,SAAS,EAAE;AACnC,YAAI,OAAO,SAAS,IAAI,SAAS,EAAE;AACnC,YAAI,UAAA;AACJ,YAAI,KAAA;AAAA,MACN,OAAO;AAEL,YAAI,UAAA;AACJ,YAAI,IAAI,QAAQ,QAAQ,YAAY,GAAG,GAAG,KAAK,KAAK,CAAC;AACrD,YAAI,KAAA;AAAA,MACN;AAEA,UAAI,QAAA;AAGJ,UAAI,YAAY,OAAO;AACvB,UAAI,OAAO;AACX,UAAI,YAAY;AAChB,UAAI,SAAS,GAAG,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM,GAAG,MAAM,GAAG,IAAI,WAAW,EAAE;AAAA,IAC/F;AAGA,QAAI,gBAAgB,aAAa,SAAS,KAAK,gBAAgB;AAC7D,YAAM,MAAM,kBAAkB,oBAAI,KAAA;AAElC,iBAAW,SAAS,cAAc;AAChC,cAAM,KAAK,OAAO,MAAM,WAAW,CAAC;AACpC,cAAM,KAAK,OAAO,MAAM,UAAU,CAAC;AACnC,cAAM,IAAI,MAAM,UAAU;AAC1B,cAAM,YAAY,MAAM,aAAa;AACrC,cAAM,QAAQ,MAAM,SAAS;AAK7B,cAAM,YAAY,KAAK,OAAO,IAAI,YAAY,KAAK,IAAI,IAAI,eAAA,GAAkB,GAAG,CAAC,KAAK,KAAQ;AAC9F,cAAM,cAAc,SAAS,KAAK,IAAK,IAAI,KAAK,KAAK,OAAQ,YAAY,GAAG;AAC5E,cAAM,SAAU,cAAc,KAAK,KAAM;AACzC,cAAM,gBAAgB,EAAG,IAAI,YAAA,IAAgB,IAAI,kBAAkB,KAAM,MAAM;AAC/E,cAAM,SAAU,MAAM,WAAW,KAAK,KAAM;AAG5C,cAAM,SAAS,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IACjC,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IAClC,KAAK,KAAM,MAAM,YAAY,iBAAiB,KAAK,KAAM,GAAG;AAC5E,cAAM,cAAe,KAAK,KAAK,MAAM,IAAI,MAAO,KAAK;AAGrD,YAAI;AACJ,YAAI,eAAe,EAAG,eAAc;AAAA,iBAC3B,eAAe,IAAK,eAAc;AAAA,2BACxB,KAAK,IAAI,GAAG,CAAC,cAAc,EAAE;AAEhD,YAAI,cAAc,KAAM;AAExB,cAAM,QAAQ,YAAY;AAC1B,cAAM,CAAC,IAAI,IAAI,EAAE,IAAI,SAAS,KAAK;AACnC,cAAM,OAAO,IAAI,qBAAqB,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC;AAC9D,aAAK,aAAa,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,KAAK,GAAG;AAC1D,aAAK,aAAa,KAAK,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,QAAQ,GAAG,GAAG;AAClE,aAAK,aAAa,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM;AAEnD,YAAI,YAAY;AAChB,YAAI,UAAA;AACJ,YAAI,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AACrC,YAAI,KAAA;AAGJ,YAAI,YAAY,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,QAAQ,GAAG,CAAC;AACrE,YAAI,UAAA;AACJ,YAAI,IAAI,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,KAAK,KAAK,CAAC;AACpD,YAAI,KAAA;AAAA,MACN;AAAA,IACF;AAGA,kBAAc,QAAQ,CAAC,KAAK,WAAW;AACrC,YAAM,QAAQ,IAAI;AAClB,UAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAElC,YAAM,aAAa,IAAI,SAAS,qBAAqB,SAAS,qBAAqB,MAAM;AACzF,YAAM,YAAY,IAAI,oBAAoB,MAAM;AAGhD,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,WAAW;AACf,UAAI,YAAY,EAAE;AAClB,UAAI,UAAA;AAEJ,UAAI,QAAQ,OAAO,MAAM,CAAC,EAAE,WAAW,CAAC;AACxC,UAAI,QAAQ,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC;AACvC,UAAI,OAAO,OAAO,KAAK;AAEvB,eAAS,IAAI,GAAG,IAAI,KAAK,IAAI,WAAW,MAAM,MAAM,GAAG,KAAK;AAC1D,cAAM,IAAI,OAAO,MAAM,CAAC,EAAE,WAAW,CAAC;AACtC,cAAM,IAAI,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC;AACrC,cAAM,kBAAkB,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI;AAClD,YAAI,iBAAiB;AACnB,cAAI,OAAA;AAAU,cAAI,UAAA;AAAa,cAAI,OAAO,GAAG,CAAC;AAAA,QAChD,OAAO;AACL,cAAI,OAAO,GAAG,CAAC;AAAA,QACjB;AACA,gBAAQ;AAAG,gBAAQ;AAAA,MACrB;AACA,UAAI,OAAA;AAGJ,UAAI,YAAY,MAAM,QAAQ;AAC5B,YAAI,cAAc,GAAG,UAAU;AAC/B,YAAI,YAAY;AAChB,YAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AACtB,YAAI,UAAA;AACJ,YAAI,OAAO,OAAO,MAAM,SAAS,EAAE,WAAW,CAAC,GAAG,OAAO,MAAM,SAAS,EAAE,UAAU,CAAC,CAAC;AACtF,YAAI,MAAM,OAAO,MAAM,SAAS,EAAE,WAAW,CAAC;AAE9C,iBAAS,IAAI,YAAY,GAAG,IAAI,MAAM,QAAQ,KAAK;AACjD,gBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,WAAW,CAAC;AACtC,gBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC;AACrC,cAAI,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,GAAG;AAC7B,gBAAI,OAAA;AAAU,gBAAI,UAAA;AAAa,gBAAI,OAAO,GAAG,CAAC;AAAA,UAChD,OAAO;AACL,gBAAI,OAAO,GAAG,CAAC;AAAA,UACjB;AACA,gBAAM;AAAA,QACR;AACA,YAAI,OAAA;AACJ,YAAI,YAAY,EAAE;AAAA,MACpB;AAGA,UAAI,IAAI,cAAc,IAAI,WAAW,KAAK,OAAO,GAAG;AAClD,YAAI,cAAc,iBAAiB;AACnC,YAAI,YAAY;AAChB,YAAI,YAAY,EAAE;AAClB,YAAI,UAAA;AACJ,YAAI,UAAU;AACd,YAAI,MAAM,OAAO,MAAM,CAAC,EAAE,WAAW,CAAC;AAEtC,iBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,WAAW,CAAC;AACtC,gBAAM,IAAI,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC;AACrC,gBAAM,SAAS,IAAI,WAAW,CAAC;AAC/B,gBAAM,kBAAkB,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI;AAEzD,cAAI,UAAU,CAAC,iBAAiB;AAC9B,gBAAI,CAAC,SAAS;AAAE,kBAAI,OAAO,GAAG,CAAC;AAAG,wBAAU;AAAA,YAAM,MAC7C,KAAI,OAAO,GAAG,CAAC;AAAA,UACtB,OAAO;AACL,gBAAI,SAAS;AAAE,kBAAI,OAAA;AAAU,kBAAI,UAAA;AAAa,wBAAU;AAAA,YAAO;AAAA,UACjE;AACA,gBAAM;AAAA,QACR;AACA,YAAI,aAAa,OAAA;AAAA,MACnB;AAGA,UAAI,IAAI,aAAa;AACnB,mBAAW,UAAU,IAAI,aAAa;AACpC,gBAAM,KAAK,OAAO,OAAO,WAAW,CAAC;AACrC,gBAAM,KAAK,OAAO,OAAO,UAAU,CAAC;AACpC,gBAAM,cAAc,OAAO,SAAS,QAAQ,iBAAiB,SAAS,iBAAiB;AAEvF,cAAI,KAAA;AACJ,cAAI,UAAU,IAAI,EAAE;AAEpB,cAAI,UAAA;AACJ,cAAI,OAAO,SAAS,OAAO;AACzB,gBAAI,OAAO,GAAG,EAAE;AAAG,gBAAI,OAAO,GAAG,CAAC;AAAG,gBAAI,OAAO,IAAI,CAAC;AAAA,UACvD,OAAO;AACL,gBAAI,OAAO,GAAG,CAAC;AAAG,gBAAI,OAAO,GAAG,EAAE;AAAG,gBAAI,OAAO,IAAI,EAAE;AAAA,UACxD;AACA,cAAI,UAAA;AACJ,cAAI,YAAY;AAChB,cAAI,KAAA;AACJ,cAAI,QAAA;AAEJ,cAAI,OAAO,OAAO;AAChB,gBAAI,YAAY;AAChB,gBAAI,OAAO;AACX,gBAAI,YAAY;AAChB,gBAAI,SAAS,OAAO,OAAO,IAAI,OAAO,SAAS,QAAQ,KAAK,IAAI,KAAK,EAAE;AAAA,UACzE;AAAA,QACF;AAAA,MACF;AAGA,UAAI,IAAI,iBAAiB,IAAI,iBAAiB;AAC5C,cAAM,SAAS,YAAY,IAAI,MAAM,KAAK,IAAI,YAAY,GAAG,MAAM,SAAS,CAAC,CAAC,IAAI,MAAM,MAAM,SAAS,CAAC;AAExG,4BAAoB,KAAK,OAAO,UAAU,OAAO,WAAW,IAAI,iBAAiB,GAAG,GAAG,QAAQ,MAAM;AACrG,YAAI,YAAY,GAAG,UAAU;AAC7B,YAAI,KAAA;AACJ,YAAI,cAAc,GAAG,UAAU;AAC/B,YAAI,YAAY;AAChB,YAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AACtB,YAAI,OAAA;AACJ,YAAI,YAAY,EAAE;AAAA,MACpB;AAGA,YAAM,aAAa,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS;AAC9F,YAAM,UAAU,MAAM,UAAU;AAChC,YAAM,KAAK,OAAO,QAAQ,WAAW,CAAC;AACtC,YAAM,KAAK,OAAO,QAAQ,UAAU,CAAC;AACrC,YAAM,YAAY,IAAI,UAAU;AAChC,YAAM,cAAc,iBAAiB,SAAS,KAAK,iBAAiB;AACpE,YAAM,cAAc;AACpB,YAAM,UAAU,cAAc;AAG9B,UAAI,UAAA;AACJ,UAAI,IAAI,IAAI,IAAI,UAAU,GAAG,GAAG,KAAK,KAAK,CAAC;AAC3C,UAAI,YAAY,GAAG,WAAW;AAC9B,UAAI,KAAA;AAEJ,UAAI,UAAA;AACJ,UAAI,IAAI,IAAI,IAAI,UAAU,GAAG,GAAG,KAAK,KAAK,CAAC;AAC3C,UAAI,YAAY,GAAG,WAAW;AAC9B,UAAI,KAAA;AAGJ,UAAI,KAAA;AACJ,UAAI,UAAU,IAAI,EAAE;AAEpB,UAAI,UAAA;AACJ,UAAI,IAAI,GAAG,GAAG,SAAS,GAAG,KAAK,KAAK,CAAC;AACrC,UAAI,YAAY;AAChB,UAAI,KAAA;AACJ,UAAI,cAAc,GAAG,WAAW;AAChC,UAAI,YAAY;AAChB,UAAI,OAAA;AAGJ,UAAI,YAAY;AAEhB,YAAM,KAAK,GAAG,KAAK;AACnB,UAAI,UAAA;AACJ,UAAI,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC;AACjC,UAAI,OAAO,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC;AAChC,UAAI,MAAM,KAAK,GAAG,CAAC,KAAK,GAAG,KAAK,GAAG,CAAC,KAAK,IAAI,KAAK,GAAG;AACrD,UAAI,OAAO,KAAK,GAAG,KAAK,IAAI,GAAG;AAC/B,UAAI,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,IAAI,KAAK,KAAK,GAAG,GAAG;AACnD,UAAI,OAAO,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC;AAChC,UAAI,MAAM,CAAC,KAAK,GAAG,KAAK,GAAG,CAAC,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG;AACrD,UAAI,OAAO,CAAC,KAAK,GAAG,CAAC,KAAK,IAAI,GAAG;AACjC,UAAI,MAAM,CAAC,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,GAAG,GAAG;AACvD,UAAI,UAAA;AACJ,UAAI,KAAA;AAGJ,UAAI,YAAY,GAAG,WAAW;AAC9B,UAAI,SAAS,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC;AAEnC,UAAI,cAAc,GAAG,WAAW;AAChC,UAAI,YAAY;AAChB,UAAI,UAAA;AACJ,UAAI,OAAO,CAAC,UAAU,KAAK,EAAE;AAAG,UAAI,OAAO,CAAC,UAAU,KAAK,CAAC;AAC5D,UAAI,OAAA;AAGJ,UAAI,YAAY,GAAG,WAAW;AAC9B,UAAI,SAAS,UAAU,GAAG,IAAI,GAAG,CAAC;AAClC,UAAI,cAAc,GAAG,WAAW;AAChC,UAAI,UAAA;AACJ,UAAI,OAAO,UAAU,KAAK,EAAE;AAAG,UAAI,OAAO,UAAU,KAAK,CAAC;AAC1D,UAAI,OAAA;AAGJ,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,UAAA;AACJ,UAAI,OAAO,CAAC,KAAK,GAAG,CAAC;AAAG,UAAI,OAAO,CAAC,UAAU,GAAG,CAAC;AAClD,UAAI,OAAO,KAAK,GAAG,CAAC;AAAG,UAAI,OAAO,UAAU,GAAG,CAAC;AAChD,UAAI,OAAA;AAMJ,YAAM,YAAY,CAAC,UAAU;AAC7B,YAAM,YAAY,CAAC,UAAU;AAC7B,YAAM,eAAe;AAGrB,UAAI,UAAA;AACJ,UAAI,IAAI,WAAW,WAAW,eAAe,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC;AAClE,UAAI,YAAY;AAChB,UAAI,KAAA;AAEJ,UAAI,YAAY;AAChB,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,UAAI,cAAc,UAAU;AAE1B,YAAI,UAAA;AACJ,YAAI,IAAI,WAAW,WAAW,eAAe,GAAG,GAAG,KAAK,KAAK,CAAC;AAC9D,YAAI,KAAA;AAAA,MACN,WAAW,cAAc,WAAW;AAElC,YAAI,UAAA;AACJ,YAAI,IAAI,WAAW,WAAW,eAAe,IAAI,KAAK,GAAG,KAAK,KAAK,CAAC;AACpE,YAAI,YAAY;AAChB,YAAI,OAAA;AAAA,MACN,WAAW,cAAc,WAAW;AAClC,cAAM,KAAK,eAAe;AAC1B,YAAI,SAAS,YAAY,IAAI,YAAY,IAAI,cAAc,YAAY;AAAA,MACzE,WAAW,cAAc,WAAW;AAElC,cAAM,KAAK,eAAe;AAC1B,YAAI,UAAA;AACJ,YAAI,OAAO,WAAW,YAAY,EAAE;AACpC,YAAI,OAAO,YAAY,IAAI,SAAS;AACpC,YAAI,OAAO,WAAW,YAAY,EAAE;AACpC,YAAI,OAAO,YAAY,IAAI,SAAS;AACpC,YAAI,UAAA;AACJ,YAAI,KAAA;AAAA,MACN,WAAW,cAAc,YAAY;AAEnC,cAAM,KAAK,eAAe;AAC1B,YAAI,UAAA;AACJ,YAAI,OAAO,WAAW,YAAY,EAAE;AACpC,YAAI,OAAO,YAAY,IAAI,YAAY,EAAE;AACzC,YAAI,OAAO,YAAY,IAAI,YAAY,EAAE;AACzC,YAAI,UAAA;AACJ,YAAI,KAAA;AAAA,MACN,OAAO;AAEL,YAAI,UAAA;AACJ,YAAI,IAAI,WAAW,WAAW,eAAe,GAAG,GAAG,KAAK,KAAK,CAAC;AAC9D,YAAI,KAAA;AAAA,MACN;AAEA,UAAI,QAAA;AAGJ,UAAI,YAAY;AAChB,UAAI,OAAO;AACX,UAAI,YAAY;AAChB,UAAI,SAAS,IAAI,MAAM,IAAI,KAAK,UAAU,CAAC;AAAA,IAC7C,CAAC;AAGD,QAAI,eAAe,cAAc,SAAS,KAAK,eAAe,SAAS,IAAI;AACzE,YAAM,UAAU;AAChB,YAAM,UAAU;AAChB,YAAM,aAAa;AACnB,YAAM,QAAiE,CAAA;AAEvE,oBAAc,QAAQ,CAAC,KAAK,QAAQ;AAClC,cAAM,IAAI,IAAI,SAAS,qBAAqB,MAAM,qBAAqB,MAAM;AAC7E,cAAM,KAAK,EAAE,OAAO,GAAG,OAAO,IAAI,MAAM;AAAA,MAC1C,CAAC;AACD,UAAI,eAAe,SAAS,GAAG;AAC7B,cAAM,KAAK,EAAE,OAAO,iBAAiB,SAAS,OAAO,GAAG,eAAe,MAAM,kBAAkB,eAAe,SAAS,IAAI,MAAM,EAAE,IAAI;AAAA,MACzI;AAEA,YAAM,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA,SAAQ,IAAI,YAAY,KAAK,KAAK,EAAE,KAAK,CAAC,IAAI;AAC1F,YAAM,UAAU,MAAM,SAAS,aAAa;AAE5C,UAAI,YAAY;AAChB,UAAI,cAAc;AAClB,UAAI,YAAY;AAChB,YAAM,IAAI;AACV,UAAI,UAAA;AACJ,UAAI,OAAO,UAAU,GAAG,OAAO;AAC/B,UAAI,OAAO,UAAU,gBAAgB,GAAG,OAAO;AAC/C,UAAI,MAAM,UAAU,eAAe,SAAS,UAAU,eAAe,UAAU,GAAG,CAAC;AACnF,UAAI,OAAO,UAAU,eAAe,UAAU,UAAU,CAAC;AACzD,UAAI,MAAM,UAAU,eAAe,UAAU,SAAS,UAAU,gBAAgB,GAAG,UAAU,SAAS,CAAC;AACvG,UAAI,OAAO,UAAU,GAAG,UAAU,OAAO;AACzC,UAAI,MAAM,SAAS,UAAU,SAAS,SAAS,UAAU,UAAU,GAAG,CAAC;AACvE,UAAI,OAAO,SAAS,UAAU,CAAC;AAC/B,UAAI,MAAM,SAAS,SAAS,UAAU,GAAG,SAAS,CAAC;AACnD,UAAI,UAAA;AACJ,UAAI,KAAA;AACJ,UAAI,OAAA;AAEJ,YAAM,QAAQ,CAAC,MAAM,MAAM;AACzB,cAAM,KAAK,UAAU,IAAI,IAAI;AAE7B,YAAI,YAAY,KAAK;AACrB,YAAI,UAAA;AACJ,YAAI,IAAI,UAAU,IAAI,KAAK,GAAG,GAAG,GAAG,KAAK,KAAK,CAAC;AAC/C,YAAI,KAAA;AAEJ,YAAI,YAAY;AAChB,YAAI,OAAO;AACX,YAAI,YAAY;AAChB,YAAI,SAAS,KAAK,OAAO,UAAU,IAAI,KAAK,CAAC;AAAA,MAC/C,CAAC;AAAA,IACH;AAGA,QAAI,QAAQ,KAAK,SAAS,GAAG;AAC3B,WAAK,QAAQ,CAAC,QAAQ;AACpB,cAAM,KAAK,OAAO,IAAI,WAAW,CAAC;AAClC,cAAM,KAAK,OAAO,IAAI,UAAU,CAAC;AACjC,cAAM,WAAW,IAAI,SAAS,OAAO,OAAO,OAAO;AAGnD,YAAI,KAAA;AACJ,YAAI,cAAc;AAClB,YAAI,aAAa;AACjB,YAAI,gBAAgB;AAGpB,YAAI,UAAA;AACJ,YAAI,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC;AAClC,YAAI,OAAO,IAAI,EAAE;AACjB,YAAI,UAAA;AACJ,YAAI,YAAY;AAChB,YAAI,KAAA;AACJ,YAAI,QAAA;AAGJ,YAAI,UAAA;AACJ,YAAI,IAAI,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,KAAK,CAAC;AACxC,YAAI,YAAY;AAChB,YAAI,KAAA;AAGJ,YAAI,IAAI,OAAO;AACb,cAAI,YAAY;AAChB,cAAI,OAAO;AACX,cAAI,YAAY;AAChB,cAAI,SAAS,IAAI,OAAO,IAAI,KAAK,EAAE;AAAA,QACrC;AAAA,MACF,CAAC;AAAA,IACH;AAGA,QAAI,cAAc,WAAW,KAAK,eAAe,WAAW,MAAM,CAAC,QAAQ,KAAK,WAAW,IAAI;AAC7F,UAAI,YAAY,OAAO;AACvB,UAAI,OAAO;AACX,UAAI,YAAY;AAChB,UAAI,SAAS,cAAc,IAAI,GAAG,IAAI,CAAC;AAAA,IACzC;AAAA,EACF,GAAG,CAAC,eAAe,gBAAgB,QAAQ,gBAAgB,gBAAgB,UAAU,YAAY,aAAa,QAAQ,QAAQ,QAAQ,cAAc,MAAM,cAAc,OAAO,OAAO,OAAO,OAAO,CAAC;AAGrM,QAAM,kBAAkB,YAAY,CAAC,MAA2C;AAC9E,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,OAAO,sBAAA;AACpB,UAAM,KAAK,EAAE,UAAU,KAAK;AAC5B,UAAM,KAAK,EAAE,UAAU,KAAK;AAC5B,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,OAAO,WAAW,WAAW,SAAS,KAAK;AAGrD,eAAW,OAAO,eAAe;AAC/B,UAAI,CAAC,IAAI,YAAY,OAAQ;AAC7B,YAAM,YAAY,IAAI,oBAAoB,IAAI,YAAY;AAC1D,YAAM,aAAa,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,YAAY,SAAS,CAAC,IAAI,IAAI,YAAY,SAAS;AAClH,YAAM,SAAS,IAAI,YAAY,UAAU;AACzC,YAAM,KAAK,OAAO,OAAO,WAAW,CAAC;AACrC,YAAM,KAAK,OAAO,OAAO,UAAU,CAAC;AACpC,YAAM,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,OAAO,CAAC;AACtD,UAAI,OAAO,IAAI;AACb,cAAM,YAAY,IAAI,UAAU;AAChC,mBAAW;AAAA,UACT,GAAG,EAAE,UAAU,KAAK,OAAO;AAAA,UAC3B,GAAG,EAAE,UAAU,KAAK,MAAM;AAAA,UAC1B,MAAM;AAAA,UACN,MAAM,IAAI;AAAA,UACV,QAAQ;AAAA,UACR,aAAa,iBAAiB,SAAS,KAAK,iBAAiB;AAAA,UAC7D,KAAK,OAAO;AAAA,UACZ,KAAK,OAAO;AAAA,UACZ,KAAK,OAAO;AAAA,UACZ,YAAY,IAAI,SAAS,qBAAqB,cAAc,QAAQ,GAAG,IAAI,qBAAqB,MAAM;AAAA,UACtG,cAAc,IAAI;AAAA,UAClB,cAAc,IAAI,YAAY,SAAS;AAAA,UACvC,YAAY;AAAA,QAAA,CACb;AACD;AAAA,MACF;AAAA,IACF;AAGA,eAAW,MAAM,gBAAgB;AAC/B,YAAM,KAAK,OAAO,GAAG,WAAW,CAAC;AACjC,YAAM,KAAK,OAAO,GAAG,UAAU,CAAC;AAChC,YAAM,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,OAAO,CAAC;AACtD,UAAI,OAAO,IAAI;AACb,cAAM,WAAW;AACjB,cAAM,WAAW,SAAS,UAAU;AACpC,mBAAW;AAAA,UACT,GAAG,EAAE,UAAU,KAAK,OAAO;AAAA,UAC3B,GAAG,EAAE,UAAU,KAAK,MAAM;AAAA,UAC1B,MAAM;AAAA,UACN,MAAM,GAAG;AAAA,UACT,QAAQ;AAAA,UACR,aAAa,iBAAiB,QAAQ,KAAK,iBAAiB;AAAA,UAC5D,KAAK,GAAG;AAAA,UACR,KAAK,GAAG;AAAA,UACR,aAAa,SAAS,QAAQ;AAAA,UAC9B,SAAU,aAAa,MAAM,GAAG,UAAW,OAAO,GAAG,OAAO,IAAI;AAAA,UAChE,gBAAgB,SAAS;AAAA,QAAA,CAC1B;AACD;AAAA,MACF;AAAA,IACF;AAEA,eAAW,IAAI;AAAA,EACjB,GAAG,CAAC,eAAe,gBAAgB,QAAQ,QAAQ,MAAM,CAAC;AAE1D,QAAM,cAAc,YAAY,CAAC,MAA2C;AAC1E,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,OAAO,sBAAA;AACpB,UAAM,KAAK,EAAE,UAAU,KAAK;AAC5B,UAAM,KAAK,EAAE,UAAU,KAAK;AAC5B,UAAM,IAAI,KAAK;AACf,UAAM,IAAI,OAAO,WAAW,WAAW,SAAS,KAAK;AAErD,eAAW,OAAO,eAAe;AAC/B,UAAI,CAAC,IAAI,YAAY,OAAQ;AAC7B,YAAM,YAAY,IAAI,oBAAoB,IAAI,YAAY;AAC1D,YAAM,aAAa,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,YAAY,SAAS,CAAC,IAAI,IAAI,YAAY,SAAS;AAClH,YAAM,YAAY,IAAI,YAAY,UAAU;AAC5C,YAAM,KAAK,OAAO,UAAU,WAAW,CAAC;AACxC,YAAM,KAAK,OAAO,UAAU,UAAU,CAAC;AACvC,UAAI,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,OAAO,CAAC,IAAI,IAAI;AACnD,6DAAmB,IAAI;AACvB;AAAA,MACF;AAAA,IACF;AAEA,eAAW,MAAM,gBAAgB;AAC/B,YAAM,KAAK,OAAO,GAAG,WAAW,CAAC;AACjC,YAAM,KAAK,OAAO,GAAG,UAAU,CAAC;AAChC,UAAI,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,OAAO,CAAC,IAAI,IAAI;AACnD,yDAAiB,QAAQ,KAAK,GAAG,KAAK,GAAG;AACzC;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,eAAe,gBAAgB,QAAQ,QAAQ,QAAQ,kBAAkB,cAAc,CAAC;AAE5F,YAAU,MAAM;AACd,SAAA;AACA,WAAO,iBAAiB,UAAU,IAAI;AACtC,WAAO,MAAM,OAAO,oBAAoB,UAAU,IAAI;AAAA,EACxD,GAAG,CAAC,IAAI,CAAC;AAGT,QAAM,8BAA8B,cAAc,OAAO,WAAW,WAAW,GAAG,MAAM,OAAO;AAE/F,MAAI,gBAAgB,WAAW;AAC7B,QAAI,YAAY;AACd,aACE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAY,cAAc,SAAS,KAAK,eAAe,SAAS,IAAI,kEAAkE;AAAA,UACtI,OAAO;AAAA,YACL,SAAS;AAAA,YACT,OAAO,SAAS;AAAA,YAChB,QAAQ,OAAO,WAAW,WAAW,SAAS;AAAA,YAC9C,WAAW;AAAA,UAAA;AAAA,UAGb,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,eAAe;AAAA,cACf,aAAa;AAAA,cACb;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAGN;AACA,QAAI,CAAC,eAAe;AAClB,aACE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW,2BAA2B,SAAS;AAAA,UAC/C,OAAO;AAAA,YACL;AAAA,YACA,QAAQ,OAAO,WAAW,WAAW,SAAS;AAAA,YAC9C,WAAW;AAAA,YACX,iBAAiB,OAAO,OAAO,WAAW;AAAA,YAC1C,cAAc;AAAA,YACd,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,gBAAgB;AAAA,UAAA;AAAA,UAGlB,UAAA,oBAAC,QAAA,EAAK,OAAO,EAAE,OAAO,OAAO,OAAO,KAAK,WAAW,UAAU,GAAA,GAAM,UAAA,eAAA,CAAY;AAAA,QAAA;AAAA,MAAA;AAAA,IAGtF;AAAA,EACF;AAEA,QAAM,oBAAoB,cAAc,OAAO,WAAW,WAAW,GAAG,MAAM,OAAO;AAGrF,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,2BAA2B,SAAS;AAAA,QAC/C,OAAO;AAAA,UACL;AAAA,UACA,WAAW;AAAA,UACX,iBAAiB,OAAO;AAAA,UACxB,cAAc;AAAA,UACd,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,gBAAgB;AAAA,QAAA;AAAA,QAGlB,UAAA,oBAAC,QAAA,EAAK,OAAO,EAAE,OAAO,OAAO,MAAM,UAAU,QAAQ,eAAe,MAAA,GAAS,UAAA,WAAA,CAAQ;AAAA,MAAA;AAAA,IAAA;AAAA,EAG3F;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAK;AAAA,MACL,MAAK;AAAA,MACL,cAAY,cAAc,SAAS,KAAK,eAAe,SAAS,IAAI,kEAAkE;AAAA,MACtI,WAAW,2BAA2B,SAAS;AAAA,MAC/C,OAAO,EAAE,OAAO,QAAQ,OAAO,WAAW,WAAW,SAAS,QAAW,WAAW,mBAAmB,iBAAiB,OAAO,YAAY,cAAc,OAAO,UAAU,UAAU,UAAU,WAAA;AAAA,MAC9L,oBAAiB;AAAA,MAGhB,UAAA;AAAA,QAAA,gBAAgB,aAAa,iBAC5B;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,OAAO;AAAA,cACP,UAAU;AAAA,cACV,cAAc;AAAA,YAAA;AAAA,YAEjB,UAAA;AAAA,cAAA;AAAA,kCACuB,QAAA,EAAK,OAAO,EAAE,YAAY,YAAA,GAAe,UAAA,WAAO;AAAA,cAAO;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAIhF,sBACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,OAAM;AAAA,YACN,cAAW;AAAA,YACX,OAAO;AAAA,cACL,UAAU;AAAA,cACV,KAAK;AAAA,cACL,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,QAAQ;AAAA,cACR,cAAc;AAAA,cACd,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,KAAK;AAAA,YAAA;AAAA,YAGP,+BAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,UAAA;AAAA,cAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,cAC9B,oBAAC,QAAA,EAAK,GAAE,iCAAA,CAAiC;AAAA,YAAA,EAAA,CAC3C;AAAA,UAAA;AAAA,QAAA;AAAA,QAIJ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,OAAO,EAAE,SAAS,SAAS,QAAQ,UAAU,YAAY,UAAA;AAAA,YACzD,aAAa;AAAA,YACb,cAAc,MAAM,WAAW,IAAI;AAAA,YACnC,SAAS;AAAA,UAAA;AAAA,QAAA;AAAA,QAEV,WACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,MAAM,QAAQ;AAAA,cACd,KAAK,QAAQ;AAAA,cACb,YAAY;AAAA,cACZ,gBAAgB;AAAA,cAChB,QAAQ,aAAa,QAAQ,WAAW;AAAA,cACxC,cAAc;AAAA,cACd,SAAS;AAAA,cACT,eAAe;AAAA,cACf,QAAQ;AAAA,cACR,OAAO;AAAA,cACP,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,YAAY;AAAA,cACZ,WAAW,2CAA2C,QAAQ,WAAW;AAAA,cACzE,UAAU;AAAA,cACV,UAAU;AAAA,YAAA;AAAA,YAIZ,UAAA;AAAA,cAAA,qBAAC,SAAI,OAAO;AAAA,gBACV,SAAS;AAAA,gBACT,cAAc,aAAa,QAAQ,WAAW;AAAA,gBAC9C,YAAY,GAAG,QAAQ,WAAW;AAAA,gBAClC,SAAS;AAAA,gBAAQ,YAAY;AAAA,gBAAU,KAAK;AAAA,cAAA,GAE5C,UAAA;AAAA,gBAAA,oBAAC,UAAK,OAAO;AAAA,kBACX,OAAO;AAAA,kBAAG,QAAQ;AAAA,kBAAG,cAAc,QAAQ,WAAW,YAAY,IAAI;AAAA,kBACtE,YAAY,QAAQ;AAAA,kBAAa,SAAS;AAAA,kBAAgB,YAAY;AAAA,kBACtE,WAAW,WAAW,QAAQ,WAAW;AAAA,gBAAA,GACxC;AAAA,gBACH,oBAAC,QAAA,EAAK,OAAO,EAAE,YAAY,KAAK,UAAU,GAAA,GAAO,UAAA,QAAQ,KAAA,CAAK;AAAA,gBAC9D,oBAAC,UAAK,OAAO;AAAA,kBACX,YAAY;AAAA,kBAAQ,UAAU;AAAA,kBAAG,YAAY;AAAA,kBAAK,eAAe;AAAA,kBACjE,OAAO,QAAQ;AAAA,kBAAa,eAAe;AAAA,gBAAA,GAE1C,kBAAQ,OAAA,CACX;AAAA,cAAA,GACF;AAAA,cAEA,qBAAC,OAAA,EAAI,OAAO,EAAE,SAAS,YAAY,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAA,GAEhF,UAAA;AAAA,gBAAA,qBAAC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,GAAG,cAAc,EAAA,GACzE,UAAA;AAAA,kBAAA,oBAAC,UAAK,OAAO;AAAA,oBACX,UAAU;AAAA,oBAAG,YAAY;AAAA,oBAAK,SAAS;AAAA,oBACvC,cAAc;AAAA,oBAAG,eAAe;AAAA,oBAAa,eAAe;AAAA,oBAC5D,YAAY,QAAQ,SAAS,cAAc,6BAA6B;AAAA,oBACxE,OAAO,QAAQ,SAAS,cAAc,YAAY;AAAA,kBAAA,GAEjD,UAAA,QAAQ,SAAS,cAClB,qBAAA,UAAA,EACE,UAAA;AAAA,oBAAA,oBAAC,WAAA,EAAU,MAAK,aAAY,MAAK,eAAc,OAAM,aAAY,OAAO,EAAE,aAAa,GAAG,eAAe,YAAY;AAAA,oBAAE;AAAA,kBAAA,EAAA,CAEzH,IAEA,qBAAA,UAAA,EACE,UAAA;AAAA,oBAAA,oBAAC,WAAA,EAAU,MAAK,WAAU,MAAK,eAAc,OAAO,QAAQ,eAAe,kBAAkB,OAAO,EAAE,aAAa,GAAG,eAAe,YAAY;AAAA,oBAChJ,QAAQ,eAAe;AAAA,kBAAA,EAAA,CAC1B,EAAA,CAEF;AAAA,kBACC,QAAQ,WACP,oBAAC,QAAA,EAAK,OAAO;AAAA,oBACX,UAAU;AAAA,oBAAG,SAAS;AAAA,oBAAW,cAAc;AAAA,oBAC/C,YAAY;AAAA,oBAA6B,OAAO;AAAA,kBAAA,GAE/C,kBAAQ,QAAA,CACX;AAAA,gBAAA,GAEJ;AAAA,gBAEA,qBAAC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,qBAAqB,YAAY,KAAK,WAAW,UAAU,GAAA,GACxF,UAAA;AAAA,kBAAA,oBAAC,UAAK,OAAO,EAAE,OAAO,wBAAA,GAA2B,UAAA,OAAG;AAAA,kBACpD,qBAAC,UAAK,OAAO,EAAE,YAAY,4BAA4B,YAAY,OAChE,UAAA;AAAA,oBAAA,QAAQ,OAAO,IAAI,MAAM;AAAA,oBAAI,QAAQ,IAAI,QAAQ,CAAC;AAAA,oBAAE;AAAA,kBAAA,GACvD;AAAA,sCACC,QAAA,EAAK,OAAO,EAAE,OAAO,wBAAA,GAA2B,UAAA,OAAG;AAAA,kBACpD,qBAAC,UAAK,OAAO,EAAE,YAAY,4BAA4B,YAAY,OAChE,UAAA;AAAA,oBAAA,QAAQ,OAAO,IAAI,MAAM;AAAA,oBAAI,QAAQ,IAAI,QAAQ,CAAC;AAAA,oBAAE;AAAA,kBAAA,GACvD;AAAA,kBACC,QAAQ,QAAQ,UACf,qBAAA,UAAA,EACE,UAAA;AAAA,oBAAA,oBAAC,UAAK,OAAO,EAAE,OAAO,wBAAA,GAA2B,UAAA,YAAQ;AAAA,oBACzD,qBAAC,UAAK,OAAO,EAAE,YAAY,4BAA4B,YAAY,OAChE,UAAA;AAAA,sBAAA,QAAQ,IAAI,QAAQ,CAAC;AAAA,sBAAE;AAAA,oBAAA,EAAA,CAC1B;AAAA,kBAAA,GACF;AAAA,kBAED,QAAQ,mBAAmB,UAC1B,qBAAA,UAAA,EACE,UAAA;AAAA,oBAAA,oBAAC,UAAK,OAAO,EAAE,OAAO,wBAAA,GAA2B,UAAA,YAAQ;AAAA,oBACzD,qBAAC,UAAK,OAAO,EAAE,YAAY,4BAA4B,YAAY,OAChE,UAAA;AAAA,sBAAA,QAAQ,eAAe,QAAQ,CAAC;AAAA,sBAAE;AAAA,oBAAA,EAAA,CACrC;AAAA,kBAAA,EAAA,CACF;AAAA,gBAAA,GAEJ;AAAA,gBAEC,QAAQ,SAAS,gBAAgB,QAAQ,eAAe,UAAa,QAAQ,iBAAiB,WAC7F,qBAAC,OAAA,EAAI,OAAO,EAAE,WAAW,GAAG,YAAY,GAAG,WAAW,oCAAoC,SAAS,QAAQ,KAAK,IAAI,UAAU,EAAA,GAC3H,UAAA;AAAA,kBAAA,QAAQ,eAAe,UACtB,qBAAC,QAAA,EAAK,UAAA;AAAA,oBAAA,oBAAC,UAAK,OAAO,EAAE,OAAO,QAAQ,WAAA,GAAc,UAAA,KAAC;AAAA,oBAAO;AAAA,oBAAE,QAAQ;AAAA,oBAAW;AAAA,kBAAA,GAAS;AAAA,kBAEzF,QAAQ,iBAAiB,UAAa,QAAQ,eAAe,0BAC3D,QAAA,EAAK,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,OAAO,EAAE,OAAO,GAAG,QAAQ,UAAU,KAAA,GAAQ,UAAA,IAAA,CAAC;AAAA,oBAAO;AAAA,oBAAE,QAAQ;AAAA,oBAAa;AAAA,kBAAA,GAAU;AAAA,kBAEnG,QAAQ,gBAAgB,oBAAC,QAAA,EAAK,OAAO,EAAE,OAAO,UAAA,GAAa,UAAA,cAAA,CAAW;AAAA,gBAAA,EAAA,CACzE;AAAA,cAAA,EAAA,CAEJ;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,EAAA;AAIR;"}
@@ -387,10 +387,10 @@ function GroundTrackMapLeaflet({
387
387
  prevOpacity = b.opacity;
388
388
  }
389
389
  const terminatorEdge = calculateTerminatorContinuous(now, 0);
390
- const glowColor = isSatelliteTile ? "#6aa0cc" : "#8faec8";
390
+ const glowColor = isSatelliteTile ? "#a0a0a0" : "#909090";
391
391
  const glowOpacity = isSatelliteTile ? 0.15 : 0.08;
392
- const coreColor = isSatelliteTile ? "#8cc4e8" : "#9ab8d8";
393
- const coreOpacity = isSatelliteTile ? 0.5 : 0.35;
392
+ const coreColor = isSatelliteTile ? "#c0c0c0" : "#a8a8a8";
393
+ const coreOpacity = isSatelliteTile ? 0.45 : 0.3;
394
394
  if (terminatorEdge.sunset.length > 2) {
395
395
  const sunsetLine = terminatorEdge.sunset.map(([lat, lon]) => [lat, lon]);
396
396
  const sunriseLine = terminatorEdge.sunrise.map(([lat, lon]) => [lat, lon]);
@@ -588,11 +588,11 @@ function GroundTrackMapLeaflet({
588
588
  rings.forEach((r) => {
589
589
  const shifted = r.map(([lat, lon]) => [lat, lon + offset]);
590
590
  addLayer(L.polygon(shifted, {
591
- color: `${color}70`,
591
+ color: `${color}50`,
592
592
  fillColor: color,
593
- fillOpacity: 0.1,
593
+ fillOpacity: 0.03,
594
594
  weight: 1,
595
- dashArray: "3, 3",
595
+ dashArray: "4, 4",
596
596
  interactive: false
597
597
  }));
598
598
  });
@@ -1 +1 @@
1
- {"version":3,"file":"GroundTrackMapLeaflet.js","sources":["../../../src/react/charts/GroundTrackMapLeaflet.tsx"],"sourcesContent":["/**\n * @zendir/ui - GroundTrackMap Leaflet Provider\n *\n * Leaflet-based 2D world map for ground tracks, stations, and terminator.\n * Uses Zendir hybrid theme; all interactions enabled (zoom, scroll, drag, etc.).\n * Import leaflet-zendir.css when using this component.\n */\n\nimport React, { useRef, useEffect, useCallback, useMemo, useState } from 'react';\nimport { useTheme } from '../theme';\nimport type { GroundStation } from '../types';\nimport type { SatelliteTrack, GroundStationEnhanced, SROGroundStation, MapPin, LightSource } from './GroundTrackMap';\nimport type { MapLayerDef } from './GroundTrackMap';\n\n// Optional Leaflet — consumer must install leaflet when using mapProvider=\"leaflet\"\nimport L from 'leaflet';\nimport 'leaflet/dist/leaflet.css';\nimport './leaflet-zendir.css';\nimport {\n splitPolylineAtAntimeridian,\n segmentsWithWorldCopies,\n geodesicCirclePoints,\n splitRingAtAntimeridian,\n} from './groundTrackMapLeafletUtils';\nimport {\n DEFAULT_TILE,\n FALLBACK_TILE,\n TILE_ERROR_THRESHOLD,\n OSM_ATTRIBUTION,\n TILE_PRESETS,\n getBasemapAttribution,\n} from './groundTrackMapLeafletTiles';\n\nconst STATUS_COLOR_MAP: Record<string, string> = {\n normal: '#56f000',\n standby: '#2dccff',\n caution: '#fce83a',\n serious: '#ffb302',\n critical: '#ff3838',\n off: '#a4abb6',\n};\n\nconst DEFAULT_TRACK_COLORS = [\n '#2dccff', '#3E3CFF', '#9D70FF', '#56f000', '#fce83a', '#ff7849', '#2dd4bf', '#ff3838',\n];\n\n// =============================================================================\n// Icon helpers — produce L.DivIcon with inline SVG (no external assets needed)\n// =============================================================================\n\n/** Satellite spacecraft icon with solar panels, matching Astro UXDS style. */\nfunction createSatDivIcon(statusColor: string, trackColor: string): L.DivIcon {\n // Status badge shape (Astro UXDS spec)\n const badge = statusColor === '#56f000'\n ? `<circle cx=\"7\" cy=\"7\" r=\"3\" fill=\"${statusColor}\"/>` // normal: filled dot\n : statusColor === '#2dccff'\n ? `<circle cx=\"7\" cy=\"7\" r=\"2.5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\"/>` // standby: ring\n : statusColor === '#fce83a'\n ? `<rect x=\"4.5\" y=\"4.5\" width=\"5\" height=\"5\" fill=\"${statusColor}\"/>` // caution: square\n : statusColor === '#ffb302'\n ? `<polygon points=\"7,3.5 10.5,7 7,10.5 3.5,7\" fill=\"${statusColor}\"/>` // serious: diamond (Astro UXDS)\n : statusColor === '#ff3838'\n ? `<polygon points=\"7,10 4,4 10,4\" fill=\"${statusColor}\"/>` // critical: triangle down\n : `<circle cx=\"7\" cy=\"7\" r=\"2\" fill=\"${statusColor}\"/>`; // off: small dot\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"34\" height=\"34\" viewBox=\"0 0 34 34\">\n <!-- Glow ring -->\n <circle cx=\"17\" cy=\"17\" r=\"15\" fill=\"${statusColor}\" fill-opacity=\"0.12\"/>\n <!-- Main body circle -->\n <circle cx=\"17\" cy=\"17\" r=\"11\" fill=\"#0d1323\" stroke=\"${trackColor}\" stroke-width=\"1.5\"/>\n <!-- Left solar panel -->\n <rect x=\"2\" y=\"15\" width=\"9\" height=\"4\" rx=\"0.5\" fill=\"${trackColor}\" fill-opacity=\"0.75\"/>\n <line x1=\"5.5\" y1=\"15\" x2=\"5.5\" y2=\"19\" stroke=\"${trackColor}\" stroke-width=\"0.5\" stroke-opacity=\"0.45\"/>\n <!-- Connector left -->\n <line x1=\"11\" y1=\"17\" x2=\"13\" y2=\"17\" stroke=\"${trackColor}\" stroke-width=\"1.2\"/>\n <!-- Satellite bus body -->\n <rect x=\"13\" y=\"14.5\" width=\"8\" height=\"5\" rx=\"1\" fill=\"${statusColor}\"/>\n <!-- Connector right -->\n <line x1=\"21\" y1=\"17\" x2=\"23\" y2=\"17\" stroke=\"${trackColor}\" stroke-width=\"1.2\"/>\n <!-- Right solar panel -->\n <rect x=\"23\" y=\"15\" width=\"9\" height=\"4\" rx=\"0.5\" fill=\"${trackColor}\" fill-opacity=\"0.75\"/>\n <line x1=\"26.5\" y1=\"15\" x2=\"26.5\" y2=\"19\" stroke=\"${trackColor}\" stroke-width=\"0.5\" stroke-opacity=\"0.45\"/>\n <!-- Status badge (top-left) -->\n <circle cx=\"7\" cy=\"7\" r=\"5.5\" fill=\"#0d1323\"/>\n ${badge}\n </svg>`;\n\n return L.divIcon({\n html: svg,\n className: 'zendir-sat-icon',\n iconSize: [34, 34] as unknown as L.PointExpression,\n iconAnchor: [17, 17] as unknown as L.PointExpression,\n tooltipAnchor: [0, -18] as unknown as L.PointExpression,\n });\n}\n\n/** Ground station icon — dish/antenna shape, matching Astro UXDS style. */\nfunction createStationDivIcon(statusColor: string, type: string, status: string): L.DivIcon {\n // Status badge\n const badge = status === 'normal'\n ? `<circle cx=\"5\" cy=\"5\" r=\"2.5\" fill=\"${statusColor}\"/>`\n : status === 'standby'\n ? `<circle cx=\"5\" cy=\"5\" r=\"2\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>`\n : status === 'caution'\n ? `<rect x=\"3\" y=\"3\" width=\"4\" height=\"4\" fill=\"${statusColor}\"/>`\n : status === 'serious'\n ? `<polygon points=\"5,2.5 7.5,5 5,7.5 2.5,5\" fill=\"${statusColor}\"/>`\n : status === 'critical'\n ? `<polygon points=\"5,7.5 2.5,2.5 7.5,2.5\" fill=\"${statusColor}\"/>`\n : `<circle cx=\"5\" cy=\"5\" r=\"1.5\" fill=\"${statusColor}\"/>`;\n\n let iconInner = '';\n if (type === 'phased-array') {\n // Grid pattern (phased array)\n iconInner = `\n <rect x=\"9\" y=\"7\" width=\"10\" height=\"8\" rx=\"0.5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"12\" y1=\"7\" x2=\"12\" y2=\"15\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"15\" y1=\"7\" x2=\"15\" y2=\"15\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"9\" y1=\"10\" x2=\"19\" y2=\"10\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"9\" y1=\"13\" x2=\"19\" y2=\"13\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"14\" y1=\"15\" x2=\"14\" y2=\"20\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"11\" y1=\"20\" x2=\"17\" y2=\"20\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>`;\n } else if (type === 'relay') {\n // Relay dish with signal arcs\n iconInner = `\n <path d=\"M 8 16 a 7 7 0 0 1 7 -7\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <path d=\"M 8 16 m 2 -2 a 5 5 0 0 1 5 -5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\" stroke-linecap=\"round\"/>\n <line x1=\"14\" y1=\"16\" x2=\"14\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"11\" y1=\"21\" x2=\"17\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <path d=\"M 16 8 a 3 3 0 0 1 0 4\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\" stroke-linecap=\"round\"/>\n <path d=\"M 17.5 6.5 a 5 5 0 0 1 0 7\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1\" stroke-linecap=\"round\"/>`;\n } else {\n // Default: dish antenna with concentric arcs (Astro UXDS antenna pattern)\n iconInner = `\n <path d=\"M 14 14 m -7 0 a 7 7 0 0 1 7 -7\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <path d=\"M 14 14 m -5 0 a 5 5 0 0 1 5 -5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <path d=\"M 14 14 m -3 0 a 3 3 0 0 1 3 -3\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <circle cx=\"14\" cy=\"14\" r=\"1.5\" fill=\"${statusColor}\"/>\n <line x1=\"14\" y1=\"15\" x2=\"14\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"11\" y1=\"21\" x2=\"17\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>`;\n }\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"28\" height=\"28\" viewBox=\"0 0 28 28\">\n <!-- Glow ring -->\n <circle cx=\"14\" cy=\"14\" r=\"13\" fill=\"${statusColor}\" fill-opacity=\"0.1\"/>\n <!-- Background -->\n <circle cx=\"14\" cy=\"14\" r=\"11\" fill=\"#0d1323\" stroke=\"${statusColor}\" stroke-width=\"1.2\" stroke-opacity=\"0.7\"/>\n ${iconInner}\n <!-- Status badge (top-left) -->\n <circle cx=\"5\" cy=\"5\" r=\"5\" fill=\"#0d1323\"/>\n ${badge}\n </svg>`;\n\n return L.divIcon({\n html: svg,\n className: 'zendir-station-icon',\n iconSize: [28, 28] as unknown as L.PointExpression,\n iconAnchor: [14, 14] as unknown as L.PointExpression,\n tooltipAnchor: [0, -14] as unknown as L.PointExpression,\n });\n}\n\n/**\n * Calculate the sub-solar point (latitude, longitude) for a given UTC Date.\n * Returns the geographic location where the sun is directly overhead.\n */\nfunction calculateSubSolarPoint(date: Date): [number, number] {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const lon = -(solarHours - 12) * 15;\n return [declination, ((lon + 540) % 360) - 180];\n}\n\n/**\n * Calculate the approximate sub-lunar point for a given UTC Date.\n * Uses a simplified low-precision algorithm sufficient for map overlay rendering.\n */\nfunction calculateSubLunarPoint(date: Date): [number, number] {\n const J2000 = Date.UTC(2000, 0, 1, 12, 0, 0);\n const d = (date.getTime() - J2000) / 86400000;\n const DEG = Math.PI / 180;\n const L = (218.316 + 13.176396 * d) % 360;\n const M = (134.963 + 13.064993 * d) % 360;\n const F = (93.272 + 13.229350 * d) % 360;\n const lon_ecl = L + 6.289 * Math.sin(M * DEG);\n const lat_ecl = 5.128 * Math.sin(F * DEG);\n const obliquity = 23.439 - 0.00000036 * d;\n const sinRA = Math.sin(lon_ecl * DEG) * Math.cos(obliquity * DEG) - Math.tan(lat_ecl * DEG) * Math.sin(obliquity * DEG);\n const cosRA = Math.cos(lon_ecl * DEG);\n let RA = Math.atan2(sinRA, cosRA) / DEG;\n if (RA < 0) RA += 360;\n const dec = Math.asin(\n Math.sin(lat_ecl * DEG) * Math.cos(obliquity * DEG)\n + Math.cos(lat_ecl * DEG) * Math.sin(obliquity * DEG) * Math.sin(lon_ecl * DEG)\n ) / DEG;\n const GMST = (280.46061837 + 360.98564736629 * d) % 360;\n let geoLon = RA - GMST;\n geoLon = ((geoLon + 540) % 360) - 180;\n return [dec, geoLon];\n}\n\n/**\n * Compute a terminator line with CONTINUOUS (unwrapped) longitudes.\n *\n * `depressionDeg` offsets the solar zenith angle to produce twilight\n * boundaries instead of the geometric sunset line:\n * - 0° = geometric sunset/sunrise (day/night boundary)\n * - 6° = civil twilight (horizon still visible, outdoor activities possible)\n * - 12° = nautical twilight (horizon barely visible, stars appearing)\n * - 18° = astronomical twilight (sky fully dark for observation)\n *\n * These thresholds follow IAU/USNO standard definitions used in celestial\n * navigation, Astro UX space ops dashboards, and STK/GMAT mission tools.\n */\nfunction calculateTerminatorContinuous(\n date: Date,\n depressionDeg: number = 0,\n numPoints: number = 360,\n): { sunset: Array<[number, number]>, sunrise: Array<[number, number]> } {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n\n // Equation of Time correction (minutes) for more accurate solar position\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n\n // Sub-solar longitude: the geographic longitude where the sun is directly overhead.\n // At noon UTC (solarHours=12) the sun is over Greenwich (0°).\n // At midnight UTC (solarHours=0) the sun is over the dateline (180°).\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const subSolarLon = -(solarHours - 12) * 15;\n const depRad = (depressionDeg * Math.PI) / 180;\n\n const sunset: Array<[number, number]> = [];\n const sunrise: Array<[number, number]> = [];\n\n for (let i = 0; i <= numPoints; i++) {\n // Avoid exact +/- 90 to prevent longitude singularities at the poles\n const lat = -89.999 + (i / numPoints) * 179.998;\n const latRad = lat * (Math.PI / 180);\n const cosH = -(Math.sin(depRad) + Math.sin(latRad) * Math.sin(decRad))\n / (Math.cos(latRad) * Math.cos(decRad));\n \n if (cosH < -1) {\n // All day — midnight sun at this latitude. No night boundary points.\n } else if (cosH > 1) {\n // All night — polar night at this latitude. Night spans all longitudes.\n sunset.push([lat, subSolarLon]);\n sunrise.push([lat, subSolarLon + 360]);\n } else {\n const H = (Math.acos(cosH) * 180) / Math.PI;\n // Sunset boundary: H degrees EAST of the sub-solar point (afternoon side).\n // Observers here see the sun setting in the west — entering night.\n sunset.push([lat, subSolarLon + H]);\n // Sunrise boundary: H degrees WEST of the sub-solar point (morning side),\n // expressed as subSolarLon - H + 360 to keep values > sunset for a continuous polygon.\n sunrise.push([lat, subSolarLon + 360 - H]);\n }\n }\n \n return { sunset, sunrise };\n}\n\n/**\n * Build the full night polygon, properly closing the loops around the poles.\n * Ensures longitudes are strictly continuous so the map projection doesn't\n * draw antimeridian lines across the day side.\n */\nfunction buildNightPolygon(\n terminator: { sunset: Array<[number, number]>, sunrise: Array<[number, number]> }\n): [number, number][] {\n const { sunset, sunrise } = terminator;\n if (!sunset.length || !sunrise.length) return [];\n\n const poly: [number, number][] = [];\n\n // Left edge of night (sunset): South to North\n poly.push(...sunset);\n\n // Right edge of night (sunrise): North to South\n poly.push(...[...sunrise].reverse());\n\n // Leaflet will automatically close the polygon by connecting the last point \n // (South end of sunrise) back to the first point (South end of sunset).\n // Because longitudes are continuous and bounded (sunrise.lon - sunset.lon <= 360),\n // this closing line will simply span the bottom or top of the map, perfectly\n // enclosing the night area without crossing the day side!\n\n return poly;\n}\n\nexport type GroundStationMapItem = GroundStation | GroundStationEnhanced | SROGroundStation;\n\nexport interface GroundTrackMapLeafletProps {\n allSatellites: SatelliteTrack[];\n groundStations: GroundStationMapItem[];\n showTerminator?: boolean;\n /** Override the time used for the terminator calculation (defaults to wall-clock now). */\n terminatorTime?: Date;\n showGrid?: boolean;\n showLegend?: boolean;\n showEquator?: boolean;\n showRecenterButton?: boolean;\n /** Show a toggle button to switch between Dark and Satellite tile styles. Default true. */\n showMapStyleToggle?: boolean;\n defaultCenter?: [number, number];\n defaultZoom?: number;\n height?: number | string;\n width?: number | string;\n minHeight?: string;\n emptyMessage?: string;\n tileUrl?: string;\n /**\n * URL template for a \"night\" tile layer (e.g. NASA Black Marble, VIIRS city lights).\n * Rendered beneath the terminator overlay so it only appears on the dark side.\n * Requires `showTerminator`. Falls back to dark overlay when not provided.\n */\n nightTileUrl?: string;\n /**\n * Point light sources rendered on the night side (masked by the terminator).\n * Each light fades in through twilight and reaches full brightness at night.\n */\n lightSources?: LightSource[];\n className?: string;\n onSatelliteClick?: (id: string) => void;\n onStationClick?: (id: string) => void;\n /** Points-of-interest pins */\n pins?: MapPin[];\n /** Allow adding/editing pins via map clicks */\n pinsEditable?: boolean;\n onPinAdd?: (pin: Omit<MapPin, 'id'>) => void;\n onPinUpdate?: (pin: MapPin) => void;\n onPinRemove?: (pinId: string) => void;\n /** Custom overlay layers for the Layers panel */\n customLayers?: MapLayerDef[];\n /** Called when any layer is toggled */\n onLayerChange?: (layerId: string, enabled: boolean) => void;\n /**\n * Show sun and moon position markers on the map.\n * Requires `showTerminator`. Default: true when terminator is enabled.\n */\n showCelestialMarkers?: boolean;\n}\n\nexport function GroundTrackMapLeaflet({\n allSatellites,\n groundStations,\n showTerminator = true,\n terminatorTime,\n showGrid = false,\n showLegend = true,\n showEquator = false,\n showRecenterButton = true,\n showMapStyleToggle = true,\n defaultCenter = [20, 0],\n defaultZoom = 2,\n height = '100%',\n width = '100%',\n minHeight = '400px',\n emptyMessage = 'No orbital data available',\n tileUrl,\n nightTileUrl,\n lightSources,\n className = '',\n onSatelliteClick,\n onStationClick,\n pins,\n pinsEditable = false,\n onPinAdd,\n onPinUpdate,\n onPinRemove,\n customLayers,\n onLayerChange,\n showCelestialMarkers,\n}: GroundTrackMapLeafletProps): React.ReactElement {\n const { tokens } = useTheme();\n const containerRef = useRef<HTMLDivElement>(null);\n const mapRef = useRef<L.Map | null>(null);\n const tileLayerRef = useRef<L.TileLayer | null>(null);\n const overlayGroupRef = useRef<L.LayerGroup | null>(null);\n const controlsRef = useRef<L.Control[]>([]);\n /** Separate layer group so pin updates don't clear satellite/station layers */\n const pinsGroupRef = useRef<L.LayerGroup | null>(null);\n const [ready, setReady] = useState(false);\n\n // ── Layers panel open/close ──\n const [layersPanelOpen, setLayersPanelOpen] = useState(false);\n const layersPanelRef = useRef<HTMLDivElement>(null);\n\n // Close layers panel when clicking outside\n useEffect(() => {\n if (!layersPanelOpen) return;\n const handleClickOutside = (e: MouseEvent) => {\n if (layersPanelRef.current && !layersPanelRef.current.contains(e.target as Node)) {\n setLayersPanelOpen(false);\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [layersPanelOpen]);\n\n // ── Tile style with localStorage persistence ──\n const TILE_STORAGE_KEY = 'zendir-map-tile-style';\n const isExplicitTileUrl = tileUrl !== undefined;\n const [tileStyle, setTileStyle] = useState<'dark' | 'satellite'>(() => {\n if (isExplicitTileUrl) return 'dark';\n try {\n const saved = localStorage.getItem(TILE_STORAGE_KEY);\n if (saved === 'dark' || saved === 'satellite') return saved;\n } catch { /* SSR / storage blocked */ }\n return 'dark';\n });\n\n const handleTileStyleChange = useCallback((style: 'dark' | 'satellite') => {\n setTileStyle(style);\n try { localStorage.setItem(TILE_STORAGE_KEY, style); } catch { /* noop */ }\n }, []);\n\n const effectiveTileUrl = isExplicitTileUrl ? tileUrl : TILE_PRESETS[tileStyle];\n\n // ── Internal overlay toggle state (built-in layers: terminator, grid) ──\n const [internalTerminator, setInternalTerminator] = useState(showTerminator);\n const [internalGrid, setInternalGrid] = useState(showGrid);\n\n // Sync with prop changes (props are the initial source of truth)\n useEffect(() => { setInternalTerminator(showTerminator); }, [showTerminator]);\n useEffect(() => { setInternalGrid(showGrid); }, [showGrid]);\n\n // ── Custom layer toggle state ──\n const [customLayerState, setCustomLayerState] = useState<Record<string, boolean>>(() => {\n const state: Record<string, boolean> = {};\n for (const l of customLayers ?? []) {\n state[l.id] = l.defaultEnabled ?? true;\n }\n return state;\n });\n\n // Sync when customLayers prop changes (add new layers with defaults)\n useEffect(() => {\n setCustomLayerState((prev) => {\n const next = { ...prev };\n for (const l of customLayers ?? []) {\n if (!(l.id in next)) next[l.id] = l.defaultEnabled ?? true;\n }\n return next;\n });\n }, [customLayers]);\n\n const handleLayerToggle = useCallback((layerId: string, enabled: boolean) => {\n if (layerId === 'terminator') {\n setInternalTerminator(enabled);\n } else if (layerId === 'grid') {\n setInternalGrid(enabled);\n } else {\n setCustomLayerState((prev) => ({ ...prev, [layerId]: enabled }));\n }\n onLayerChange?.(layerId, enabled);\n }, [onLayerChange]);\n\n const clearLayers = useCallback(() => {\n const map = mapRef.current;\n if (!map) return;\n overlayGroupRef.current?.clearLayers();\n controlsRef.current.forEach((ctrl) => map.removeControl(ctrl));\n controlsRef.current = [];\n }, []);\n\n const addLayer = useCallback((layer: L.Layer) => {\n overlayGroupRef.current?.addLayer(layer);\n }, []);\n\n // Create map once on mount (or when tileUrl changes). Intentionally not depending on\n // defaultCenter/defaultZoom so animated updates do not recreate the map (no flicker/zoom reset).\n useEffect(() => {\n // eslint-disable-next-line react-hooks/exhaustive-deps -- defaultCenter/defaultZoom used only for initial view\n const el = containerRef.current;\n if (!el) return;\n\n const center: L.LatLngExpression = defaultCenter ?? [20, 0];\n const zoom = defaultZoom ?? 2;\n\n const map = L.map(el, {\n center,\n zoom,\n zoomControl: false,\n scrollWheelZoom: true,\n doubleClickZoom: true,\n touchZoom: true,\n boxZoom: true,\n keyboard: true,\n dragging: true,\n attributionControl: true,\n maxBounds: [[-90, -540], [90, 540]],\n maxBoundsViscosity: 1.0,\n });\n\n map.attributionControl.setPrefix('');\n\n const overlayGroup = L.layerGroup();\n overlayGroup.addTo(map);\n overlayGroupRef.current = overlayGroup;\n\n const pinsGroup = L.layerGroup();\n pinsGroup.addTo(map);\n pinsGroupRef.current = pinsGroup;\n\n mapRef.current = map;\n setReady(true);\n\n const onSize = () => {\n map.invalidateSize({ animate: false });\n };\n // Immediate RAF + two deferred calls cover: first paint, CSS transitions, flex layout settle\n const raf = requestAnimationFrame(onSize);\n const t1 = setTimeout(onSize, 150);\n const t2 = setTimeout(onSize, 500);\n\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n cancelAnimationFrame(raf);\n clearLayers();\n pinsGroupRef.current?.clearLayers();\n pinsGroupRef.current = null;\n tileLayerRef.current = null;\n map.remove();\n mapRef.current = null;\n overlayGroupRef.current = null;\n };\n // Mount-only: tile layer is swapped by a dedicated effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [clearLayers]);\n\n // Swap tile layer without recreating the entire map (avoids flash on style toggle).\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready) return;\n\n // Remove existing tile layer (Leaflet drops that layer's attribution with it)\n if (tileLayerRef.current) {\n tileLayerRef.current.remove();\n tileLayerRef.current = null;\n }\n\n const isCartoTiles = effectiveTileUrl.includes('cartocdn');\n const basemapAttribution = getBasemapAttribution(effectiveTileUrl);\n\n const tile = L.tileLayer(effectiveTileUrl, {\n maxZoom: 19,\n subdomains: isCartoTiles ? 'abcd' : 'abc',\n crossOrigin: true,\n attribution: basemapAttribution || undefined,\n });\n tile.addTo(map);\n tile.bringToBack();\n tileLayerRef.current = tile;\n\n // Fallback on tile error\n let hasSwitchedToFallback = false;\n const onTileError = () => {\n if (hasSwitchedToFallback) return;\n hasSwitchedToFallback = true;\n tile.off('tileerror', onTileError);\n tile.remove();\n const fallback = L.tileLayer(FALLBACK_TILE, {\n maxZoom: 19,\n subdomains: 'abc',\n crossOrigin: true,\n attribution: OSM_ATTRIBUTION,\n });\n fallback.addTo(map);\n fallback.bringToBack();\n tileLayerRef.current = fallback;\n };\n tile.on('tileerror', onTileError);\n }, [effectiveTileUrl, ready]);\n\n useEffect(() => {\n if (!ready || !mapRef.current) return;\n const map = mapRef.current;\n clearLayers();\n\n // === Night Tile Layer (placed beneath terminator so night imagery appears on dark side) ===\n if (nightTileUrl && internalTerminator) {\n const nightTile = L.tileLayer(nightTileUrl, {\n maxZoom: 19,\n crossOrigin: true,\n opacity: 0.7,\n className: 'zendir-night-tiles',\n });\n addLayer(nightTile);\n }\n\n if (internalTerminator) {\n const now = terminatorTime ?? new Date();\n\n // Graduated terminator shade. Stronger on satellite imagery for contrast,\n // lighter on dark tiles where subtlety reads better.\n const isSatelliteTile = tileStyle === 'satellite';\n const BAND_STEP = 1.5;\n const MAX_DEP = 30;\n const NIGHT_OPACITY = isSatelliteTile ? 0.75 : 0.38;\n const NIGHT_COLOR = isSatelliteTile ? '#030810' : '#2a3a52';\n const bandSteps: Array<{ depression: number; opacity: number; color: string }> = [];\n for (let d = 0; d <= MAX_DEP; d += BAND_STEP) {\n const t = Math.min(d / 18, 1);\n const opacity = Math.pow(t, 1.6) * (NIGHT_OPACITY * 0.85) + (d > 18 ? (d - 18) / 12 * (NIGHT_OPACITY * 0.15) : 0);\n bandSteps.push({ depression: d, opacity: Math.min(opacity, NIGHT_OPACITY), color: NIGHT_COLOR });\n }\n bandSteps.push({ depression: 90, opacity: NIGHT_OPACITY, color: NIGHT_COLOR });\n\n let prevOpacity = 0;\n\n // Draw each band as a cumulative overlay — each adds incremental darkening\n // By stacking full night polygons with small opacities, we avoid drawing\n // complex band-difference polygons, which is much more robust at the poles.\n for (const b of bandSteps) {\n const terminator = calculateTerminatorContinuous(now, Math.min(b.depression, 89));\n const bandOpacity = b.opacity - prevOpacity;\n if (bandOpacity < 0.002 || terminator.sunset.length === 0) {\n prevOpacity = b.opacity;\n continue;\n }\n\n const poly = buildNightPolygon(terminator);\n if (poly.length < 3) continue;\n\n [0, 360, -360].forEach((offset) => {\n const shifted = poly.map(([lat, lon]) => [lat, lon + offset] as [number, number]);\n addLayer(L.polygon(shifted, {\n color: 'transparent',\n fillColor: b.color,\n fillOpacity: bandOpacity,\n interactive: false,\n }));\n });\n \n prevOpacity = b.opacity;\n }\n\n // Draw a smooth terminator boundary line (0° depression)\n // — a thin, continuous stroke showing the day/night geometric edge.\n // Styling adapts to tile style: brighter on satellite for visibility.\n const terminatorEdge = calculateTerminatorContinuous(now, 0);\n const glowColor = isSatelliteTile ? '#6aa0cc' : '#8faec8';\n const glowOpacity = isSatelliteTile ? 0.15 : 0.08;\n const coreColor = isSatelliteTile ? '#8cc4e8' : '#9ab8d8';\n const coreOpacity = isSatelliteTile ? 0.5 : 0.35;\n if (terminatorEdge.sunset.length > 2) {\n const sunsetLine = terminatorEdge.sunset.map(([lat, lon]) => [lat, lon] as [number, number]);\n const sunriseLine = terminatorEdge.sunrise.map(([lat, lon]) => [lat, lon] as [number, number]);\n [0, 360, -360].forEach((offset) => {\n addLayer(L.polyline(\n sunsetLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: glowColor, weight: 3, opacity: glowOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n addLayer(L.polyline(\n sunriseLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: glowColor, weight: 3, opacity: glowOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n addLayer(L.polyline(\n sunsetLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: coreColor, weight: 1, opacity: coreOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n addLayer(L.polyline(\n sunriseLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: coreColor, weight: 1, opacity: coreOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n });\n }\n\n // TODO: Re-enable sun/moon celestial markers once visual design is finalized.\n // Calculations (calculateSubSolarPoint, calculateSubLunarPoint) are correct.\n // Uncomment and set back to prop-driven to restore:\n // const celestialEnabled = showCelestialMarkers !== undefined ? showCelestialMarkers : true;\n const celestialEnabled = false;\n if (celestialEnabled) {\n const [sunLat, sunLon] = calculateSubSolarPoint(now);\n const sunIcon = L.divIcon({\n className: '',\n iconSize: [28, 28] as unknown as L.PointExpression,\n iconAnchor: [14, 14] as unknown as L.PointExpression,\n html: `<svg width=\"28\" height=\"28\" viewBox=\"0 0 28 28\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs><filter id=\"sun-glow\"><feGaussianBlur stdDeviation=\"1.5\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs>\n <circle cx=\"14\" cy=\"14\" r=\"6\" fill=\"#FFB300\" stroke=\"#FF8F00\" stroke-width=\"1.2\" filter=\"url(#sun-glow)\"/>\n ${[0,45,90,135,180,225,270,315].map(a => {\n const r1 = 8, r2 = 12, rad = a * Math.PI / 180;\n return `<line x1=\"${14+r1*Math.cos(rad)}\" y1=\"${14+r1*Math.sin(rad)}\" x2=\"${14+r2*Math.cos(rad)}\" y2=\"${14+r2*Math.sin(rad)}\" stroke=\"#FFB300\" stroke-width=\"1.4\" stroke-linecap=\"round\" opacity=\"0.85\"/>`;\n }).join('')}\n </svg>`,\n });\n const sunMarker = L.marker([sunLat, sunLon], { icon: sunIcon, interactive: true, zIndexOffset: 800 });\n sunMarker.bindTooltip(\n `<b>Sub-Solar Point</b><br/>Sun's zenith position<br/>Lat ${sunLat.toFixed(2)}° Lon ${sunLon.toFixed(2)}°`,\n { direction: 'top', offset: [0, -14] as unknown as L.PointExpression, className: 'zendir-celestial-tooltip' }\n );\n addLayer(sunMarker);\n\n // Sub-lunar point marker\n const [moonLat, moonLon] = calculateSubLunarPoint(now);\n const moonIcon = L.divIcon({\n className: '',\n iconSize: [22, 22] as unknown as L.PointExpression,\n iconAnchor: [11, 11] as unknown as L.PointExpression,\n html: `<svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs><filter id=\"moon-glow\"><feGaussianBlur stdDeviation=\"1\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs>\n <circle cx=\"11\" cy=\"11\" r=\"6.5\" fill=\"#e0e0e0\" stroke=\"#9e9e9e\" stroke-width=\"0.8\" filter=\"url(#moon-glow)\" opacity=\"0.9\"/>\n <circle cx=\"9\" cy=\"9.5\" r=\"1.6\" fill=\"#bdbdbd\" opacity=\"0.5\"/>\n <circle cx=\"13\" cy=\"12\" r=\"1.0\" fill=\"#bdbdbd\" opacity=\"0.4\"/>\n <circle cx=\"10.5\" cy=\"13.5\" r=\"0.7\" fill=\"#bdbdbd\" opacity=\"0.35\"/>\n </svg>`,\n });\n const moonMarker = L.marker([moonLat, moonLon], { icon: moonIcon, interactive: true, zIndexOffset: 790 });\n moonMarker.bindTooltip(\n `<b>Sub-Lunar Point</b><br/>Moon's zenith position<br/>Lat ${moonLat.toFixed(2)}° Lon ${moonLon.toFixed(2)}°`,\n { direction: 'top', offset: [0, -11] as unknown as L.PointExpression, className: 'zendir-celestial-tooltip' }\n );\n addLayer(moonMarker);\n } // end celestialEnabled\n }\n\n // === Light Sources (rendered as glowing markers on the night side) ===\n if (lightSources && lightSources.length > 0 && internalTerminator) {\n const now = terminatorTime ?? new Date();\n const dayOfYear = Math.floor((now.getTime() - Date.UTC(now.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n const lsSubSolarLon = -((now.getUTCHours() + now.getUTCMinutes() / 60) - 12) * 15;\n\n for (const light of lightSources) {\n const latRad = (light.latitude * Math.PI) / 180;\n const sinAlt = Math.sin(latRad) * Math.sin(decRad) +\n Math.cos(latRad) * Math.cos(decRad) *\n Math.cos(((light.longitude - lsSubSolarLon) * Math.PI) / 180);\n const solarAltDeg = (Math.asin(sinAlt) * 180) / Math.PI;\n\n let nightFactor: number;\n if (solarAltDeg >= 0) nightFactor = 0;\n else if (solarAltDeg <= -18) nightFactor = 1;\n else nightFactor = Math.min(1, -solarAltDeg / 18);\n\n if (nightFactor < 0.01) continue;\n\n const r = light.radius ?? 4;\n const intensity = light.intensity ?? 0.8;\n const color = light.color ?? '#ffeedd';\n const alpha = intensity * nightFactor;\n\n // Outer glow circle\n const glowMarker = L.circleMarker([light.latitude, light.longitude], {\n radius: r * 2,\n fillColor: color,\n fillOpacity: alpha * 0.4,\n color: color,\n weight: 0,\n interactive: !!light.label,\n });\n addLayer(glowMarker);\n\n // Bright core\n const coreMarker = L.circleMarker([light.latitude, light.longitude], {\n radius: Math.max(1, r * 0.5),\n fillColor: color,\n fillOpacity: Math.min(1, alpha * 1.2),\n color: 'transparent',\n weight: 0,\n interactive: false,\n });\n addLayer(coreMarker);\n\n if (light.label) {\n glowMarker.bindTooltip(light.label, {\n permanent: false,\n direction: 'top',\n className: 'zendir-leaflet-tooltip',\n });\n }\n }\n }\n\n if (internalGrid) {\n const gridStyle = { color: 'rgba(157, 112, 255, 0.12)', weight: 0.5, interactive: false };\n [-360, 0, 360].forEach((offset) => {\n for (let lon = -180; lon <= 180; lon += 30) {\n const l = lon + offset;\n addLayer(L.polyline([[90, l], [-90, l]], gridStyle));\n }\n for (let lat = -90; lat <= 90; lat += 30) {\n addLayer(L.polyline([[lat, -180 + offset], [lat, 180 + offset]], gridStyle));\n }\n });\n }\n\n if (showEquator) {\n [-360, 0, 360].forEach((offset) => {\n addLayer(L.polyline([[0, -180 + offset], [0, 180 + offset]], {\n color: 'rgba(88, 166, 255, 0.25)',\n weight: 1,\n dashArray: '6, 4',\n interactive: false,\n }));\n });\n }\n\n groundStations.forEach((gs) => {\n const status = ('status' in gs ? gs.status : undefined) ?? 'standby';\n const statusColor = STATUS_COLOR_MAP[status] || STATUS_COLOR_MAP.standby;\n const stationType = ('type' in gs ? (gs as { type?: string }).type : undefined) ?? 'dish';\n const radius = 'coverageRadius' in gs ? gs.coverageRadius : undefined;\n const showCoverage = 'showCoverage' in gs ? gs.showCoverage : false;\n if (radius != null && radius > 0 && showCoverage) {\n const ring = geodesicCirclePoints(gs.latitude, gs.longitude, radius, 64);\n const rings = splitRingAtAntimeridian(ring);\n [0, 360, -360].forEach((offset) => {\n rings.forEach((r) => {\n const shifted = r.map(([lat, lon]) => [lat, lon + offset] as [number, number]);\n addLayer(L.polygon(shifted, {\n color: `${statusColor}55`,\n fillColor: statusColor,\n fillOpacity: 0.1,\n weight: 1,\n dashArray: '4, 3',\n interactive: false,\n }));\n });\n });\n }\n\n const gsIcon = createStationDivIcon(statusColor, stationType, status);\n const marker = L.marker([gs.latitude, gs.longitude], { icon: gsIcon });\n addLayer(marker);\n const statusLabel = status !== 'standby' ? ` · ${status}` : '';\n marker.bindTooltip(\n `<strong>${gs.name}</strong>${statusLabel}${'network' in gs && gs.network ? `<br/><span style=\"opacity:0.7\">${gs.network}</span>` : ''}`,\n { permanent: false, direction: 'top', className: 'zendir-leaflet-tooltip' }\n );\n marker.on('click', () => {\n onStationClick?.('id' in gs ? String(gs.id) : gs.name);\n });\n });\n\n allSatellites.forEach((sat, satIdx) => {\n const track = sat.groundTrack;\n if (!track || track.length === 0) return;\n\n const color = sat.color || DEFAULT_TRACK_COLORS[satIdx % DEFAULT_TRACK_COLORS.length];\n const futureIdx = sat.futureTrackIndex ?? track.length;\n\n const pastLatLngs = track\n .slice(0, futureIdx)\n .map((p) => [p.latitude, p.longitude] as [number, number]);\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(pastLatLngs)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color, weight: 2.5, opacity: 1 }));\n }\n });\n\n if (futureIdx < track.length) {\n const futureLatLngs = track\n .slice(futureIdx)\n .map((p) => [p.latitude, p.longitude] as [number, number]);\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(futureLatLngs)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color, weight: 1.5, opacity: 0.5, dashArray: '6, 4' }));\n }\n });\n }\n\n // Access mask segments (contact passes) — solid green overlay on track\n if (sat.accessMask && sat.accessMask.some(Boolean)) {\n let segment: [number, number][] = [];\n for (let i = 0; i < track.length; i++) {\n if (sat.accessMask[i]) {\n segment.push([track[i].latitude, track[i].longitude]);\n } else if (segment.length >= 2) {\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(segment)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color: STATUS_COLOR_MAP.normal, weight: 4, opacity: 0.9 }));\n }\n });\n segment = [];\n } else {\n segment = [];\n }\n }\n if (segment.length >= 2) {\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(segment)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color: STATUS_COLOR_MAP.normal, weight: 4, opacity: 0.9 }));\n }\n });\n }\n }\n\n if (sat.passMarkers && sat.passMarkers.length > 0) {\n sat.passMarkers.forEach((pm) => {\n const isAos = pm.type === 'aos';\n const pmColor = isAos ? '#56f000' : '#ff3838';\n const pmMarker = L.circleMarker([pm.latitude, pm.longitude], {\n radius: 5,\n fillColor: pmColor,\n color: `${pmColor}cc`,\n weight: 1.5,\n fillOpacity: 0.9,\n });\n addLayer(pmMarker);\n pmMarker.bindTooltip(`${pm.type.toUpperCase()}${pm.label ? ` – ${pm.label}` : ''}`, {\n permanent: false,\n direction: 'top',\n className: 'zendir-leaflet-tooltip',\n });\n });\n }\n\n if (sat.showFootprint && sat.footprintRadius) {\n const lastIdx = futureIdx > 0 ? Math.min(futureIdx - 1, track.length - 1) : track.length - 1;\n const last = track[lastIdx];\n const ring = geodesicCirclePoints(last.latitude, last.longitude, sat.footprintRadius, 64);\n const rings = splitRingAtAntimeridian(ring);\n [0, 360, -360].forEach((offset) => {\n rings.forEach((r) => {\n const shifted = r.map(([lat, lon]) => [lat, lon + offset] as [number, number]);\n addLayer(L.polygon(shifted, {\n color: `${color}70`,\n fillColor: color,\n fillOpacity: 0.1,\n weight: 1,\n dashArray: '3, 3',\n interactive: false,\n }));\n });\n });\n }\n\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, track.length - 1) : track.length - 1;\n const current = track[currentIdx];\n const statusColor = STATUS_COLOR_MAP[sat.status || 'normal'] || STATUS_COLOR_MAP.normal;\n\n const satIcon = createSatDivIcon(statusColor, color);\n const satMarker = L.marker([current.latitude, current.longitude], { icon: satIcon });\n addLayer(satMarker);\n satMarker.bindTooltip(\n `<strong style=\"color:${color}\">${sat.name}</strong><br/>` +\n `Lat ${current.latitude.toFixed(3)}° &nbsp; Lon ${current.longitude.toFixed(3)}°` +\n (current.altitude != null ? `<br/>Alt ${current.altitude.toFixed(1)} km` : '') +\n (sat.status ? `<br/><span style=\"color:${statusColor}\">${sat.status.toUpperCase()}</span>` : ''),\n { permanent: false, direction: 'top', className: 'zendir-leaflet-tooltip' }\n );\n satMarker.on('click', () => onSatelliteClick?.(sat.id));\n });\n\n if (showLegend && (allSatellites.length > 0 || groundStations.length > 0)) {\n const Legend = L.Control.extend({\n onAdd() {\n const div = L.DomUtil.create('div', 'leaflet-legend-zendir');\n div.style.cssText = `\n padding: 8px 12px; background: rgba(15,21,32,0.9); border: 1px solid rgba(157,112,255,0.2);\n border-radius: 8px; color: #e4e0f0; font-size: 11px; font-family: Roboto, sans-serif;\n `;\n allSatellites.forEach((s, i) => {\n const c = s.color || DEFAULT_TRACK_COLORS[i % DEFAULT_TRACK_COLORS.length];\n const row = document.createElement('div');\n row.style.cssText = 'display: flex; align-items: center; gap: 6px; margin: 2px 0;';\n const swatch = document.createElement('span');\n swatch.style.cssText = `width:8px;height:8px;border-radius:50%;background:${c};`;\n const label = document.createElement('span');\n label.textContent = s.name;\n row.appendChild(swatch);\n row.appendChild(label);\n div.appendChild(row);\n });\n if (groundStations.length > 0) {\n const row = document.createElement('div');\n row.style.cssText = 'display: flex; align-items: center; gap: 6px; margin: 2px 0; margin-top: 6px;';\n const swatch = document.createElement('span');\n swatch.style.cssText = 'width:8px;height:8px;border-radius:50%;background:#2dccff;';\n const label = document.createElement('span');\n label.textContent = `${groundStations.length} Ground Station${groundStations.length > 1 ? 's' : ''}`;\n row.appendChild(swatch);\n row.appendChild(label);\n div.appendChild(row);\n }\n return div;\n },\n });\n const legend = new Legend({ position: 'topleft' });\n legend.addTo(map);\n controlsRef.current.push(legend);\n }\n\n }, [\n ready,\n allSatellites,\n groundStations,\n internalTerminator,\n terminatorTime,\n nightTileUrl,\n lightSources,\n internalGrid,\n showEquator,\n showLegend,\n tileStyle,\n tokens.colors.text.secondary,\n addLayer,\n clearLayers,\n onSatelliteClick,\n onStationClick,\n ]);\n\n // ==========================================================================\n // Pins layer — separate from overlayGroup so pin updates don't rebuild tracks\n // ==========================================================================\n\n useEffect(() => {\n if (!ready || !mapRef.current) return;\n const group = pinsGroupRef.current;\n if (!group) return;\n group.clearLayers();\n\n if (!pins || pins.length === 0) return;\n const accentColor = tokens.colors.accent.primary;\n\n pins.forEach((pin) => {\n const pinColor = pin.color || accentColor;\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"36\" viewBox=\"0 0 24 36\">\n <defs>\n <filter id=\"pin-shadow-${pin.id}\" x=\"-30%\" y=\"-10%\" width=\"160%\" height=\"140%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"2\" flood-color=\"#000\" flood-opacity=\"0.35\"/>\n </filter>\n </defs>\n <g filter=\"url(#pin-shadow-${pin.id})\">\n <path d=\"M12 2 C6.5 2 2 6.5 2 12 C2 19 12 34 12 34 C12 34 22 19 22 12 C22 6.5 17.5 2 12 2Z\"\n fill=\"${pinColor}\" stroke=\"rgba(255,255,255,0.5)\" stroke-width=\"1\"/>\n <circle cx=\"12\" cy=\"12\" r=\"4\" fill=\"#0d1323\" stroke=\"rgba(255,255,255,0.7)\" stroke-width=\"0.8\"/>\n </g>\n </svg>`;\n\n const icon = L.divIcon({\n html: svg,\n className: 'zendir-pin-icon',\n iconSize: [24, 36] as unknown as L.PointExpression,\n iconAnchor: [12, 36] as unknown as L.PointExpression,\n tooltipAnchor: [0, -36] as unknown as L.PointExpression,\n });\n\n const marker = L.marker([pin.latitude, pin.longitude], {\n icon,\n draggable: pinsEditable,\n title: pin.label ?? '',\n });\n\n // Rich tooltip\n const tooltipLines = [\n pin.label ? `<strong>${pin.label}</strong>` : '',\n pin.description ? `<div style=\"opacity:0.7;font-size:11px\">${pin.description}</div>` : '',\n `<div style=\"font-size:10px;opacity:0.5;font-family:monospace\">${pin.latitude.toFixed(4)}°, ${pin.longitude.toFixed(4)}°</div>`,\n pin.createdBy ? `<div style=\"font-size:10px;opacity:0.4;margin-top:2px\">by ${pin.createdBy}</div>` : '',\n ].filter(Boolean).join('');\n marker.bindTooltip(tooltipLines, {\n className: 'zendir-pin-tooltip',\n direction: 'top',\n offset: [0, -4],\n });\n\n if (pinsEditable) {\n // Drag to reposition\n marker.on('dragend', () => {\n const latlng = marker.getLatLng();\n onPinUpdate?.({ ...pin, latitude: latlng.lat, longitude: latlng.lng });\n });\n\n // Right-click to delete\n marker.on('contextmenu', (e: L.LeafletEvent) => {\n L.DomEvent.stopPropagation(e as unknown as Event);\n onPinRemove?.(pin.id);\n });\n }\n\n group.addLayer(marker);\n });\n }, [ready, pins, pinsEditable, onPinUpdate, onPinRemove, tokens.colors.accent.primary]);\n\n // Click-to-add: listen for clicks on the map background when pinsEditable is true\n useEffect(() => {\n if (!ready || !mapRef.current || !pinsEditable || !onPinAdd) return;\n const map = mapRef.current;\n\n const handleClick = (e: L.LeafletMouseEvent) => {\n // Only fire on map background clicks — ignore clicks that bubbled from markers\n if ((e.originalEvent?.target as HTMLElement)?.closest?.('.leaflet-marker-icon')) return;\n onPinAdd({\n latitude: e.latlng.lat,\n longitude: e.latlng.lng,\n label: '',\n color: tokens.colors.accent.primary,\n });\n };\n\n map.on('click', handleClick);\n return () => { map.off('click', handleClick); };\n }, [ready, pinsEditable, onPinAdd, tokens.colors.accent.primary]);\n\n const handleRecenter = useCallback(() => {\n const map = mapRef.current;\n if (!map) return;\n const points: L.LatLngExpression[] = [];\n allSatellites.forEach((s) => {\n s.groundTrack.forEach((p) => points.push([p.latitude, p.longitude]));\n });\n groundStations.forEach((gs) => points.push([gs.latitude, gs.longitude]));\n if (points.length > 0) {\n const bounds = L.latLngBounds(points);\n map.fitBounds(bounds, { padding: [40, 40], maxZoom: 8 });\n } else {\n map.setView(defaultCenter, defaultZoom);\n }\n }, [allSatellites, groundStations, defaultCenter, defaultZoom]);\n\n const handleZoomIn = useCallback(() => { mapRef.current?.zoomIn(); }, []);\n const handleZoomOut = useCallback(() => { mapRef.current?.zoomOut(); }, []);\n\n const resolvedMinHeight = minHeight || (typeof height === 'number' ? `${height}px` : '400px');\n\n const isEmpty = allSatellites.length === 0 && groundStations.length === 0 && (!pins || pins.length === 0);\n\n // ── Shared control button style ──\n const ctrlBtnBase: React.CSSProperties = {\n background: 'rgba(20, 24, 38, 0.92)',\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n border: '1px solid rgba(120, 100, 180, 0.18)',\n color: '#c8c0d8',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background 0.15s, border-color 0.15s',\n };\n\n const ctrlHover = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.background = 'rgba(30, 34, 52, 0.95)';\n e.currentTarget.style.borderColor = 'rgba(157, 112, 255, 0.4)';\n };\n const ctrlLeave = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.background = 'rgba(20, 24, 38, 0.92)';\n e.currentTarget.style.borderColor = 'rgba(120, 100, 180, 0.18)';\n };\n\n // Overlay items shown in the Layers panel\n const overlayItems: Array<{ id: string; label: string; enabled: boolean }> = [];\n overlayItems.push({ id: 'terminator', label: 'Day / Night', enabled: internalTerminator });\n overlayItems.push({ id: 'grid', label: 'Grid Lines', enabled: internalGrid });\n for (const l of customLayers ?? []) {\n overlayItems.push({ id: l.id, label: l.label, enabled: customLayerState[l.id] ?? (l.defaultEnabled ?? true) });\n }\n\n return (\n <div\n className={`zendir-ground-track-map zendir-ground-track-map-leaflet${pinsEditable ? ' zendir-pins-editable' : ''} ${className}`}\n data-map-backend=\"leaflet\"\n style={{\n width,\n height,\n minHeight: resolvedMinHeight,\n backgroundColor: tokens.colors.background.base,\n borderRadius: 8,\n overflow: 'hidden',\n position: 'relative',\n }}\n >\n <div\n ref={containerRef}\n style={{ width: '100%', height: '100%', minHeight: resolvedMinHeight }}\n />\n {isEmpty && (\n <div\n style={{\n position: 'absolute',\n left: '50%',\n top: '50%',\n transform: 'translate(-50%, -50%)',\n color: tokens.colors.text.secondary,\n fontSize: 14,\n pointerEvents: 'none',\n }}\n >\n {emptyMessage}\n </div>\n )}\n {/* ── Unified Map Controls — top-right control bar ── */}\n <div\n style={{\n position: 'absolute',\n top: 10,\n right: 10,\n zIndex: 1000,\n display: 'flex',\n flexDirection: 'row',\n gap: 4,\n alignItems: 'flex-start',\n pointerEvents: 'none',\n }}\n >\n {/* Recenter */}\n {showRecenterButton && (\n <button\n type=\"button\"\n onClick={handleRecenter}\n title=\"Recenter map to fit all assets and ground stations\"\n aria-label=\"Recenter map\"\n style={{\n ...ctrlBtnBase,\n borderRadius: 4,\n padding: '6px 8px',\n gap: 4,\n fontSize: 10,\n fontWeight: 500,\n letterSpacing: '0.03em',\n pointerEvents: 'auto',\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M12 2v4M12 18v4M2 12h4M18 12h4\" />\n </svg>\n </button>\n )}\n\n {/* Layers panel */}\n <div ref={layersPanelRef} style={{ position: 'relative', pointerEvents: 'auto' }}>\n <button\n type=\"button\"\n onClick={() => setLayersPanelOpen((o) => !o)}\n title=\"Map layers\"\n aria-label=\"Toggle map layers panel\"\n aria-expanded={layersPanelOpen}\n style={{\n ...ctrlBtnBase,\n borderRadius: 4,\n padding: '6px 8px',\n pointerEvents: 'auto',\n borderColor: layersPanelOpen ? 'rgba(157, 112, 255, 0.4)' : ctrlBtnBase.border ? undefined : 'rgba(120, 100, 180, 0.18)',\n background: layersPanelOpen ? 'rgba(30, 34, 52, 0.95)' : ctrlBtnBase.background,\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >\n {/* Layers icon — stacked diamonds */}\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinejoin=\"round\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5z\" />\n <path d=\"M2 17l10 5 10-5\" />\n <path d=\"M2 12l10 5 10-5\" />\n </svg>\n </button>\n\n {/* Dropdown panel */}\n {layersPanelOpen && (\n <div\n style={{\n position: 'absolute',\n top: 'calc(100% + 6px)',\n right: 0,\n minWidth: 180,\n background: 'rgba(16, 18, 30, 0.96)',\n backdropFilter: 'blur(16px)',\n WebkitBackdropFilter: 'blur(16px)',\n border: '1px solid rgba(120, 100, 180, 0.18)',\n borderRadius: 6,\n padding: '8px 0',\n boxShadow: '0 8px 32px rgba(0,0,0,0.5)',\n }}\n >\n {/* Base Map section (only when no explicit tileUrl) */}\n {!isExplicitTileUrl && (\n <>\n <div style={{\n padding: '4px 12px 6px',\n fontSize: 9,\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase' as const,\n color: '#7a748e',\n }}>\n Base Map\n </div>\n <div style={{ display: 'flex', gap: 2, padding: '0 8px 8px' }}>\n {(['dark', 'satellite'] as const).map((style) => (\n <button\n key={style}\n type=\"button\"\n onClick={() => handleTileStyleChange(style)}\n aria-pressed={tileStyle === style}\n style={{\n flex: 1,\n background: tileStyle === style ? 'rgba(157, 112, 255, 0.18)' : 'rgba(255,255,255,0.03)',\n border: `1px solid ${tileStyle === style ? 'rgba(157, 112, 255, 0.35)' : 'rgba(120, 100, 180, 0.1)'}`,\n borderRadius: 4,\n color: tileStyle === style ? '#d0c4ee' : '#7a748e',\n cursor: 'pointer',\n padding: '5px 6px',\n fontSize: 10,\n fontWeight: tileStyle === style ? 600 : 400,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n transition: 'all 0.15s ease',\n }}\n >\n {style === 'dark' ? (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\">\n <path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\" />\n </svg>\n ) : (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z\" />\n </svg>\n )}\n {style === 'dark' ? 'Dark' : 'Satellite'}\n </button>\n ))}\n </div>\n <div style={{ height: 1, background: 'rgba(120, 100, 180, 0.1)', margin: '0 8px' }} />\n </>\n )}\n\n {/* Overlays section */}\n <div style={{\n padding: `${isExplicitTileUrl ? '4px' : '8px'} 12px 4px`,\n fontSize: 9,\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase' as const,\n color: '#7a748e',\n }}>\n Overlays\n </div>\n {overlayItems.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => handleLayerToggle(item.id, !item.enabled)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n width: '100%',\n padding: '5px 12px',\n background: 'transparent',\n border: 'none',\n color: item.enabled ? '#c8c0d8' : '#5a5470',\n cursor: 'pointer',\n fontSize: 11,\n textAlign: 'left' as const,\n transition: 'background 0.1s',\n }}\n onMouseEnter={(e) => { e.currentTarget.style.background = 'rgba(157, 112, 255, 0.08)'; }}\n onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}\n >\n {/* Toggle indicator */}\n <span style={{\n width: 14,\n height: 14,\n borderRadius: 3,\n border: `1.5px solid ${item.enabled ? 'rgba(157, 112, 255, 0.6)' : 'rgba(120, 100, 180, 0.25)'}`,\n background: item.enabled ? 'rgba(157, 112, 255, 0.22)' : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n transition: 'all 0.15s ease',\n }}>\n {item.enabled && (\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"#d0c4ee\" strokeWidth=\"2\">\n <path d=\"M2 6l3 3 5-5\" />\n </svg>\n )}\n </span>\n {item.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Zoom controls */}\n <div style={{ display: 'flex', flexDirection: 'column', pointerEvents: 'auto' }}>\n <button\n type=\"button\"\n onClick={handleZoomIn}\n title=\"Zoom in\"\n aria-label=\"Zoom in\"\n style={{\n ...ctrlBtnBase,\n borderRadius: '4px 4px 0 0',\n borderBottom: 'none',\n width: 30,\n height: 28,\n fontSize: 16,\n fontWeight: 300,\n pointerEvents: 'auto',\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >+</button>\n <button\n type=\"button\"\n onClick={handleZoomOut}\n title=\"Zoom out\"\n aria-label=\"Zoom out\"\n style={{\n ...ctrlBtnBase,\n borderRadius: '0 0 4px 4px',\n width: 30,\n height: 28,\n fontSize: 16,\n fontWeight: 300,\n pointerEvents: 'auto',\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >−</button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default GroundTrackMapLeaflet;\n"],"names":[],"mappings":";;;;;;;;AAiCA,MAAM,mBAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,KAAK;AACP;AAEA,MAAM,uBAAuB;AAAA,EAC3B;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAC/E;AAOA,SAAS,iBAAiB,aAAqB,YAA+B;AAE5E,QAAM,QAAQ,gBAAgB,YAC1B,qCAAqC,WAAW,QAChD,gBAAgB,YAChB,qDAAqD,WAAW,2BAChE,gBAAgB,YAChB,oDAAoD,WAAW,QAC/D,gBAAgB,YAChB,qDAAqD,WAAW,QAChE,gBAAgB,YAChB,yCAAyC,WAAW,QACpD,qCAAqC,WAAW;AAEpD,QAAM,MAAM;AAAA;AAAA,2CAE6B,WAAW;AAAA;AAAA,4DAEM,UAAU;AAAA;AAAA,6DAET,UAAU;AAAA,sDACjB,UAAU;AAAA;AAAA,oDAEZ,UAAU;AAAA;AAAA,8DAEA,WAAW;AAAA;AAAA,oDAErB,UAAU;AAAA;AAAA,8DAEA,UAAU;AAAA,wDAChB,UAAU;AAAA;AAAA;AAAA,MAG5D,KAAK;AAAA;AAGT,SAAO,EAAE,QAAQ;AAAA,IACf,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU,CAAC,IAAI,EAAE;AAAA,IACjB,YAAY,CAAC,IAAI,EAAE;AAAA,IACnB,eAAe,CAAC,GAAG,GAAG;AAAA,EAAA,CACvB;AACH;AAGA,SAAS,qBAAqB,aAAqB,MAAc,QAA2B;AAE1F,QAAM,QAAQ,WAAW,WACrB,uCAAuC,WAAW,QAClD,WAAW,YACX,mDAAmD,WAAW,2BAC9D,WAAW,YACX,gDAAgD,WAAW,QAC3D,WAAW,YACX,mDAAmD,WAAW,QAC9D,WAAW,aACX,iDAAiD,WAAW,QAC5D,uCAAuC,WAAW;AAEtD,MAAI,YAAY;AAChB,MAAI,SAAS,gBAAgB;AAE3B,gBAAY;AAAA,6EAC6D,WAAW;AAAA,qDACnC,WAAW;AAAA,qDACX,WAAW;AAAA,qDACX,WAAW;AAAA,qDACX,WAAW;AAAA,sDACV,WAAW;AAAA,sDACX,WAAW;AAAA,EAC/D,WAAW,SAAS,SAAS;AAE3B,gBAAY;AAAA,8DAC8C,WAAW;AAAA,qEACJ,WAAW;AAAA,sDAC1B,WAAW;AAAA,sDACX,WAAW;AAAA,6DACJ,WAAW;AAAA,iEACP,WAAW;AAAA,EAC1E,OAAO;AAEL,gBAAY;AAAA,sEACsD,WAAW;AAAA,sEACX,WAAW;AAAA,sEACX,WAAW;AAAA,8CACnC,WAAW;AAAA,sDACH,WAAW;AAAA,sDACX,WAAW;AAAA,EAC/D;AAEA,QAAM,MAAM;AAAA;AAAA,2CAE6B,WAAW;AAAA;AAAA,4DAEM,WAAW;AAAA,MACjE,SAAS;AAAA;AAAA;AAAA,MAGT,KAAK;AAAA;AAGT,SAAO,EAAE,QAAQ;AAAA,IACf,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU,CAAC,IAAI,EAAE;AAAA,IACjB,YAAY,CAAC,IAAI,EAAE;AAAA,IACnB,eAAe,CAAC,GAAG,GAAG;AAAA,EAAA,CACvB;AACH;AA0DA,SAAS,8BACP,MACA,gBAAwB,GACxB,YAAoB,KACmD;AACvE,QAAM,YAAY,KAAK,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,eAAA,GAAkB,GAAG,CAAC,KAAK,KAAQ;AAChG,QAAM,cAAc,SAAS,KAAK,IAAK,IAAI,KAAK,KAAK,OAAQ,YAAY,GAAG;AAC5E,QAAM,SAAU,cAAc,KAAK,KAAM;AAGzC,QAAM,IAAK,IAAI,KAAK,KAAK,OAAQ,YAAY;AAC7C,QAAM,aAAa,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,MAAM,KAAK,IAAI,CAAC;AAKjF,QAAM,WAAW,KAAK,YAAA,IAAgB,KAAK,kBAAkB,KAAK,KAAK,cAAA,IAAkB;AACzF,QAAM,aAAa,WAAW,aAAa;AAC3C,QAAM,cAAc,EAAE,aAAa,MAAM;AACzC,QAAM,SAAU,gBAAgB,KAAK,KAAM;AAE3C,QAAM,SAAkC,CAAA;AACxC,QAAM,UAAmC,CAAA;AAEzC,WAAS,IAAI,GAAG,KAAK,WAAW,KAAK;AAEnC,UAAM,MAAM,UAAW,IAAI,YAAa;AACxC,UAAM,SAAS,OAAO,KAAK,KAAK;AAChC,UAAM,OAAO,EAAE,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,MACnD,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM;AAEnD,QAAI,OAAO,GAAI;AAAA,aAEJ,OAAO,GAAG;AAEnB,aAAO,KAAK,CAAC,KAAK,WAAW,CAAC;AAC9B,cAAQ,KAAK,CAAC,KAAK,cAAc,GAAG,CAAC;AAAA,IACvC,OAAO;AACL,YAAM,IAAK,KAAK,KAAK,IAAI,IAAI,MAAO,KAAK;AAGzC,aAAO,KAAK,CAAC,KAAK,cAAc,CAAC,CAAC;AAGlC,cAAQ,KAAK,CAAC,KAAK,cAAc,MAAM,CAAC,CAAC;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,QAAA;AACnB;AAOA,SAAS,kBACP,YACoB;AACpB,QAAM,EAAE,QAAQ,QAAA,IAAY;AAC5B,MAAI,CAAC,OAAO,UAAU,CAAC,QAAQ,eAAe,CAAA;AAE9C,QAAM,OAA2B,CAAA;AAGjC,OAAK,KAAK,GAAG,MAAM;AAGnB,OAAK,KAAK,GAAG,CAAC,GAAG,OAAO,EAAE,SAAS;AAQnC,SAAO;AACT;AAuDO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,gBAAgB,CAAC,IAAI,CAAC;AAAA,EACtB,cAAc;AAAA,EACd,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmD;AACjD,QAAM,EAAE,OAAA,IAAW,SAAA;AACnB,QAAM,eAAe,OAAuB,IAAI;AAChD,QAAM,SAAS,OAAqB,IAAI;AACxC,QAAM,eAAe,OAA2B,IAAI;AACpD,QAAM,kBAAkB,OAA4B,IAAI;AACxD,QAAM,cAAc,OAAoB,EAAE;AAE1C,QAAM,eAAe,OAA4B,IAAI;AACrD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK;AAGxC,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAS,KAAK;AAC5D,QAAM,iBAAiB,OAAuB,IAAI;AAGlD,YAAU,MAAM;AACd,QAAI,CAAC,gBAAiB;AACtB,UAAM,qBAAqB,CAAC,MAAkB;AAC5C,UAAI,eAAe,WAAW,CAAC,eAAe,QAAQ,SAAS,EAAE,MAAc,GAAG;AAChF,2BAAmB,KAAK;AAAA,MAC1B;AAAA,IACF;AACA,aAAS,iBAAiB,aAAa,kBAAkB;AACzD,WAAO,MAAM,SAAS,oBAAoB,aAAa,kBAAkB;AAAA,EAC3E,GAAG,CAAC,eAAe,CAAC;AAGpB,QAAM,mBAAmB;AACzB,QAAM,oBAAoB,YAAY;AACtC,QAAM,CAAC,WAAW,YAAY,IAAI,SAA+B,MAAM;AACrE,QAAI,kBAAmB,QAAO;AAC9B,QAAI;AACF,YAAM,QAAQ,aAAa,QAAQ,gBAAgB;AACnD,UAAI,UAAU,UAAU,UAAU,YAAa,QAAO;AAAA,IACxD,QAAQ;AAAA,IAA8B;AACtC,WAAO;AAAA,EACT,CAAC;AAED,QAAM,wBAAwB,YAAY,CAAC,UAAgC;AACzE,iBAAa,KAAK;AAClB,QAAI;AAAE,mBAAa,QAAQ,kBAAkB,KAAK;AAAA,IAAG,QAAQ;AAAA,IAAa;AAAA,EAC5E,GAAG,CAAA,CAAE;AAEL,QAAM,mBAAmB,oBAAoB,UAAU,aAAa,SAAS;AAG7E,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,SAAS,cAAc;AAC3E,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,QAAQ;AAGzD,YAAU,MAAM;AAAE,0BAAsB,cAAc;AAAA,EAAG,GAAG,CAAC,cAAc,CAAC;AAC5E,YAAU,MAAM;AAAE,oBAAgB,QAAQ;AAAA,EAAG,GAAG,CAAC,QAAQ,CAAC;AAG1D,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAkC,MAAM;AACtF,UAAM,QAAiC,CAAA;AACvC,eAAW,KAAK,gBAAgB,IAAI;AAClC,YAAM,EAAE,EAAE,IAAI,EAAE,kBAAkB;AAAA,IACpC;AACA,WAAO;AAAA,EACT,CAAC;AAGD,YAAU,MAAM;AACd,wBAAoB,CAAC,SAAS;AAC5B,YAAM,OAAO,EAAE,GAAG,KAAA;AAClB,iBAAW,KAAK,gBAAgB,IAAI;AAClC,YAAI,EAAE,EAAE,MAAM,YAAY,EAAE,EAAE,IAAI,EAAE,kBAAkB;AAAA,MACxD;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,oBAAoB,YAAY,CAAC,SAAiB,YAAqB;AAC3E,QAAI,YAAY,cAAc;AAC5B,4BAAsB,OAAO;AAAA,IAC/B,WAAW,YAAY,QAAQ;AAC7B,sBAAgB,OAAO;AAAA,IACzB,OAAO;AACL,0BAAoB,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,OAAO,GAAG,QAAA,EAAU;AAAA,IACjE;AACA,mDAAgB,SAAS;AAAA,EAC3B,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,cAAc,YAAY,MAAM;;AACpC,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,IAAK;AACV,0BAAgB,YAAhB,mBAAyB;AACzB,gBAAY,QAAQ,QAAQ,CAAC,SAAS,IAAI,cAAc,IAAI,CAAC;AAC7D,gBAAY,UAAU,CAAA;AAAA,EACxB,GAAG,CAAA,CAAE;AAEL,QAAM,WAAW,YAAY,CAAC,UAAmB;;AAC/C,0BAAgB,YAAhB,mBAAyB,SAAS;AAAA,EACpC,GAAG,CAAA,CAAE;AAIL,YAAU,MAAM;AAEd,UAAM,KAAK,aAAa;AACxB,QAAI,CAAC,GAAI;AAET,UAAM,SAA6B,iBAAiB,CAAC,IAAI,CAAC;AAC1D,UAAM,OAAO,eAAe;AAE5B,UAAM,MAAM,EAAE,IAAI,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,MACjB,WAAW;AAAA,MACX,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU;AAAA,MACV,oBAAoB;AAAA,MACpB,WAAW,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC;AAAA,MAClC,oBAAoB;AAAA,IAAA,CACrB;AAED,QAAI,mBAAmB,UAAU,EAAE;AAEnC,UAAM,eAAe,EAAE,WAAA;AACvB,iBAAa,MAAM,GAAG;AACtB,oBAAgB,UAAU;AAE1B,UAAM,YAAY,EAAE,WAAA;AACpB,cAAU,MAAM,GAAG;AACnB,iBAAa,UAAU;AAEvB,WAAO,UAAU;AACjB,aAAS,IAAI;AAEb,UAAM,SAAS,MAAM;AACnB,UAAI,eAAe,EAAE,SAAS,MAAA,CAAO;AAAA,IACvC;AAEA,UAAM,MAAM,sBAAsB,MAAM;AACxC,UAAM,KAAK,WAAW,QAAQ,GAAG;AACjC,UAAM,KAAK,WAAW,QAAQ,GAAG;AAEjC,WAAO,MAAM;;AACX,mBAAa,EAAE;AACf,mBAAa,EAAE;AACf,2BAAqB,GAAG;AACxB,kBAAA;AACA,yBAAa,YAAb,mBAAsB;AACtB,mBAAa,UAAU;AACvB,mBAAa,UAAU;AACvB,UAAI,OAAA;AACJ,aAAO,UAAU;AACjB,sBAAgB,UAAU;AAAA,IAC5B;AAAA,EAGF,GAAG,CAAC,WAAW,CAAC;AAGhB,YAAU,MAAM;AACd,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,OAAO,CAAC,MAAO;AAGpB,QAAI,aAAa,SAAS;AACxB,mBAAa,QAAQ,OAAA;AACrB,mBAAa,UAAU;AAAA,IACzB;AAEA,UAAM,eAAe,iBAAiB,SAAS,UAAU;AACzD,UAAM,qBAAqB,sBAAsB,gBAAgB;AAEjE,UAAM,OAAO,EAAE,UAAU,kBAAkB;AAAA,MACzC,SAAS;AAAA,MACT,YAAY,eAAe,SAAS;AAAA,MACpC,aAAa;AAAA,MACb,aAAa,sBAAsB;AAAA,IAAA,CACpC;AACD,SAAK,MAAM,GAAG;AACd,SAAK,YAAA;AACL,iBAAa,UAAU;AAGvB,QAAI,wBAAwB;AAC5B,UAAM,cAAc,MAAM;AACxB,UAAI,sBAAuB;AAC3B,8BAAwB;AACxB,WAAK,IAAI,aAAa,WAAW;AACjC,WAAK,OAAA;AACL,YAAM,WAAW,EAAE,UAAU,eAAe;AAAA,QAC1C,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,aAAa;AAAA,MAAA,CACd;AACD,eAAS,MAAM,GAAG;AAClB,eAAS,YAAA;AACT,mBAAa,UAAU;AAAA,IACzB;AACA,SAAK,GAAG,aAAa,WAAW;AAAA,EAClC,GAAG,CAAC,kBAAkB,KAAK,CAAC;AAE5B,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,OAAO,QAAS;AAC/B,UAAM,MAAM,OAAO;AACnB,gBAAA;AAGA,QAAI,gBAAgB,oBAAoB;AACtC,YAAM,YAAY,EAAE,UAAU,cAAc;AAAA,QAC1C,SAAS;AAAA,QACT,aAAa;AAAA,QACb,SAAS;AAAA,QACT,WAAW;AAAA,MAAA,CACZ;AACD,eAAS,SAAS;AAAA,IACpB;AAEA,QAAI,oBAAoB;AACtB,YAAM,MAAM,kBAAkB,oBAAI,KAAA;AAIlC,YAAM,kBAAkB,cAAc;AACtC,YAAM,YAAY;AAClB,YAAM,UAAU;AAChB,YAAM,gBAAgB,kBAAkB,OAAO;AAC/C,YAAM,cAAc,kBAAkB,YAAY;AAClD,YAAM,YAA2E,CAAA;AACjF,eAAS,IAAI,GAAG,KAAK,SAAS,KAAK,WAAW;AAC5C,cAAM,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC;AAC5B,cAAM,UAAU,KAAK,IAAI,GAAG,GAAG,KAAK,gBAAgB,SAAS,IAAI,MAAM,IAAI,MAAM,MAAM,gBAAgB,QAAQ;AAC/G,kBAAU,KAAK,EAAE,YAAY,GAAG,SAAS,KAAK,IAAI,SAAS,aAAa,GAAG,OAAO,YAAA,CAAa;AAAA,MACjG;AACA,gBAAU,KAAK,EAAE,YAAY,IAAI,SAAS,eAAe,OAAO,aAAa;AAE7E,UAAI,cAAc;AAKlB,iBAAW,KAAK,WAAW;AACzB,cAAM,aAAa,8BAA8B,KAAK,KAAK,IAAI,EAAE,YAAY,EAAE,CAAC;AAChF,cAAM,cAAc,EAAE,UAAU;AAChC,YAAI,cAAc,QAAS,WAAW,OAAO,WAAW,GAAG;AACzD,wBAAc,EAAE;AAChB;AAAA,QACF;AAEA,cAAM,OAAO,kBAAkB,UAAU;AACzC,YAAI,KAAK,SAAS,EAAG;AAErB,SAAC,GAAG,KAAK,IAAI,EAAE,QAAQ,CAAC,WAAW;AACjC,gBAAM,UAAU,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAqB;AAChF,mBAAS,EAAE,QAAQ,SAAS;AAAA,YAC1B,OAAO;AAAA,YACP,WAAW,EAAE;AAAA,YACb,aAAa;AAAA,YACb,aAAa;AAAA,UAAA,CACd,CAAC;AAAA,QACJ,CAAC;AAED,sBAAc,EAAE;AAAA,MAClB;AAKA,YAAM,iBAAiB,8BAA8B,KAAK,CAAC;AAC3D,YAAM,YAAY,kBAAkB,YAAY;AAChD,YAAM,cAAc,kBAAkB,OAAO;AAC7C,YAAM,YAAY,kBAAkB,YAAY;AAChD,YAAM,cAAc,kBAAkB,MAAM;AAC5C,UAAI,eAAe,OAAO,SAAS,GAAG;AACpC,cAAM,aAAa,eAAe,OAAO,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,CAAqB;AAC3F,cAAM,cAAc,eAAe,QAAQ,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,CAAqB;AAC7F,SAAC,GAAG,KAAK,IAAI,EAAE,QAAQ,CAAC,WAAW;AACjC,mBAAS,EAAE;AAAA,YACT,WAAW,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAqB;AAAA,YACtE,EAAE,OAAO,WAAW,QAAQ,GAAG,SAAS,aAAa,aAAa,OAAO,cAAc,IAAA;AAAA,UAAI,CAC5F;AACD,mBAAS,EAAE;AAAA,YACT,YAAY,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAqB;AAAA,YACvE,EAAE,OAAO,WAAW,QAAQ,GAAG,SAAS,aAAa,aAAa,OAAO,cAAc,IAAA;AAAA,UAAI,CAC5F;AACD,mBAAS,EAAE;AAAA,YACT,WAAW,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAqB;AAAA,YACtE,EAAE,OAAO,WAAW,QAAQ,GAAG,SAAS,aAAa,aAAa,OAAO,cAAc,IAAA;AAAA,UAAI,CAC5F;AACD,mBAAS,EAAE;AAAA,YACT,YAAY,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAqB;AAAA,YACvE,EAAE,OAAO,WAAW,QAAQ,GAAG,SAAS,aAAa,aAAa,OAAO,cAAc,IAAA;AAAA,UAAI,CAC5F;AAAA,QACH,CAAC;AAAA,MACH;AAAA,IAkDF;AAGA,QAAI,gBAAgB,aAAa,SAAS,KAAK,oBAAoB;AACjE,YAAM,MAAM,kBAAkB,oBAAI,KAAA;AAClC,YAAM,YAAY,KAAK,OAAO,IAAI,YAAY,KAAK,IAAI,IAAI,eAAA,GAAkB,GAAG,CAAC,KAAK,KAAQ;AAC9F,YAAM,cAAc,SAAS,KAAK,IAAK,IAAI,KAAK,KAAK,OAAQ,YAAY,GAAG;AAC5E,YAAM,SAAU,cAAc,KAAK,KAAM;AACzC,YAAM,gBAAgB,EAAG,IAAI,YAAA,IAAgB,IAAI,kBAAkB,KAAM,MAAM;AAE/E,iBAAW,SAAS,cAAc;AAChC,cAAM,SAAU,MAAM,WAAW,KAAK,KAAM;AAC5C,cAAM,SAAS,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IACjC,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IAClC,KAAK,KAAM,MAAM,YAAY,iBAAiB,KAAK,KAAM,GAAG;AAC5E,cAAM,cAAe,KAAK,KAAK,MAAM,IAAI,MAAO,KAAK;AAErD,YAAI;AACJ,YAAI,eAAe,EAAG,eAAc;AAAA,iBAC3B,eAAe,IAAK,eAAc;AAAA,2BACxB,KAAK,IAAI,GAAG,CAAC,cAAc,EAAE;AAEhD,YAAI,cAAc,KAAM;AAExB,cAAM,IAAI,MAAM,UAAU;AAC1B,cAAM,YAAY,MAAM,aAAa;AACrC,cAAM,QAAQ,MAAM,SAAS;AAC7B,cAAM,QAAQ,YAAY;AAG1B,cAAM,aAAa,EAAE,aAAa,CAAC,MAAM,UAAU,MAAM,SAAS,GAAG;AAAA,UACnE,QAAQ,IAAI;AAAA,UACZ,WAAW;AAAA,UACX,aAAa,QAAQ;AAAA,UACrB;AAAA,UACA,QAAQ;AAAA,UACR,aAAa,CAAC,CAAC,MAAM;AAAA,QAAA,CACtB;AACD,iBAAS,UAAU;AAGnB,cAAM,aAAa,EAAE,aAAa,CAAC,MAAM,UAAU,MAAM,SAAS,GAAG;AAAA,UACnE,QAAQ,KAAK,IAAI,GAAG,IAAI,GAAG;AAAA,UAC3B,WAAW;AAAA,UACX,aAAa,KAAK,IAAI,GAAG,QAAQ,GAAG;AAAA,UACpC,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,aAAa;AAAA,QAAA,CACd;AACD,iBAAS,UAAU;AAEnB,YAAI,MAAM,OAAO;AACf,qBAAW,YAAY,MAAM,OAAO;AAAA,YAClC,WAAW;AAAA,YACX,WAAW;AAAA,YACX,WAAW;AAAA,UAAA,CACZ;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,QAAI,cAAc;AAChB,YAAM,YAAY,EAAE,OAAO,6BAA6B,QAAQ,KAAK,aAAa,MAAA;AAClF,OAAC,MAAM,GAAG,GAAG,EAAE,QAAQ,CAAC,WAAW;AACjC,iBAAS,MAAM,MAAM,OAAO,KAAK,OAAO,IAAI;AAC1C,gBAAM,IAAI,MAAM;AAChB,mBAAS,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;AAAA,QACrD;AACA,iBAAS,MAAM,KAAK,OAAO,IAAI,OAAO,IAAI;AACxC,mBAAS,EAAE,SAAS,CAAC,CAAC,KAAK,OAAO,MAAM,GAAG,CAAC,KAAK,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;AAAA,QAC7E;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,aAAa;AACf,OAAC,MAAM,GAAG,GAAG,EAAE,QAAQ,CAAC,WAAW;AACjC,iBAAS,EAAE,SAAS,CAAC,CAAC,GAAG,OAAO,MAAM,GAAG,CAAC,GAAG,MAAM,MAAM,CAAC,GAAG;AAAA,UAC3D,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,aAAa;AAAA,QAAA,CACd,CAAC;AAAA,MACJ,CAAC;AAAA,IACH;AAEA,mBAAe,QAAQ,CAAC,OAAO;AAC7B,YAAM,UAAU,YAAY,KAAK,GAAG,SAAS,WAAc;AAC3D,YAAM,cAAc,iBAAiB,MAAM,KAAK,iBAAiB;AACjE,YAAM,eAAe,UAAU,KAAM,GAAyB,OAAO,WAAc;AACnF,YAAM,SAAS,oBAAoB,KAAK,GAAG,iBAAiB;AAC5D,YAAM,eAAe,kBAAkB,KAAK,GAAG,eAAe;AAC9D,UAAI,UAAU,QAAQ,SAAS,KAAK,cAAc;AAChD,cAAM,OAAO,qBAAqB,GAAG,UAAU,GAAG,WAAW,QAAQ,EAAE;AACvE,cAAM,QAAQ,wBAAwB,IAAI;AAC1C,SAAC,GAAG,KAAK,IAAI,EAAE,QAAQ,CAAC,WAAW;AACjC,gBAAM,QAAQ,CAAC,MAAM;AACnB,kBAAM,UAAU,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAqB;AAC7E,qBAAS,EAAE,QAAQ,SAAS;AAAA,cAC1B,OAAO,GAAG,WAAW;AAAA,cACrB,WAAW;AAAA,cACX,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,WAAW;AAAA,cACX,aAAa;AAAA,YAAA,CACd,CAAC;AAAA,UACJ,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAEA,YAAM,SAAS,qBAAqB,aAAa,aAAa,MAAM;AACpE,YAAM,SAAS,EAAE,OAAO,CAAC,GAAG,UAAU,GAAG,SAAS,GAAG,EAAE,MAAM,OAAA,CAAQ;AACrE,eAAS,MAAM;AACf,YAAM,cAAc,WAAW,YAAY,MAAM,MAAM,KAAK;AAC5D,aAAO;AAAA,QACL,WAAW,GAAG,IAAI,YAAY,WAAW,GAAG,aAAa,MAAM,GAAG,UAAU,kCAAkC,GAAG,OAAO,YAAY,EAAE;AAAA,QACtI,EAAE,WAAW,OAAO,WAAW,OAAO,WAAW,yBAAA;AAAA,MAAyB;AAE5E,aAAO,GAAG,SAAS,MAAM;AACvB,yDAAiB,QAAQ,KAAK,OAAO,GAAG,EAAE,IAAI,GAAG;AAAA,MACnD,CAAC;AAAA,IACH,CAAC;AAED,kBAAc,QAAQ,CAAC,KAAK,WAAW;AACrC,YAAM,QAAQ,IAAI;AAClB,UAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAElC,YAAM,QAAQ,IAAI,SAAS,qBAAqB,SAAS,qBAAqB,MAAM;AACpF,YAAM,YAAY,IAAI,oBAAoB,MAAM;AAEhD,YAAM,cAAc,MACjB,MAAM,GAAG,SAAS,EAClB,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,SAAS,CAAqB;AAC3D,8BAAwB,4BAA4B,WAAW,CAAC,EAAE,QAAQ,CAAC,QAAQ;AACjF,YAAI,IAAI,UAAU,GAAG;AACnB,mBAAS,EAAE,SAAS,KAAK,EAAE,OAAO,QAAQ,KAAK,SAAS,EAAA,CAAG,CAAC;AAAA,QAC9D;AAAA,MACF,CAAC;AAED,UAAI,YAAY,MAAM,QAAQ;AAC5B,cAAM,gBAAgB,MACnB,MAAM,SAAS,EACf,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,SAAS,CAAqB;AAC3D,gCAAwB,4BAA4B,aAAa,CAAC,EAAE,QAAQ,CAAC,QAAQ;AACnF,cAAI,IAAI,UAAU,GAAG;AACnB,qBAAS,EAAE,SAAS,KAAK,EAAE,OAAO,QAAQ,KAAK,SAAS,KAAK,WAAW,OAAA,CAAQ,CAAC;AAAA,UACnF;AAAA,QACF,CAAC;AAAA,MACH;AAGA,UAAI,IAAI,cAAc,IAAI,WAAW,KAAK,OAAO,GAAG;AAClD,YAAI,UAA8B,CAAA;AAClC,iBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAI,IAAI,WAAW,CAAC,GAAG;AACrB,oBAAQ,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,MAAM,CAAC,EAAE,SAAS,CAAC;AAAA,UACtD,WAAW,QAAQ,UAAU,GAAG;AAC9B,oCAAwB,4BAA4B,OAAO,CAAC,EAAE,QAAQ,CAAC,QAAQ;AAC7E,kBAAI,IAAI,UAAU,GAAG;AACnB,yBAAS,EAAE,SAAS,KAAK,EAAE,OAAO,iBAAiB,QAAQ,QAAQ,GAAG,SAAS,IAAA,CAAK,CAAC;AAAA,cACvF;AAAA,YACF,CAAC;AACD,sBAAU,CAAA;AAAA,UACZ,OAAO;AACL,sBAAU,CAAA;AAAA,UACZ;AAAA,QACF;AACA,YAAI,QAAQ,UAAU,GAAG;AACvB,kCAAwB,4BAA4B,OAAO,CAAC,EAAE,QAAQ,CAAC,QAAQ;AAC7E,gBAAI,IAAI,UAAU,GAAG;AACnB,uBAAS,EAAE,SAAS,KAAK,EAAE,OAAO,iBAAiB,QAAQ,QAAQ,GAAG,SAAS,IAAA,CAAK,CAAC;AAAA,YACvF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAEA,UAAI,IAAI,eAAe,IAAI,YAAY,SAAS,GAAG;AACjD,YAAI,YAAY,QAAQ,CAAC,OAAO;AAC9B,gBAAM,QAAQ,GAAG,SAAS;AAC1B,gBAAM,UAAU,QAAQ,YAAY;AACpC,gBAAM,WAAW,EAAE,aAAa,CAAC,GAAG,UAAU,GAAG,SAAS,GAAG;AAAA,YAC3D,QAAQ;AAAA,YACR,WAAW;AAAA,YACX,OAAO,GAAG,OAAO;AAAA,YACjB,QAAQ;AAAA,YACR,aAAa;AAAA,UAAA,CACd;AACD,mBAAS,QAAQ;AACjB,mBAAS,YAAY,GAAG,GAAG,KAAK,aAAa,GAAG,GAAG,QAAQ,MAAM,GAAG,KAAK,KAAK,EAAE,IAAI;AAAA,YAClF,WAAW;AAAA,YACX,WAAW;AAAA,YACX,WAAW;AAAA,UAAA,CACZ;AAAA,QACH,CAAC;AAAA,MACH;AAEA,UAAI,IAAI,iBAAiB,IAAI,iBAAiB;AAC5C,cAAM,UAAU,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS;AAC3F,cAAM,OAAO,MAAM,OAAO;AAC1B,cAAM,OAAO,qBAAqB,KAAK,UAAU,KAAK,WAAW,IAAI,iBAAiB,EAAE;AACxF,cAAM,QAAQ,wBAAwB,IAAI;AAC1C,SAAC,GAAG,KAAK,IAAI,EAAE,QAAQ,CAAC,WAAW;AACjC,gBAAM,QAAQ,CAAC,MAAM;AACnB,kBAAM,UAAU,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAqB;AAC7E,qBAAS,EAAE,QAAQ,SAAS;AAAA,cAC1B,OAAO,GAAG,KAAK;AAAA,cACf,WAAW;AAAA,cACX,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,WAAW;AAAA,cACX,aAAa;AAAA,YAAA,CACd,CAAC;AAAA,UACJ,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAEA,YAAM,aAAa,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS;AAC9F,YAAM,UAAU,MAAM,UAAU;AAChC,YAAM,cAAc,iBAAiB,IAAI,UAAU,QAAQ,KAAK,iBAAiB;AAEjF,YAAM,UAAU,iBAAiB,aAAa,KAAK;AACnD,YAAM,YAAY,EAAE,OAAO,CAAC,QAAQ,UAAU,QAAQ,SAAS,GAAG,EAAE,MAAM,QAAA,CAAS;AACnF,eAAS,SAAS;AAClB,gBAAU;AAAA,QACR,wBAAwB,KAAK,KAAK,IAAI,IAAI,qBACnC,QAAQ,SAAS,QAAQ,CAAC,CAAC,gBAAgB,QAAQ,UAAU,QAAQ,CAAC,CAAC,OAC7E,QAAQ,YAAY,OAAO,YAAY,QAAQ,SAAS,QAAQ,CAAC,CAAC,QAAQ,OAC1E,IAAI,SAAS,2BAA2B,WAAW,KAAK,IAAI,OAAO,YAAA,CAAa,YAAY;AAAA,QAC7F,EAAE,WAAW,OAAO,WAAW,OAAO,WAAW,yBAAA;AAAA,MAAyB;AAE5E,gBAAU,GAAG,SAAS,MAAM,qDAAmB,IAAI,GAAG;AAAA,IACxD,CAAC;AAED,QAAI,eAAe,cAAc,SAAS,KAAK,eAAe,SAAS,IAAI;AACzE,YAAM,SAAS,EAAE,QAAQ,OAAO;AAAA,QAC9B,QAAQ;AACN,gBAAM,MAAM,EAAE,QAAQ,OAAO,OAAO,uBAAuB;AAC3D,cAAI,MAAM,UAAU;AAAA;AAAA;AAAA;AAIpB,wBAAc,QAAQ,CAAC,GAAG,MAAM;AAC9B,kBAAM,IAAI,EAAE,SAAS,qBAAqB,IAAI,qBAAqB,MAAM;AACzE,kBAAM,MAAM,SAAS,cAAc,KAAK;AACxC,gBAAI,MAAM,UAAU;AACpB,kBAAM,SAAS,SAAS,cAAc,MAAM;AAC5C,mBAAO,MAAM,UAAU,qDAAqD,CAAC;AAC7E,kBAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,kBAAM,cAAc,EAAE;AACtB,gBAAI,YAAY,MAAM;AACtB,gBAAI,YAAY,KAAK;AACrB,gBAAI,YAAY,GAAG;AAAA,UACrB,CAAC;AACD,cAAI,eAAe,SAAS,GAAG;AAC7B,kBAAM,MAAM,SAAS,cAAc,KAAK;AACxC,gBAAI,MAAM,UAAU;AACpB,kBAAM,SAAS,SAAS,cAAc,MAAM;AAC5C,mBAAO,MAAM,UAAU;AACvB,kBAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,kBAAM,cAAc,GAAG,eAAe,MAAM,kBAAkB,eAAe,SAAS,IAAI,MAAM,EAAE;AAClG,gBAAI,YAAY,MAAM;AACtB,gBAAI,YAAY,KAAK;AACrB,gBAAI,YAAY,GAAG;AAAA,UACrB;AACA,iBAAO;AAAA,QACT;AAAA,MAAA,CACD;AACD,YAAM,SAAS,IAAI,OAAO,EAAE,UAAU,WAAW;AACjD,aAAO,MAAM,GAAG;AAChB,kBAAY,QAAQ,KAAK,MAAM;AAAA,IACjC;AAAA,EAEF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,OAAO,KAAK;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAMD,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,OAAO,QAAS;AAC/B,UAAM,QAAQ,aAAa;AAC3B,QAAI,CAAC,MAAO;AACZ,UAAM,YAAA;AAEN,QAAI,CAAC,QAAQ,KAAK,WAAW,EAAG;AAChC,UAAM,cAAc,OAAO,OAAO,OAAO;AAEzC,SAAK,QAAQ,CAAC,QAAQ;AACpB,YAAM,WAAW,IAAI,SAAS;AAE9B,YAAM,MAAM;AAAA;AAAA,mCAEiB,IAAI,EAAE;AAAA;AAAA;AAAA;AAAA,qCAIJ,IAAI,EAAE;AAAA;AAAA,wBAEnB,QAAQ;AAAA;AAAA;AAAA;AAK1B,YAAM,OAAO,EAAE,QAAQ;AAAA,QACrB,MAAM;AAAA,QACN,WAAW;AAAA,QACX,UAAU,CAAC,IAAI,EAAE;AAAA,QACjB,YAAY,CAAC,IAAI,EAAE;AAAA,QACnB,eAAe,CAAC,GAAG,GAAG;AAAA,MAAA,CACvB;AAED,YAAM,SAAS,EAAE,OAAO,CAAC,IAAI,UAAU,IAAI,SAAS,GAAG;AAAA,QACrD;AAAA,QACA,WAAW;AAAA,QACX,OAAO,IAAI,SAAS;AAAA,MAAA,CACrB;AAGD,YAAM,eAAe;AAAA,QACnB,IAAI,QAAQ,WAAW,IAAI,KAAK,cAAc;AAAA,QAC9C,IAAI,cAAc,2CAA2C,IAAI,WAAW,WAAW;AAAA,QACvF,iEAAiE,IAAI,SAAS,QAAQ,CAAC,CAAC,MAAM,IAAI,UAAU,QAAQ,CAAC,CAAC;AAAA,QACtH,IAAI,YAAY,6DAA6D,IAAI,SAAS,WAAW;AAAA,MAAA,EACrG,OAAO,OAAO,EAAE,KAAK,EAAE;AACzB,aAAO,YAAY,cAAc;AAAA,QAC/B,WAAW;AAAA,QACX,WAAW;AAAA,QACX,QAAQ,CAAC,GAAG,EAAE;AAAA,MAAA,CACf;AAED,UAAI,cAAc;AAEhB,eAAO,GAAG,WAAW,MAAM;AACzB,gBAAM,SAAS,OAAO,UAAA;AACtB,qDAAc,EAAE,GAAG,KAAK,UAAU,OAAO,KAAK,WAAW,OAAO;QAClE,CAAC;AAGD,eAAO,GAAG,eAAe,CAAC,MAAsB;AAC9C,YAAE,SAAS,gBAAgB,CAAqB;AAChD,qDAAc,IAAI;AAAA,QACpB,CAAC;AAAA,MACH;AAEA,YAAM,SAAS,MAAM;AAAA,IACvB,CAAC;AAAA,EACH,GAAG,CAAC,OAAO,MAAM,cAAc,aAAa,aAAa,OAAO,OAAO,OAAO,OAAO,CAAC;AAGtF,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,CAAC,OAAO,WAAW,CAAC,gBAAgB,CAAC,SAAU;AAC7D,UAAM,MAAM,OAAO;AAEnB,UAAM,cAAc,CAAC,MAA2B;;AAE9C,WAAK,mBAAE,kBAAF,mBAAiB,WAAjB,mBAAyC,YAAzC,4BAAmD,wBAAyB;AACjF,eAAS;AAAA,QACP,UAAU,EAAE,OAAO;AAAA,QACnB,WAAW,EAAE,OAAO;AAAA,QACpB,OAAO;AAAA,QACP,OAAO,OAAO,OAAO,OAAO;AAAA,MAAA,CAC7B;AAAA,IACH;AAEA,QAAI,GAAG,SAAS,WAAW;AAC3B,WAAO,MAAM;AAAE,UAAI,IAAI,SAAS,WAAW;AAAA,IAAG;AAAA,EAChD,GAAG,CAAC,OAAO,cAAc,UAAU,OAAO,OAAO,OAAO,OAAO,CAAC;AAEhE,QAAM,iBAAiB,YAAY,MAAM;AACvC,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,IAAK;AACV,UAAM,SAA+B,CAAA;AACrC,kBAAc,QAAQ,CAAC,MAAM;AAC3B,QAAE,YAAY,QAAQ,CAAC,MAAM,OAAO,KAAK,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAAA,IACrE,CAAC;AACD,mBAAe,QAAQ,CAAC,OAAO,OAAO,KAAK,CAAC,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC;AACvE,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,SAAS,EAAE,aAAa,MAAM;AACpC,UAAI,UAAU,QAAQ,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,SAAS,GAAG;AAAA,IACzD,OAAO;AACL,UAAI,QAAQ,eAAe,WAAW;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,eAAe,gBAAgB,eAAe,WAAW,CAAC;AAE9D,QAAM,eAAe,YAAY,MAAM;;AAAE,iBAAO,YAAP,mBAAgB;AAAA,EAAU,GAAG,CAAA,CAAE;AACxE,QAAM,gBAAgB,YAAY,MAAM;;AAAE,iBAAO,YAAP,mBAAgB;AAAA,EAAW,GAAG,CAAA,CAAE;AAE1E,QAAM,oBAAoB,cAAc,OAAO,WAAW,WAAW,GAAG,MAAM,OAAO;AAErF,QAAM,UAAU,cAAc,WAAW,KAAK,eAAe,WAAW,MAAM,CAAC,QAAQ,KAAK,WAAW;AAGvG,QAAM,cAAmC;AAAA,IACvC,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,YAAY;AAAA,EAAA;AAGd,QAAM,YAAY,CAAC,MAA2C;AAC5D,MAAE,cAAc,MAAM,aAAa;AACnC,MAAE,cAAc,MAAM,cAAc;AAAA,EACtC;AACA,QAAM,YAAY,CAAC,MAA2C;AAC5D,MAAE,cAAc,MAAM,aAAa;AACnC,MAAE,cAAc,MAAM,cAAc;AAAA,EACtC;AAGA,QAAM,eAAuE,CAAA;AAC7E,eAAa,KAAK,EAAE,IAAI,cAAc,OAAO,eAAe,SAAS,oBAAoB;AACzF,eAAa,KAAK,EAAE,IAAI,QAAQ,OAAO,cAAc,SAAS,cAAc;AAC5E,aAAW,KAAK,gBAAgB,IAAI;AAClC,iBAAa,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,OAAO,SAAS,iBAAiB,EAAE,EAAE,MAAM,EAAE,kBAAkB,OAAO;AAAA,EAC/G;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,0DAA0D,eAAe,0BAA0B,EAAE,IAAI,SAAS;AAAA,MAC7H,oBAAiB;AAAA,MACjB,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX,iBAAiB,OAAO,OAAO,WAAW;AAAA,QAC1C,cAAc;AAAA,QACd,UAAU;AAAA,QACV,UAAU;AAAA,MAAA;AAAA,MAGZ,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,WAAW,kBAAA;AAAA,UAAkB;AAAA,QAAA;AAAA,QAEtE,WACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,MAAM;AAAA,cACN,KAAK;AAAA,cACL,WAAW;AAAA,cACX,OAAO,OAAO,OAAO,KAAK;AAAA,cAC1B,UAAU;AAAA,cACV,eAAe;AAAA,YAAA;AAAA,YAGhB,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAIL;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,KAAK;AAAA,cACL,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,eAAe;AAAA,cACf,KAAK;AAAA,cACL,YAAY;AAAA,cACZ,eAAe;AAAA,YAAA;AAAA,YAIhB,UAAA;AAAA,cAAA,sBACC;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAS;AAAA,kBACT,OAAM;AAAA,kBACN,cAAW;AAAA,kBACX,OAAO;AAAA,oBACL,GAAG;AAAA,oBACH,cAAc;AAAA,oBACd,SAAS;AAAA,oBACT,KAAK;AAAA,oBACL,UAAU;AAAA,oBACV,YAAY;AAAA,oBACZ,eAAe;AAAA,oBACf,eAAe;AAAA,kBAAA;AAAA,kBAEjB,cAAc;AAAA,kBACd,cAAc;AAAA,kBAEd,UAAA,qBAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAC5F,UAAA;AAAA,oBAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,oBAC9B,oBAAC,QAAA,EAAK,GAAE,iCAAA,CAAiC;AAAA,kBAAA,EAAA,CAC3C;AAAA,gBAAA;AAAA,cAAA;AAAA,cAKJ,qBAAC,OAAA,EAAI,KAAK,gBAAgB,OAAO,EAAE,UAAU,YAAY,eAAe,OAAA,GACtE,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAAA,oBAC3C,OAAM;AAAA,oBACN,cAAW;AAAA,oBACX,iBAAe;AAAA,oBACf,OAAO;AAAA,sBACL,GAAG;AAAA,sBACH,cAAc;AAAA,sBACd,SAAS;AAAA,sBACT,eAAe;AAAA,sBACf,aAAa,kBAAkB,6BAAkD;AAAA,sBACjF,YAAY,kBAAkB,2BAA2B,YAAY;AAAA,oBAAA;AAAA,oBAEvE,cAAc;AAAA,oBACd,cAAc;AAAA,oBAGd,UAAA,qBAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,gBAAe,SACjH,UAAA;AAAA,sBAAA,oBAAC,QAAA,EAAK,GAAE,4BAAA,CAA4B;AAAA,sBACpC,oBAAC,QAAA,EAAK,GAAE,kBAAA,CAAkB;AAAA,sBAC1B,oBAAC,QAAA,EAAK,GAAE,kBAAA,CAAkB;AAAA,oBAAA,EAAA,CAC5B;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAID,mBACC;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,OAAO;AAAA,sBACL,UAAU;AAAA,sBACV,KAAK;AAAA,sBACL,OAAO;AAAA,sBACP,UAAU;AAAA,sBACV,YAAY;AAAA,sBACZ,gBAAgB;AAAA,sBAChB,sBAAsB;AAAA,sBACtB,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,SAAS;AAAA,sBACT,WAAW;AAAA,oBAAA;AAAA,oBAIZ,UAAA;AAAA,sBAAA,CAAC,qBACA,qBAAA,UAAA,EACE,UAAA;AAAA,wBAAA,oBAAC,SAAI,OAAO;AAAA,0BACV,SAAS;AAAA,0BACT,UAAU;AAAA,0BACV,YAAY;AAAA,0BACZ,eAAe;AAAA,0BACf,eAAe;AAAA,0BACf,OAAO;AAAA,wBAAA,GACN,UAAA,YAEH;AAAA,4CACC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,GAAG,SAAS,YAAA,GAC5C,UAAA,CAAC,QAAQ,WAAW,EAAY,IAAI,CAAC,UACrC;AAAA,0BAAC;AAAA,0BAAA;AAAA,4BAEC,MAAK;AAAA,4BACL,SAAS,MAAM,sBAAsB,KAAK;AAAA,4BAC1C,gBAAc,cAAc;AAAA,4BAC5B,OAAO;AAAA,8BACL,MAAM;AAAA,8BACN,YAAY,cAAc,QAAQ,8BAA8B;AAAA,8BAChE,QAAQ,aAAa,cAAc,QAAQ,8BAA8B,0BAA0B;AAAA,8BACnG,cAAc;AAAA,8BACd,OAAO,cAAc,QAAQ,YAAY;AAAA,8BACzC,QAAQ;AAAA,8BACR,SAAS;AAAA,8BACT,UAAU;AAAA,8BACV,YAAY,cAAc,QAAQ,MAAM;AAAA,8BACxC,SAAS;AAAA,8BACT,YAAY;AAAA,8BACZ,gBAAgB;AAAA,8BAChB,KAAK;AAAA,8BACL,YAAY;AAAA,4BAAA;AAAA,4BAGb,UAAA;AAAA,8BAAA,UAAU,SACT,oBAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBAAe,QAAO,QACzE,8BAAC,QAAA,EAAK,GAAE,8CAAA,CAA8C,EAAA,CACxD,IAEA,qBAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAC5F,UAAA;AAAA,gCAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,gCAC/B,oBAAC,QAAA,EAAK,GAAE,+FAAA,CAA+F;AAAA,8BAAA,GACzG;AAAA,8BAED,UAAU,SAAS,SAAS;AAAA,4BAAA;AAAA,0BAAA;AAAA,0BA/BxB;AAAA,wBAAA,CAiCR,GACH;AAAA,wBACA,oBAAC,OAAA,EAAI,OAAO,EAAE,QAAQ,GAAG,YAAY,4BAA4B,QAAQ,UAAQ,CAAG;AAAA,sBAAA,GACtF;AAAA,sBAIF,oBAAC,SAAI,OAAO;AAAA,wBACV,SAAS,GAAG,oBAAoB,QAAQ,KAAK;AAAA,wBAC7C,UAAU;AAAA,wBACV,YAAY;AAAA,wBACZ,eAAe;AAAA,wBACf,eAAe;AAAA,wBACf,OAAO;AAAA,sBAAA,GACN,UAAA,YAEH;AAAA,sBACC,aAAa,IAAI,CAAC,SACjB;AAAA,wBAAC;AAAA,wBAAA;AAAA,0BAEC,MAAK;AAAA,0BACL,SAAS,MAAM,kBAAkB,KAAK,IAAI,CAAC,KAAK,OAAO;AAAA,0BACvD,OAAO;AAAA,4BACL,SAAS;AAAA,4BACT,YAAY;AAAA,4BACZ,KAAK;AAAA,4BACL,OAAO;AAAA,4BACP,SAAS;AAAA,4BACT,YAAY;AAAA,4BACZ,QAAQ;AAAA,4BACR,OAAO,KAAK,UAAU,YAAY;AAAA,4BAClC,QAAQ;AAAA,4BACR,UAAU;AAAA,4BACV,WAAW;AAAA,4BACX,YAAY;AAAA,0BAAA;AAAA,0BAEd,cAAc,CAAC,MAAM;AAAE,8BAAE,cAAc,MAAM,aAAa;AAAA,0BAA6B;AAAA,0BACvF,cAAc,CAAC,MAAM;AAAE,8BAAE,cAAc,MAAM,aAAa;AAAA,0BAAe;AAAA,0BAGzE,UAAA;AAAA,4BAAA,oBAAC,UAAK,OAAO;AAAA,8BACX,OAAO;AAAA,8BACP,QAAQ;AAAA,8BACR,cAAc;AAAA,8BACd,QAAQ,eAAe,KAAK,UAAU,6BAA6B,2BAA2B;AAAA,8BAC9F,YAAY,KAAK,UAAU,8BAA8B;AAAA,8BACzD,SAAS;AAAA,8BACT,YAAY;AAAA,8BACZ,gBAAgB;AAAA,8BAChB,YAAY;AAAA,8BACZ,YAAY;AAAA,4BAAA,GAEX,eAAK,WACJ,oBAAC,SAAI,OAAM,KAAI,QAAO,KAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,WAAU,aAAY,KACrF,8BAAC,QAAA,EAAK,GAAE,gBAAe,EAAA,CACzB,EAAA,CAEJ;AAAA,4BACC,KAAK;AAAA,0BAAA;AAAA,wBAAA;AAAA,wBAvCD,KAAK;AAAA,sBAAA,CAyCb;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACH,GAEJ;AAAA,cAGA,qBAAC,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,eAAe,OAAA,GACrE,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS;AAAA,oBACT,OAAM;AAAA,oBACN,cAAW;AAAA,oBACX,OAAO;AAAA,sBACL,GAAG;AAAA,sBACH,cAAc;AAAA,sBACd,cAAc;AAAA,sBACd,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,UAAU;AAAA,sBACV,YAAY;AAAA,sBACZ,eAAe;AAAA,oBAAA;AAAA,oBAEjB,cAAc;AAAA,oBACd,cAAc;AAAA,oBACf,UAAA;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBACD;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS;AAAA,oBACT,OAAM;AAAA,oBACN,cAAW;AAAA,oBACX,OAAO;AAAA,sBACL,GAAG;AAAA,sBACH,cAAc;AAAA,sBACd,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,UAAU;AAAA,sBACV,YAAY;AAAA,sBACZ,eAAe;AAAA,oBAAA;AAAA,oBAEjB,cAAc;AAAA,oBACd,cAAc;AAAA,oBACf,UAAA;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAAC,EAAA,CACJ;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,EAAA;AAGN;"}
1
+ {"version":3,"file":"GroundTrackMapLeaflet.js","sources":["../../../src/react/charts/GroundTrackMapLeaflet.tsx"],"sourcesContent":["/**\n * @zendir/ui - GroundTrackMap Leaflet Provider\n *\n * Leaflet-based 2D world map for ground tracks, stations, and terminator.\n * Uses Zendir hybrid theme; all interactions enabled (zoom, scroll, drag, etc.).\n * Import leaflet-zendir.css when using this component.\n */\n\nimport React, { useRef, useEffect, useCallback, useMemo, useState } from 'react';\nimport { useTheme } from '../theme';\nimport type { GroundStation } from '../types';\nimport type { SatelliteTrack, GroundStationEnhanced, SROGroundStation, MapPin, LightSource } from './GroundTrackMap';\nimport type { MapLayerDef } from './GroundTrackMap';\n\n// Optional Leaflet — consumer must install leaflet when using mapProvider=\"leaflet\"\nimport L from 'leaflet';\nimport 'leaflet/dist/leaflet.css';\nimport './leaflet-zendir.css';\nimport {\n splitPolylineAtAntimeridian,\n segmentsWithWorldCopies,\n geodesicCirclePoints,\n splitRingAtAntimeridian,\n} from './groundTrackMapLeafletUtils';\nimport {\n DEFAULT_TILE,\n FALLBACK_TILE,\n TILE_ERROR_THRESHOLD,\n OSM_ATTRIBUTION,\n TILE_PRESETS,\n getBasemapAttribution,\n} from './groundTrackMapLeafletTiles';\n\nconst STATUS_COLOR_MAP: Record<string, string> = {\n normal: '#56f000',\n standby: '#2dccff',\n caution: '#fce83a',\n serious: '#ffb302',\n critical: '#ff3838',\n off: '#a4abb6',\n};\n\nconst DEFAULT_TRACK_COLORS = [\n '#2dccff', '#3E3CFF', '#9D70FF', '#56f000', '#fce83a', '#ff7849', '#2dd4bf', '#ff3838',\n];\n\n// =============================================================================\n// Icon helpers — produce L.DivIcon with inline SVG (no external assets needed)\n// =============================================================================\n\n/** Satellite spacecraft icon with solar panels, matching Astro UXDS style. */\nfunction createSatDivIcon(statusColor: string, trackColor: string): L.DivIcon {\n // Status badge shape (Astro UXDS spec)\n const badge = statusColor === '#56f000'\n ? `<circle cx=\"7\" cy=\"7\" r=\"3\" fill=\"${statusColor}\"/>` // normal: filled dot\n : statusColor === '#2dccff'\n ? `<circle cx=\"7\" cy=\"7\" r=\"2.5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\"/>` // standby: ring\n : statusColor === '#fce83a'\n ? `<rect x=\"4.5\" y=\"4.5\" width=\"5\" height=\"5\" fill=\"${statusColor}\"/>` // caution: square\n : statusColor === '#ffb302'\n ? `<polygon points=\"7,3.5 10.5,7 7,10.5 3.5,7\" fill=\"${statusColor}\"/>` // serious: diamond (Astro UXDS)\n : statusColor === '#ff3838'\n ? `<polygon points=\"7,10 4,4 10,4\" fill=\"${statusColor}\"/>` // critical: triangle down\n : `<circle cx=\"7\" cy=\"7\" r=\"2\" fill=\"${statusColor}\"/>`; // off: small dot\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"34\" height=\"34\" viewBox=\"0 0 34 34\">\n <!-- Glow ring -->\n <circle cx=\"17\" cy=\"17\" r=\"15\" fill=\"${statusColor}\" fill-opacity=\"0.12\"/>\n <!-- Main body circle -->\n <circle cx=\"17\" cy=\"17\" r=\"11\" fill=\"#0d1323\" stroke=\"${trackColor}\" stroke-width=\"1.5\"/>\n <!-- Left solar panel -->\n <rect x=\"2\" y=\"15\" width=\"9\" height=\"4\" rx=\"0.5\" fill=\"${trackColor}\" fill-opacity=\"0.75\"/>\n <line x1=\"5.5\" y1=\"15\" x2=\"5.5\" y2=\"19\" stroke=\"${trackColor}\" stroke-width=\"0.5\" stroke-opacity=\"0.45\"/>\n <!-- Connector left -->\n <line x1=\"11\" y1=\"17\" x2=\"13\" y2=\"17\" stroke=\"${trackColor}\" stroke-width=\"1.2\"/>\n <!-- Satellite bus body -->\n <rect x=\"13\" y=\"14.5\" width=\"8\" height=\"5\" rx=\"1\" fill=\"${statusColor}\"/>\n <!-- Connector right -->\n <line x1=\"21\" y1=\"17\" x2=\"23\" y2=\"17\" stroke=\"${trackColor}\" stroke-width=\"1.2\"/>\n <!-- Right solar panel -->\n <rect x=\"23\" y=\"15\" width=\"9\" height=\"4\" rx=\"0.5\" fill=\"${trackColor}\" fill-opacity=\"0.75\"/>\n <line x1=\"26.5\" y1=\"15\" x2=\"26.5\" y2=\"19\" stroke=\"${trackColor}\" stroke-width=\"0.5\" stroke-opacity=\"0.45\"/>\n <!-- Status badge (top-left) -->\n <circle cx=\"7\" cy=\"7\" r=\"5.5\" fill=\"#0d1323\"/>\n ${badge}\n </svg>`;\n\n return L.divIcon({\n html: svg,\n className: 'zendir-sat-icon',\n iconSize: [34, 34] as unknown as L.PointExpression,\n iconAnchor: [17, 17] as unknown as L.PointExpression,\n tooltipAnchor: [0, -18] as unknown as L.PointExpression,\n });\n}\n\n/** Ground station icon — dish/antenna shape, matching Astro UXDS style. */\nfunction createStationDivIcon(statusColor: string, type: string, status: string): L.DivIcon {\n // Status badge\n const badge = status === 'normal'\n ? `<circle cx=\"5\" cy=\"5\" r=\"2.5\" fill=\"${statusColor}\"/>`\n : status === 'standby'\n ? `<circle cx=\"5\" cy=\"5\" r=\"2\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>`\n : status === 'caution'\n ? `<rect x=\"3\" y=\"3\" width=\"4\" height=\"4\" fill=\"${statusColor}\"/>`\n : status === 'serious'\n ? `<polygon points=\"5,2.5 7.5,5 5,7.5 2.5,5\" fill=\"${statusColor}\"/>`\n : status === 'critical'\n ? `<polygon points=\"5,7.5 2.5,2.5 7.5,2.5\" fill=\"${statusColor}\"/>`\n : `<circle cx=\"5\" cy=\"5\" r=\"1.5\" fill=\"${statusColor}\"/>`;\n\n let iconInner = '';\n if (type === 'phased-array') {\n // Grid pattern (phased array)\n iconInner = `\n <rect x=\"9\" y=\"7\" width=\"10\" height=\"8\" rx=\"0.5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"12\" y1=\"7\" x2=\"12\" y2=\"15\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"15\" y1=\"7\" x2=\"15\" y2=\"15\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"9\" y1=\"10\" x2=\"19\" y2=\"10\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"9\" y1=\"13\" x2=\"19\" y2=\"13\" stroke=\"${statusColor}\" stroke-width=\"0.7\"/>\n <line x1=\"14\" y1=\"15\" x2=\"14\" y2=\"20\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"11\" y1=\"20\" x2=\"17\" y2=\"20\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>`;\n } else if (type === 'relay') {\n // Relay dish with signal arcs\n iconInner = `\n <path d=\"M 8 16 a 7 7 0 0 1 7 -7\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <path d=\"M 8 16 m 2 -2 a 5 5 0 0 1 5 -5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\" stroke-linecap=\"round\"/>\n <line x1=\"14\" y1=\"16\" x2=\"14\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"11\" y1=\"21\" x2=\"17\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <path d=\"M 16 8 a 3 3 0 0 1 0 4\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.2\" stroke-linecap=\"round\"/>\n <path d=\"M 17.5 6.5 a 5 5 0 0 1 0 7\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1\" stroke-linecap=\"round\"/>`;\n } else {\n // Default: dish antenna with concentric arcs (Astro UXDS antenna pattern)\n iconInner = `\n <path d=\"M 14 14 m -7 0 a 7 7 0 0 1 7 -7\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <path d=\"M 14 14 m -5 0 a 5 5 0 0 1 5 -5\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <path d=\"M 14 14 m -3 0 a 3 3 0 0 1 3 -3\" fill=\"none\" stroke=\"${statusColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <circle cx=\"14\" cy=\"14\" r=\"1.5\" fill=\"${statusColor}\"/>\n <line x1=\"14\" y1=\"15\" x2=\"14\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>\n <line x1=\"11\" y1=\"21\" x2=\"17\" y2=\"21\" stroke=\"${statusColor}\" stroke-width=\"1.2\"/>`;\n }\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"28\" height=\"28\" viewBox=\"0 0 28 28\">\n <!-- Glow ring -->\n <circle cx=\"14\" cy=\"14\" r=\"13\" fill=\"${statusColor}\" fill-opacity=\"0.1\"/>\n <!-- Background -->\n <circle cx=\"14\" cy=\"14\" r=\"11\" fill=\"#0d1323\" stroke=\"${statusColor}\" stroke-width=\"1.2\" stroke-opacity=\"0.7\"/>\n ${iconInner}\n <!-- Status badge (top-left) -->\n <circle cx=\"5\" cy=\"5\" r=\"5\" fill=\"#0d1323\"/>\n ${badge}\n </svg>`;\n\n return L.divIcon({\n html: svg,\n className: 'zendir-station-icon',\n iconSize: [28, 28] as unknown as L.PointExpression,\n iconAnchor: [14, 14] as unknown as L.PointExpression,\n tooltipAnchor: [0, -14] as unknown as L.PointExpression,\n });\n}\n\n/**\n * Calculate the sub-solar point (latitude, longitude) for a given UTC Date.\n * Returns the geographic location where the sun is directly overhead.\n */\nfunction calculateSubSolarPoint(date: Date): [number, number] {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const lon = -(solarHours - 12) * 15;\n return [declination, ((lon + 540) % 360) - 180];\n}\n\n/**\n * Calculate the approximate sub-lunar point for a given UTC Date.\n * Uses a simplified low-precision algorithm sufficient for map overlay rendering.\n */\nfunction calculateSubLunarPoint(date: Date): [number, number] {\n const J2000 = Date.UTC(2000, 0, 1, 12, 0, 0);\n const d = (date.getTime() - J2000) / 86400000;\n const DEG = Math.PI / 180;\n const L = (218.316 + 13.176396 * d) % 360;\n const M = (134.963 + 13.064993 * d) % 360;\n const F = (93.272 + 13.229350 * d) % 360;\n const lon_ecl = L + 6.289 * Math.sin(M * DEG);\n const lat_ecl = 5.128 * Math.sin(F * DEG);\n const obliquity = 23.439 - 0.00000036 * d;\n const sinRA = Math.sin(lon_ecl * DEG) * Math.cos(obliquity * DEG) - Math.tan(lat_ecl * DEG) * Math.sin(obliquity * DEG);\n const cosRA = Math.cos(lon_ecl * DEG);\n let RA = Math.atan2(sinRA, cosRA) / DEG;\n if (RA < 0) RA += 360;\n const dec = Math.asin(\n Math.sin(lat_ecl * DEG) * Math.cos(obliquity * DEG)\n + Math.cos(lat_ecl * DEG) * Math.sin(obliquity * DEG) * Math.sin(lon_ecl * DEG)\n ) / DEG;\n const GMST = (280.46061837 + 360.98564736629 * d) % 360;\n let geoLon = RA - GMST;\n geoLon = ((geoLon + 540) % 360) - 180;\n return [dec, geoLon];\n}\n\n/**\n * Compute a terminator line with CONTINUOUS (unwrapped) longitudes.\n *\n * `depressionDeg` offsets the solar zenith angle to produce twilight\n * boundaries instead of the geometric sunset line:\n * - 0° = geometric sunset/sunrise (day/night boundary)\n * - 6° = civil twilight (horizon still visible, outdoor activities possible)\n * - 12° = nautical twilight (horizon barely visible, stars appearing)\n * - 18° = astronomical twilight (sky fully dark for observation)\n *\n * These thresholds follow IAU/USNO standard definitions used in celestial\n * navigation, Astro UX space ops dashboards, and STK/GMAT mission tools.\n */\nfunction calculateTerminatorContinuous(\n date: Date,\n depressionDeg: number = 0,\n numPoints: number = 360,\n): { sunset: Array<[number, number]>, sunrise: Array<[number, number]> } {\n const dayOfYear = Math.floor((date.getTime() - Date.UTC(date.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n\n // Equation of Time correction (minutes) for more accurate solar position\n const B = (2 * Math.PI / 365) * (dayOfYear - 81);\n const eotMinutes = 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);\n\n // Sub-solar longitude: the geographic longitude where the sun is directly overhead.\n // At noon UTC (solarHours=12) the sun is over Greenwich (0°).\n // At midnight UTC (solarHours=0) the sun is over the dateline (180°).\n const utcHours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n const solarHours = utcHours + eotMinutes / 60;\n const subSolarLon = -(solarHours - 12) * 15;\n const depRad = (depressionDeg * Math.PI) / 180;\n\n const sunset: Array<[number, number]> = [];\n const sunrise: Array<[number, number]> = [];\n\n for (let i = 0; i <= numPoints; i++) {\n // Avoid exact +/- 90 to prevent longitude singularities at the poles\n const lat = -89.999 + (i / numPoints) * 179.998;\n const latRad = lat * (Math.PI / 180);\n const cosH = -(Math.sin(depRad) + Math.sin(latRad) * Math.sin(decRad))\n / (Math.cos(latRad) * Math.cos(decRad));\n \n if (cosH < -1) {\n // All day — midnight sun at this latitude. No night boundary points.\n } else if (cosH > 1) {\n // All night — polar night at this latitude. Night spans all longitudes.\n sunset.push([lat, subSolarLon]);\n sunrise.push([lat, subSolarLon + 360]);\n } else {\n const H = (Math.acos(cosH) * 180) / Math.PI;\n // Sunset boundary: H degrees EAST of the sub-solar point (afternoon side).\n // Observers here see the sun setting in the west — entering night.\n sunset.push([lat, subSolarLon + H]);\n // Sunrise boundary: H degrees WEST of the sub-solar point (morning side),\n // expressed as subSolarLon - H + 360 to keep values > sunset for a continuous polygon.\n sunrise.push([lat, subSolarLon + 360 - H]);\n }\n }\n \n return { sunset, sunrise };\n}\n\n/**\n * Build the full night polygon, properly closing the loops around the poles.\n * Ensures longitudes are strictly continuous so the map projection doesn't\n * draw antimeridian lines across the day side.\n */\nfunction buildNightPolygon(\n terminator: { sunset: Array<[number, number]>, sunrise: Array<[number, number]> }\n): [number, number][] {\n const { sunset, sunrise } = terminator;\n if (!sunset.length || !sunrise.length) return [];\n\n const poly: [number, number][] = [];\n\n // Left edge of night (sunset): South to North\n poly.push(...sunset);\n\n // Right edge of night (sunrise): North to South\n poly.push(...[...sunrise].reverse());\n\n // Leaflet will automatically close the polygon by connecting the last point \n // (South end of sunrise) back to the first point (South end of sunset).\n // Because longitudes are continuous and bounded (sunrise.lon - sunset.lon <= 360),\n // this closing line will simply span the bottom or top of the map, perfectly\n // enclosing the night area without crossing the day side!\n\n return poly;\n}\n\nexport type GroundStationMapItem = GroundStation | GroundStationEnhanced | SROGroundStation;\n\nexport interface GroundTrackMapLeafletProps {\n allSatellites: SatelliteTrack[];\n groundStations: GroundStationMapItem[];\n showTerminator?: boolean;\n /** Override the time used for the terminator calculation (defaults to wall-clock now). */\n terminatorTime?: Date;\n showGrid?: boolean;\n showLegend?: boolean;\n showEquator?: boolean;\n showRecenterButton?: boolean;\n /** Show a toggle button to switch between Dark and Satellite tile styles. Default true. */\n showMapStyleToggle?: boolean;\n defaultCenter?: [number, number];\n defaultZoom?: number;\n height?: number | string;\n width?: number | string;\n minHeight?: string;\n emptyMessage?: string;\n tileUrl?: string;\n /**\n * URL template for a \"night\" tile layer (e.g. NASA Black Marble, VIIRS city lights).\n * Rendered beneath the terminator overlay so it only appears on the dark side.\n * Requires `showTerminator`. Falls back to dark overlay when not provided.\n */\n nightTileUrl?: string;\n /**\n * Point light sources rendered on the night side (masked by the terminator).\n * Each light fades in through twilight and reaches full brightness at night.\n */\n lightSources?: LightSource[];\n className?: string;\n onSatelliteClick?: (id: string) => void;\n onStationClick?: (id: string) => void;\n /** Points-of-interest pins */\n pins?: MapPin[];\n /** Allow adding/editing pins via map clicks */\n pinsEditable?: boolean;\n onPinAdd?: (pin: Omit<MapPin, 'id'>) => void;\n onPinUpdate?: (pin: MapPin) => void;\n onPinRemove?: (pinId: string) => void;\n /** Custom overlay layers for the Layers panel */\n customLayers?: MapLayerDef[];\n /** Called when any layer is toggled */\n onLayerChange?: (layerId: string, enabled: boolean) => void;\n /**\n * Show sun and moon position markers on the map.\n * Requires `showTerminator`. Default: true when terminator is enabled.\n */\n showCelestialMarkers?: boolean;\n}\n\nexport function GroundTrackMapLeaflet({\n allSatellites,\n groundStations,\n showTerminator = true,\n terminatorTime,\n showGrid = false,\n showLegend = true,\n showEquator = false,\n showRecenterButton = true,\n showMapStyleToggle = true,\n defaultCenter = [20, 0],\n defaultZoom = 2,\n height = '100%',\n width = '100%',\n minHeight = '400px',\n emptyMessage = 'No orbital data available',\n tileUrl,\n nightTileUrl,\n lightSources,\n className = '',\n onSatelliteClick,\n onStationClick,\n pins,\n pinsEditable = false,\n onPinAdd,\n onPinUpdate,\n onPinRemove,\n customLayers,\n onLayerChange,\n showCelestialMarkers,\n}: GroundTrackMapLeafletProps): React.ReactElement {\n const { tokens } = useTheme();\n const containerRef = useRef<HTMLDivElement>(null);\n const mapRef = useRef<L.Map | null>(null);\n const tileLayerRef = useRef<L.TileLayer | null>(null);\n const overlayGroupRef = useRef<L.LayerGroup | null>(null);\n const controlsRef = useRef<L.Control[]>([]);\n /** Separate layer group so pin updates don't clear satellite/station layers */\n const pinsGroupRef = useRef<L.LayerGroup | null>(null);\n const [ready, setReady] = useState(false);\n\n // ── Layers panel open/close ──\n const [layersPanelOpen, setLayersPanelOpen] = useState(false);\n const layersPanelRef = useRef<HTMLDivElement>(null);\n\n // Close layers panel when clicking outside\n useEffect(() => {\n if (!layersPanelOpen) return;\n const handleClickOutside = (e: MouseEvent) => {\n if (layersPanelRef.current && !layersPanelRef.current.contains(e.target as Node)) {\n setLayersPanelOpen(false);\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [layersPanelOpen]);\n\n // ── Tile style with localStorage persistence ──\n const TILE_STORAGE_KEY = 'zendir-map-tile-style';\n const isExplicitTileUrl = tileUrl !== undefined;\n const [tileStyle, setTileStyle] = useState<'dark' | 'satellite'>(() => {\n if (isExplicitTileUrl) return 'dark';\n try {\n const saved = localStorage.getItem(TILE_STORAGE_KEY);\n if (saved === 'dark' || saved === 'satellite') return saved;\n } catch { /* SSR / storage blocked */ }\n return 'dark';\n });\n\n const handleTileStyleChange = useCallback((style: 'dark' | 'satellite') => {\n setTileStyle(style);\n try { localStorage.setItem(TILE_STORAGE_KEY, style); } catch { /* noop */ }\n }, []);\n\n const effectiveTileUrl = isExplicitTileUrl ? tileUrl : TILE_PRESETS[tileStyle];\n\n // ── Internal overlay toggle state (built-in layers: terminator, grid) ──\n const [internalTerminator, setInternalTerminator] = useState(showTerminator);\n const [internalGrid, setInternalGrid] = useState(showGrid);\n\n // Sync with prop changes (props are the initial source of truth)\n useEffect(() => { setInternalTerminator(showTerminator); }, [showTerminator]);\n useEffect(() => { setInternalGrid(showGrid); }, [showGrid]);\n\n // ── Custom layer toggle state ──\n const [customLayerState, setCustomLayerState] = useState<Record<string, boolean>>(() => {\n const state: Record<string, boolean> = {};\n for (const l of customLayers ?? []) {\n state[l.id] = l.defaultEnabled ?? true;\n }\n return state;\n });\n\n // Sync when customLayers prop changes (add new layers with defaults)\n useEffect(() => {\n setCustomLayerState((prev) => {\n const next = { ...prev };\n for (const l of customLayers ?? []) {\n if (!(l.id in next)) next[l.id] = l.defaultEnabled ?? true;\n }\n return next;\n });\n }, [customLayers]);\n\n const handleLayerToggle = useCallback((layerId: string, enabled: boolean) => {\n if (layerId === 'terminator') {\n setInternalTerminator(enabled);\n } else if (layerId === 'grid') {\n setInternalGrid(enabled);\n } else {\n setCustomLayerState((prev) => ({ ...prev, [layerId]: enabled }));\n }\n onLayerChange?.(layerId, enabled);\n }, [onLayerChange]);\n\n const clearLayers = useCallback(() => {\n const map = mapRef.current;\n if (!map) return;\n overlayGroupRef.current?.clearLayers();\n controlsRef.current.forEach((ctrl) => map.removeControl(ctrl));\n controlsRef.current = [];\n }, []);\n\n const addLayer = useCallback((layer: L.Layer) => {\n overlayGroupRef.current?.addLayer(layer);\n }, []);\n\n // Create map once on mount (or when tileUrl changes). Intentionally not depending on\n // defaultCenter/defaultZoom so animated updates do not recreate the map (no flicker/zoom reset).\n useEffect(() => {\n // eslint-disable-next-line react-hooks/exhaustive-deps -- defaultCenter/defaultZoom used only for initial view\n const el = containerRef.current;\n if (!el) return;\n\n const center: L.LatLngExpression = defaultCenter ?? [20, 0];\n const zoom = defaultZoom ?? 2;\n\n const map = L.map(el, {\n center,\n zoom,\n zoomControl: false,\n scrollWheelZoom: true,\n doubleClickZoom: true,\n touchZoom: true,\n boxZoom: true,\n keyboard: true,\n dragging: true,\n attributionControl: true,\n maxBounds: [[-90, -540], [90, 540]],\n maxBoundsViscosity: 1.0,\n });\n\n map.attributionControl.setPrefix('');\n\n const overlayGroup = L.layerGroup();\n overlayGroup.addTo(map);\n overlayGroupRef.current = overlayGroup;\n\n const pinsGroup = L.layerGroup();\n pinsGroup.addTo(map);\n pinsGroupRef.current = pinsGroup;\n\n mapRef.current = map;\n setReady(true);\n\n const onSize = () => {\n map.invalidateSize({ animate: false });\n };\n // Immediate RAF + two deferred calls cover: first paint, CSS transitions, flex layout settle\n const raf = requestAnimationFrame(onSize);\n const t1 = setTimeout(onSize, 150);\n const t2 = setTimeout(onSize, 500);\n\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n cancelAnimationFrame(raf);\n clearLayers();\n pinsGroupRef.current?.clearLayers();\n pinsGroupRef.current = null;\n tileLayerRef.current = null;\n map.remove();\n mapRef.current = null;\n overlayGroupRef.current = null;\n };\n // Mount-only: tile layer is swapped by a dedicated effect below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [clearLayers]);\n\n // Swap tile layer without recreating the entire map (avoids flash on style toggle).\n useEffect(() => {\n const map = mapRef.current;\n if (!map || !ready) return;\n\n // Remove existing tile layer (Leaflet drops that layer's attribution with it)\n if (tileLayerRef.current) {\n tileLayerRef.current.remove();\n tileLayerRef.current = null;\n }\n\n const isCartoTiles = effectiveTileUrl.includes('cartocdn');\n const basemapAttribution = getBasemapAttribution(effectiveTileUrl);\n\n const tile = L.tileLayer(effectiveTileUrl, {\n maxZoom: 19,\n subdomains: isCartoTiles ? 'abcd' : 'abc',\n crossOrigin: true,\n attribution: basemapAttribution || undefined,\n });\n tile.addTo(map);\n tile.bringToBack();\n tileLayerRef.current = tile;\n\n // Fallback on tile error\n let hasSwitchedToFallback = false;\n const onTileError = () => {\n if (hasSwitchedToFallback) return;\n hasSwitchedToFallback = true;\n tile.off('tileerror', onTileError);\n tile.remove();\n const fallback = L.tileLayer(FALLBACK_TILE, {\n maxZoom: 19,\n subdomains: 'abc',\n crossOrigin: true,\n attribution: OSM_ATTRIBUTION,\n });\n fallback.addTo(map);\n fallback.bringToBack();\n tileLayerRef.current = fallback;\n };\n tile.on('tileerror', onTileError);\n }, [effectiveTileUrl, ready]);\n\n useEffect(() => {\n if (!ready || !mapRef.current) return;\n const map = mapRef.current;\n clearLayers();\n\n // === Night Tile Layer (placed beneath terminator so night imagery appears on dark side) ===\n if (nightTileUrl && internalTerminator) {\n const nightTile = L.tileLayer(nightTileUrl, {\n maxZoom: 19,\n crossOrigin: true,\n opacity: 0.7,\n className: 'zendir-night-tiles',\n });\n addLayer(nightTile);\n }\n\n if (internalTerminator) {\n const now = terminatorTime ?? new Date();\n\n // Graduated terminator shade. Stronger on satellite imagery for contrast,\n // lighter on dark tiles where subtlety reads better.\n const isSatelliteTile = tileStyle === 'satellite';\n const BAND_STEP = 1.5;\n const MAX_DEP = 30;\n const NIGHT_OPACITY = isSatelliteTile ? 0.75 : 0.38;\n const NIGHT_COLOR = isSatelliteTile ? '#030810' : '#2a3a52';\n const bandSteps: Array<{ depression: number; opacity: number; color: string }> = [];\n for (let d = 0; d <= MAX_DEP; d += BAND_STEP) {\n const t = Math.min(d / 18, 1);\n const opacity = Math.pow(t, 1.6) * (NIGHT_OPACITY * 0.85) + (d > 18 ? (d - 18) / 12 * (NIGHT_OPACITY * 0.15) : 0);\n bandSteps.push({ depression: d, opacity: Math.min(opacity, NIGHT_OPACITY), color: NIGHT_COLOR });\n }\n bandSteps.push({ depression: 90, opacity: NIGHT_OPACITY, color: NIGHT_COLOR });\n\n let prevOpacity = 0;\n\n // Draw each band as a cumulative overlay — each adds incremental darkening\n // By stacking full night polygons with small opacities, we avoid drawing\n // complex band-difference polygons, which is much more robust at the poles.\n for (const b of bandSteps) {\n const terminator = calculateTerminatorContinuous(now, Math.min(b.depression, 89));\n const bandOpacity = b.opacity - prevOpacity;\n if (bandOpacity < 0.002 || terminator.sunset.length === 0) {\n prevOpacity = b.opacity;\n continue;\n }\n\n const poly = buildNightPolygon(terminator);\n if (poly.length < 3) continue;\n\n [0, 360, -360].forEach((offset) => {\n const shifted = poly.map(([lat, lon]) => [lat, lon + offset] as [number, number]);\n addLayer(L.polygon(shifted, {\n color: 'transparent',\n fillColor: b.color,\n fillOpacity: bandOpacity,\n interactive: false,\n }));\n });\n \n prevOpacity = b.opacity;\n }\n\n // Draw a smooth terminator boundary line (0° depression)\n // — a thin, continuous stroke showing the day/night geometric edge.\n // Styling adapts to tile style: brighter on satellite for visibility.\n const terminatorEdge = calculateTerminatorContinuous(now, 0);\n const glowColor = isSatelliteTile ? '#a0a0a0' : '#909090';\n const glowOpacity = isSatelliteTile ? 0.15 : 0.08;\n const coreColor = isSatelliteTile ? '#c0c0c0' : '#a8a8a8';\n const coreOpacity = isSatelliteTile ? 0.45 : 0.30;\n if (terminatorEdge.sunset.length > 2) {\n const sunsetLine = terminatorEdge.sunset.map(([lat, lon]) => [lat, lon] as [number, number]);\n const sunriseLine = terminatorEdge.sunrise.map(([lat, lon]) => [lat, lon] as [number, number]);\n [0, 360, -360].forEach((offset) => {\n addLayer(L.polyline(\n sunsetLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: glowColor, weight: 3, opacity: glowOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n addLayer(L.polyline(\n sunriseLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: glowColor, weight: 3, opacity: glowOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n addLayer(L.polyline(\n sunsetLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: coreColor, weight: 1, opacity: coreOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n addLayer(L.polyline(\n sunriseLine.map(([lat, lon]) => [lat, lon + offset] as [number, number]),\n { color: coreColor, weight: 1, opacity: coreOpacity, interactive: false, smoothFactor: 1.5 }\n ));\n });\n }\n\n // TODO: Re-enable sun/moon celestial markers once visual design is finalized.\n // Calculations (calculateSubSolarPoint, calculateSubLunarPoint) are correct.\n // Uncomment and set back to prop-driven to restore:\n // const celestialEnabled = showCelestialMarkers !== undefined ? showCelestialMarkers : true;\n const celestialEnabled = false;\n if (celestialEnabled) {\n const [sunLat, sunLon] = calculateSubSolarPoint(now);\n const sunIcon = L.divIcon({\n className: '',\n iconSize: [28, 28] as unknown as L.PointExpression,\n iconAnchor: [14, 14] as unknown as L.PointExpression,\n html: `<svg width=\"28\" height=\"28\" viewBox=\"0 0 28 28\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs><filter id=\"sun-glow\"><feGaussianBlur stdDeviation=\"1.5\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs>\n <circle cx=\"14\" cy=\"14\" r=\"6\" fill=\"#FFB300\" stroke=\"#FF8F00\" stroke-width=\"1.2\" filter=\"url(#sun-glow)\"/>\n ${[0,45,90,135,180,225,270,315].map(a => {\n const r1 = 8, r2 = 12, rad = a * Math.PI / 180;\n return `<line x1=\"${14+r1*Math.cos(rad)}\" y1=\"${14+r1*Math.sin(rad)}\" x2=\"${14+r2*Math.cos(rad)}\" y2=\"${14+r2*Math.sin(rad)}\" stroke=\"#FFB300\" stroke-width=\"1.4\" stroke-linecap=\"round\" opacity=\"0.85\"/>`;\n }).join('')}\n </svg>`,\n });\n const sunMarker = L.marker([sunLat, sunLon], { icon: sunIcon, interactive: true, zIndexOffset: 800 });\n sunMarker.bindTooltip(\n `<b>Sub-Solar Point</b><br/>Sun's zenith position<br/>Lat ${sunLat.toFixed(2)}° Lon ${sunLon.toFixed(2)}°`,\n { direction: 'top', offset: [0, -14] as unknown as L.PointExpression, className: 'zendir-celestial-tooltip' }\n );\n addLayer(sunMarker);\n\n // Sub-lunar point marker\n const [moonLat, moonLon] = calculateSubLunarPoint(now);\n const moonIcon = L.divIcon({\n className: '',\n iconSize: [22, 22] as unknown as L.PointExpression,\n iconAnchor: [11, 11] as unknown as L.PointExpression,\n html: `<svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs><filter id=\"moon-glow\"><feGaussianBlur stdDeviation=\"1\" result=\"blur\"/><feMerge><feMergeNode in=\"blur\"/><feMergeNode in=\"SourceGraphic\"/></feMerge></filter></defs>\n <circle cx=\"11\" cy=\"11\" r=\"6.5\" fill=\"#e0e0e0\" stroke=\"#9e9e9e\" stroke-width=\"0.8\" filter=\"url(#moon-glow)\" opacity=\"0.9\"/>\n <circle cx=\"9\" cy=\"9.5\" r=\"1.6\" fill=\"#bdbdbd\" opacity=\"0.5\"/>\n <circle cx=\"13\" cy=\"12\" r=\"1.0\" fill=\"#bdbdbd\" opacity=\"0.4\"/>\n <circle cx=\"10.5\" cy=\"13.5\" r=\"0.7\" fill=\"#bdbdbd\" opacity=\"0.35\"/>\n </svg>`,\n });\n const moonMarker = L.marker([moonLat, moonLon], { icon: moonIcon, interactive: true, zIndexOffset: 790 });\n moonMarker.bindTooltip(\n `<b>Sub-Lunar Point</b><br/>Moon's zenith position<br/>Lat ${moonLat.toFixed(2)}° Lon ${moonLon.toFixed(2)}°`,\n { direction: 'top', offset: [0, -11] as unknown as L.PointExpression, className: 'zendir-celestial-tooltip' }\n );\n addLayer(moonMarker);\n } // end celestialEnabled\n }\n\n // === Light Sources (rendered as glowing markers on the night side) ===\n if (lightSources && lightSources.length > 0 && internalTerminator) {\n const now = terminatorTime ?? new Date();\n const dayOfYear = Math.floor((now.getTime() - Date.UTC(now.getUTCFullYear(), 0, 0)) / 86400000);\n const declination = -23.44 * Math.cos((2 * Math.PI / 365) * (dayOfYear + 10));\n const decRad = (declination * Math.PI) / 180;\n const lsSubSolarLon = -((now.getUTCHours() + now.getUTCMinutes() / 60) - 12) * 15;\n\n for (const light of lightSources) {\n const latRad = (light.latitude * Math.PI) / 180;\n const sinAlt = Math.sin(latRad) * Math.sin(decRad) +\n Math.cos(latRad) * Math.cos(decRad) *\n Math.cos(((light.longitude - lsSubSolarLon) * Math.PI) / 180);\n const solarAltDeg = (Math.asin(sinAlt) * 180) / Math.PI;\n\n let nightFactor: number;\n if (solarAltDeg >= 0) nightFactor = 0;\n else if (solarAltDeg <= -18) nightFactor = 1;\n else nightFactor = Math.min(1, -solarAltDeg / 18);\n\n if (nightFactor < 0.01) continue;\n\n const r = light.radius ?? 4;\n const intensity = light.intensity ?? 0.8;\n const color = light.color ?? '#ffeedd';\n const alpha = intensity * nightFactor;\n\n // Outer glow circle\n const glowMarker = L.circleMarker([light.latitude, light.longitude], {\n radius: r * 2,\n fillColor: color,\n fillOpacity: alpha * 0.4,\n color: color,\n weight: 0,\n interactive: !!light.label,\n });\n addLayer(glowMarker);\n\n // Bright core\n const coreMarker = L.circleMarker([light.latitude, light.longitude], {\n radius: Math.max(1, r * 0.5),\n fillColor: color,\n fillOpacity: Math.min(1, alpha * 1.2),\n color: 'transparent',\n weight: 0,\n interactive: false,\n });\n addLayer(coreMarker);\n\n if (light.label) {\n glowMarker.bindTooltip(light.label, {\n permanent: false,\n direction: 'top',\n className: 'zendir-leaflet-tooltip',\n });\n }\n }\n }\n\n if (internalGrid) {\n const gridStyle = { color: 'rgba(157, 112, 255, 0.12)', weight: 0.5, interactive: false };\n [-360, 0, 360].forEach((offset) => {\n for (let lon = -180; lon <= 180; lon += 30) {\n const l = lon + offset;\n addLayer(L.polyline([[90, l], [-90, l]], gridStyle));\n }\n for (let lat = -90; lat <= 90; lat += 30) {\n addLayer(L.polyline([[lat, -180 + offset], [lat, 180 + offset]], gridStyle));\n }\n });\n }\n\n if (showEquator) {\n [-360, 0, 360].forEach((offset) => {\n addLayer(L.polyline([[0, -180 + offset], [0, 180 + offset]], {\n color: 'rgba(88, 166, 255, 0.25)',\n weight: 1,\n dashArray: '6, 4',\n interactive: false,\n }));\n });\n }\n\n groundStations.forEach((gs) => {\n const status = ('status' in gs ? gs.status : undefined) ?? 'standby';\n const statusColor = STATUS_COLOR_MAP[status] || STATUS_COLOR_MAP.standby;\n const stationType = ('type' in gs ? (gs as { type?: string }).type : undefined) ?? 'dish';\n const radius = 'coverageRadius' in gs ? gs.coverageRadius : undefined;\n const showCoverage = 'showCoverage' in gs ? gs.showCoverage : false;\n if (radius != null && radius > 0 && showCoverage) {\n const ring = geodesicCirclePoints(gs.latitude, gs.longitude, radius, 64);\n const rings = splitRingAtAntimeridian(ring);\n [0, 360, -360].forEach((offset) => {\n rings.forEach((r) => {\n const shifted = r.map(([lat, lon]) => [lat, lon + offset] as [number, number]);\n addLayer(L.polygon(shifted, {\n color: `${statusColor}55`,\n fillColor: statusColor,\n fillOpacity: 0.1,\n weight: 1,\n dashArray: '4, 3',\n interactive: false,\n }));\n });\n });\n }\n\n const gsIcon = createStationDivIcon(statusColor, stationType, status);\n const marker = L.marker([gs.latitude, gs.longitude], { icon: gsIcon });\n addLayer(marker);\n const statusLabel = status !== 'standby' ? ` · ${status}` : '';\n marker.bindTooltip(\n `<strong>${gs.name}</strong>${statusLabel}${'network' in gs && gs.network ? `<br/><span style=\"opacity:0.7\">${gs.network}</span>` : ''}`,\n { permanent: false, direction: 'top', className: 'zendir-leaflet-tooltip' }\n );\n marker.on('click', () => {\n onStationClick?.('id' in gs ? String(gs.id) : gs.name);\n });\n });\n\n allSatellites.forEach((sat, satIdx) => {\n const track = sat.groundTrack;\n if (!track || track.length === 0) return;\n\n const color = sat.color || DEFAULT_TRACK_COLORS[satIdx % DEFAULT_TRACK_COLORS.length];\n const futureIdx = sat.futureTrackIndex ?? track.length;\n\n const pastLatLngs = track\n .slice(0, futureIdx)\n .map((p) => [p.latitude, p.longitude] as [number, number]);\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(pastLatLngs)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color, weight: 2.5, opacity: 1 }));\n }\n });\n\n if (futureIdx < track.length) {\n const futureLatLngs = track\n .slice(futureIdx)\n .map((p) => [p.latitude, p.longitude] as [number, number]);\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(futureLatLngs)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color, weight: 1.5, opacity: 0.5, dashArray: '6, 4' }));\n }\n });\n }\n\n // Access mask segments (contact passes) — solid green overlay on track\n if (sat.accessMask && sat.accessMask.some(Boolean)) {\n let segment: [number, number][] = [];\n for (let i = 0; i < track.length; i++) {\n if (sat.accessMask[i]) {\n segment.push([track[i].latitude, track[i].longitude]);\n } else if (segment.length >= 2) {\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(segment)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color: STATUS_COLOR_MAP.normal, weight: 4, opacity: 0.9 }));\n }\n });\n segment = [];\n } else {\n segment = [];\n }\n }\n if (segment.length >= 2) {\n segmentsWithWorldCopies(splitPolylineAtAntimeridian(segment)).forEach((seg) => {\n if (seg.length >= 2) {\n addLayer(L.polyline(seg, { color: STATUS_COLOR_MAP.normal, weight: 4, opacity: 0.9 }));\n }\n });\n }\n }\n\n if (sat.passMarkers && sat.passMarkers.length > 0) {\n sat.passMarkers.forEach((pm) => {\n const isAos = pm.type === 'aos';\n const pmColor = isAos ? '#56f000' : '#ff3838';\n const pmMarker = L.circleMarker([pm.latitude, pm.longitude], {\n radius: 5,\n fillColor: pmColor,\n color: `${pmColor}cc`,\n weight: 1.5,\n fillOpacity: 0.9,\n });\n addLayer(pmMarker);\n pmMarker.bindTooltip(`${pm.type.toUpperCase()}${pm.label ? ` – ${pm.label}` : ''}`, {\n permanent: false,\n direction: 'top',\n className: 'zendir-leaflet-tooltip',\n });\n });\n }\n\n if (sat.showFootprint && sat.footprintRadius) {\n const lastIdx = futureIdx > 0 ? Math.min(futureIdx - 1, track.length - 1) : track.length - 1;\n const last = track[lastIdx];\n const ring = geodesicCirclePoints(last.latitude, last.longitude, sat.footprintRadius, 64);\n const rings = splitRingAtAntimeridian(ring);\n [0, 360, -360].forEach((offset) => {\n rings.forEach((r) => {\n const shifted = r.map(([lat, lon]) => [lat, lon + offset] as [number, number]);\n addLayer(L.polygon(shifted, {\n color: `${color}50`,\n fillColor: color,\n fillOpacity: 0.03,\n weight: 1,\n dashArray: '4, 4',\n interactive: false,\n }));\n });\n });\n }\n\n const currentIdx = futureIdx > 0 ? Math.min(futureIdx - 1, track.length - 1) : track.length - 1;\n const current = track[currentIdx];\n const statusColor = STATUS_COLOR_MAP[sat.status || 'normal'] || STATUS_COLOR_MAP.normal;\n\n const satIcon = createSatDivIcon(statusColor, color);\n const satMarker = L.marker([current.latitude, current.longitude], { icon: satIcon });\n addLayer(satMarker);\n satMarker.bindTooltip(\n `<strong style=\"color:${color}\">${sat.name}</strong><br/>` +\n `Lat ${current.latitude.toFixed(3)}° &nbsp; Lon ${current.longitude.toFixed(3)}°` +\n (current.altitude != null ? `<br/>Alt ${current.altitude.toFixed(1)} km` : '') +\n (sat.status ? `<br/><span style=\"color:${statusColor}\">${sat.status.toUpperCase()}</span>` : ''),\n { permanent: false, direction: 'top', className: 'zendir-leaflet-tooltip' }\n );\n satMarker.on('click', () => onSatelliteClick?.(sat.id));\n });\n\n if (showLegend && (allSatellites.length > 0 || groundStations.length > 0)) {\n const Legend = L.Control.extend({\n onAdd() {\n const div = L.DomUtil.create('div', 'leaflet-legend-zendir');\n div.style.cssText = `\n padding: 8px 12px; background: rgba(15,21,32,0.9); border: 1px solid rgba(157,112,255,0.2);\n border-radius: 8px; color: #e4e0f0; font-size: 11px; font-family: Roboto, sans-serif;\n `;\n allSatellites.forEach((s, i) => {\n const c = s.color || DEFAULT_TRACK_COLORS[i % DEFAULT_TRACK_COLORS.length];\n const row = document.createElement('div');\n row.style.cssText = 'display: flex; align-items: center; gap: 6px; margin: 2px 0;';\n const swatch = document.createElement('span');\n swatch.style.cssText = `width:8px;height:8px;border-radius:50%;background:${c};`;\n const label = document.createElement('span');\n label.textContent = s.name;\n row.appendChild(swatch);\n row.appendChild(label);\n div.appendChild(row);\n });\n if (groundStations.length > 0) {\n const row = document.createElement('div');\n row.style.cssText = 'display: flex; align-items: center; gap: 6px; margin: 2px 0; margin-top: 6px;';\n const swatch = document.createElement('span');\n swatch.style.cssText = 'width:8px;height:8px;border-radius:50%;background:#2dccff;';\n const label = document.createElement('span');\n label.textContent = `${groundStations.length} Ground Station${groundStations.length > 1 ? 's' : ''}`;\n row.appendChild(swatch);\n row.appendChild(label);\n div.appendChild(row);\n }\n return div;\n },\n });\n const legend = new Legend({ position: 'topleft' });\n legend.addTo(map);\n controlsRef.current.push(legend);\n }\n\n }, [\n ready,\n allSatellites,\n groundStations,\n internalTerminator,\n terminatorTime,\n nightTileUrl,\n lightSources,\n internalGrid,\n showEquator,\n showLegend,\n tileStyle,\n tokens.colors.text.secondary,\n addLayer,\n clearLayers,\n onSatelliteClick,\n onStationClick,\n ]);\n\n // ==========================================================================\n // Pins layer — separate from overlayGroup so pin updates don't rebuild tracks\n // ==========================================================================\n\n useEffect(() => {\n if (!ready || !mapRef.current) return;\n const group = pinsGroupRef.current;\n if (!group) return;\n group.clearLayers();\n\n if (!pins || pins.length === 0) return;\n const accentColor = tokens.colors.accent.primary;\n\n pins.forEach((pin) => {\n const pinColor = pin.color || accentColor;\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"36\" viewBox=\"0 0 24 36\">\n <defs>\n <filter id=\"pin-shadow-${pin.id}\" x=\"-30%\" y=\"-10%\" width=\"160%\" height=\"140%\">\n <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"2\" flood-color=\"#000\" flood-opacity=\"0.35\"/>\n </filter>\n </defs>\n <g filter=\"url(#pin-shadow-${pin.id})\">\n <path d=\"M12 2 C6.5 2 2 6.5 2 12 C2 19 12 34 12 34 C12 34 22 19 22 12 C22 6.5 17.5 2 12 2Z\"\n fill=\"${pinColor}\" stroke=\"rgba(255,255,255,0.5)\" stroke-width=\"1\"/>\n <circle cx=\"12\" cy=\"12\" r=\"4\" fill=\"#0d1323\" stroke=\"rgba(255,255,255,0.7)\" stroke-width=\"0.8\"/>\n </g>\n </svg>`;\n\n const icon = L.divIcon({\n html: svg,\n className: 'zendir-pin-icon',\n iconSize: [24, 36] as unknown as L.PointExpression,\n iconAnchor: [12, 36] as unknown as L.PointExpression,\n tooltipAnchor: [0, -36] as unknown as L.PointExpression,\n });\n\n const marker = L.marker([pin.latitude, pin.longitude], {\n icon,\n draggable: pinsEditable,\n title: pin.label ?? '',\n });\n\n // Rich tooltip\n const tooltipLines = [\n pin.label ? `<strong>${pin.label}</strong>` : '',\n pin.description ? `<div style=\"opacity:0.7;font-size:11px\">${pin.description}</div>` : '',\n `<div style=\"font-size:10px;opacity:0.5;font-family:monospace\">${pin.latitude.toFixed(4)}°, ${pin.longitude.toFixed(4)}°</div>`,\n pin.createdBy ? `<div style=\"font-size:10px;opacity:0.4;margin-top:2px\">by ${pin.createdBy}</div>` : '',\n ].filter(Boolean).join('');\n marker.bindTooltip(tooltipLines, {\n className: 'zendir-pin-tooltip',\n direction: 'top',\n offset: [0, -4],\n });\n\n if (pinsEditable) {\n // Drag to reposition\n marker.on('dragend', () => {\n const latlng = marker.getLatLng();\n onPinUpdate?.({ ...pin, latitude: latlng.lat, longitude: latlng.lng });\n });\n\n // Right-click to delete\n marker.on('contextmenu', (e: L.LeafletEvent) => {\n L.DomEvent.stopPropagation(e as unknown as Event);\n onPinRemove?.(pin.id);\n });\n }\n\n group.addLayer(marker);\n });\n }, [ready, pins, pinsEditable, onPinUpdate, onPinRemove, tokens.colors.accent.primary]);\n\n // Click-to-add: listen for clicks on the map background when pinsEditable is true\n useEffect(() => {\n if (!ready || !mapRef.current || !pinsEditable || !onPinAdd) return;\n const map = mapRef.current;\n\n const handleClick = (e: L.LeafletMouseEvent) => {\n // Only fire on map background clicks — ignore clicks that bubbled from markers\n if ((e.originalEvent?.target as HTMLElement)?.closest?.('.leaflet-marker-icon')) return;\n onPinAdd({\n latitude: e.latlng.lat,\n longitude: e.latlng.lng,\n label: '',\n color: tokens.colors.accent.primary,\n });\n };\n\n map.on('click', handleClick);\n return () => { map.off('click', handleClick); };\n }, [ready, pinsEditable, onPinAdd, tokens.colors.accent.primary]);\n\n const handleRecenter = useCallback(() => {\n const map = mapRef.current;\n if (!map) return;\n const points: L.LatLngExpression[] = [];\n allSatellites.forEach((s) => {\n s.groundTrack.forEach((p) => points.push([p.latitude, p.longitude]));\n });\n groundStations.forEach((gs) => points.push([gs.latitude, gs.longitude]));\n if (points.length > 0) {\n const bounds = L.latLngBounds(points);\n map.fitBounds(bounds, { padding: [40, 40], maxZoom: 8 });\n } else {\n map.setView(defaultCenter, defaultZoom);\n }\n }, [allSatellites, groundStations, defaultCenter, defaultZoom]);\n\n const handleZoomIn = useCallback(() => { mapRef.current?.zoomIn(); }, []);\n const handleZoomOut = useCallback(() => { mapRef.current?.zoomOut(); }, []);\n\n const resolvedMinHeight = minHeight || (typeof height === 'number' ? `${height}px` : '400px');\n\n const isEmpty = allSatellites.length === 0 && groundStations.length === 0 && (!pins || pins.length === 0);\n\n // ── Shared control button style ──\n const ctrlBtnBase: React.CSSProperties = {\n background: 'rgba(20, 24, 38, 0.92)',\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n border: '1px solid rgba(120, 100, 180, 0.18)',\n color: '#c8c0d8',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background 0.15s, border-color 0.15s',\n };\n\n const ctrlHover = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.background = 'rgba(30, 34, 52, 0.95)';\n e.currentTarget.style.borderColor = 'rgba(157, 112, 255, 0.4)';\n };\n const ctrlLeave = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.currentTarget.style.background = 'rgba(20, 24, 38, 0.92)';\n e.currentTarget.style.borderColor = 'rgba(120, 100, 180, 0.18)';\n };\n\n // Overlay items shown in the Layers panel\n const overlayItems: Array<{ id: string; label: string; enabled: boolean }> = [];\n overlayItems.push({ id: 'terminator', label: 'Day / Night', enabled: internalTerminator });\n overlayItems.push({ id: 'grid', label: 'Grid Lines', enabled: internalGrid });\n for (const l of customLayers ?? []) {\n overlayItems.push({ id: l.id, label: l.label, enabled: customLayerState[l.id] ?? (l.defaultEnabled ?? true) });\n }\n\n return (\n <div\n className={`zendir-ground-track-map zendir-ground-track-map-leaflet${pinsEditable ? ' zendir-pins-editable' : ''} ${className}`}\n data-map-backend=\"leaflet\"\n style={{\n width,\n height,\n minHeight: resolvedMinHeight,\n backgroundColor: tokens.colors.background.base,\n borderRadius: 8,\n overflow: 'hidden',\n position: 'relative',\n }}\n >\n <div\n ref={containerRef}\n style={{ width: '100%', height: '100%', minHeight: resolvedMinHeight }}\n />\n {isEmpty && (\n <div\n style={{\n position: 'absolute',\n left: '50%',\n top: '50%',\n transform: 'translate(-50%, -50%)',\n color: tokens.colors.text.secondary,\n fontSize: 14,\n pointerEvents: 'none',\n }}\n >\n {emptyMessage}\n </div>\n )}\n {/* ── Unified Map Controls — top-right control bar ── */}\n <div\n style={{\n position: 'absolute',\n top: 10,\n right: 10,\n zIndex: 1000,\n display: 'flex',\n flexDirection: 'row',\n gap: 4,\n alignItems: 'flex-start',\n pointerEvents: 'none',\n }}\n >\n {/* Recenter */}\n {showRecenterButton && (\n <button\n type=\"button\"\n onClick={handleRecenter}\n title=\"Recenter map to fit all assets and ground stations\"\n aria-label=\"Recenter map\"\n style={{\n ...ctrlBtnBase,\n borderRadius: 4,\n padding: '6px 8px',\n gap: 4,\n fontSize: 10,\n fontWeight: 500,\n letterSpacing: '0.03em',\n pointerEvents: 'auto',\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M12 2v4M12 18v4M2 12h4M18 12h4\" />\n </svg>\n </button>\n )}\n\n {/* Layers panel */}\n <div ref={layersPanelRef} style={{ position: 'relative', pointerEvents: 'auto' }}>\n <button\n type=\"button\"\n onClick={() => setLayersPanelOpen((o) => !o)}\n title=\"Map layers\"\n aria-label=\"Toggle map layers panel\"\n aria-expanded={layersPanelOpen}\n style={{\n ...ctrlBtnBase,\n borderRadius: 4,\n padding: '6px 8px',\n pointerEvents: 'auto',\n borderColor: layersPanelOpen ? 'rgba(157, 112, 255, 0.4)' : ctrlBtnBase.border ? undefined : 'rgba(120, 100, 180, 0.18)',\n background: layersPanelOpen ? 'rgba(30, 34, 52, 0.95)' : ctrlBtnBase.background,\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >\n {/* Layers icon — stacked diamonds */}\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinejoin=\"round\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5z\" />\n <path d=\"M2 17l10 5 10-5\" />\n <path d=\"M2 12l10 5 10-5\" />\n </svg>\n </button>\n\n {/* Dropdown panel */}\n {layersPanelOpen && (\n <div\n style={{\n position: 'absolute',\n top: 'calc(100% + 6px)',\n right: 0,\n minWidth: 180,\n background: 'rgba(16, 18, 30, 0.96)',\n backdropFilter: 'blur(16px)',\n WebkitBackdropFilter: 'blur(16px)',\n border: '1px solid rgba(120, 100, 180, 0.18)',\n borderRadius: 6,\n padding: '8px 0',\n boxShadow: '0 8px 32px rgba(0,0,0,0.5)',\n }}\n >\n {/* Base Map section (only when no explicit tileUrl) */}\n {!isExplicitTileUrl && (\n <>\n <div style={{\n padding: '4px 12px 6px',\n fontSize: 9,\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase' as const,\n color: '#7a748e',\n }}>\n Base Map\n </div>\n <div style={{ display: 'flex', gap: 2, padding: '0 8px 8px' }}>\n {(['dark', 'satellite'] as const).map((style) => (\n <button\n key={style}\n type=\"button\"\n onClick={() => handleTileStyleChange(style)}\n aria-pressed={tileStyle === style}\n style={{\n flex: 1,\n background: tileStyle === style ? 'rgba(157, 112, 255, 0.18)' : 'rgba(255,255,255,0.03)',\n border: `1px solid ${tileStyle === style ? 'rgba(157, 112, 255, 0.35)' : 'rgba(120, 100, 180, 0.1)'}`,\n borderRadius: 4,\n color: tileStyle === style ? '#d0c4ee' : '#7a748e',\n cursor: 'pointer',\n padding: '5px 6px',\n fontSize: 10,\n fontWeight: tileStyle === style ? 600 : 400,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n transition: 'all 0.15s ease',\n }}\n >\n {style === 'dark' ? (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\">\n <path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\" />\n </svg>\n ) : (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z\" />\n </svg>\n )}\n {style === 'dark' ? 'Dark' : 'Satellite'}\n </button>\n ))}\n </div>\n <div style={{ height: 1, background: 'rgba(120, 100, 180, 0.1)', margin: '0 8px' }} />\n </>\n )}\n\n {/* Overlays section */}\n <div style={{\n padding: `${isExplicitTileUrl ? '4px' : '8px'} 12px 4px`,\n fontSize: 9,\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase' as const,\n color: '#7a748e',\n }}>\n Overlays\n </div>\n {overlayItems.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => handleLayerToggle(item.id, !item.enabled)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n width: '100%',\n padding: '5px 12px',\n background: 'transparent',\n border: 'none',\n color: item.enabled ? '#c8c0d8' : '#5a5470',\n cursor: 'pointer',\n fontSize: 11,\n textAlign: 'left' as const,\n transition: 'background 0.1s',\n }}\n onMouseEnter={(e) => { e.currentTarget.style.background = 'rgba(157, 112, 255, 0.08)'; }}\n onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}\n >\n {/* Toggle indicator */}\n <span style={{\n width: 14,\n height: 14,\n borderRadius: 3,\n border: `1.5px solid ${item.enabled ? 'rgba(157, 112, 255, 0.6)' : 'rgba(120, 100, 180, 0.25)'}`,\n background: item.enabled ? 'rgba(157, 112, 255, 0.22)' : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n transition: 'all 0.15s ease',\n }}>\n {item.enabled && (\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"#d0c4ee\" strokeWidth=\"2\">\n <path d=\"M2 6l3 3 5-5\" />\n </svg>\n )}\n </span>\n {item.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Zoom controls */}\n <div style={{ display: 'flex', flexDirection: 'column', pointerEvents: 'auto' }}>\n <button\n type=\"button\"\n onClick={handleZoomIn}\n title=\"Zoom in\"\n aria-label=\"Zoom in\"\n style={{\n ...ctrlBtnBase,\n borderRadius: '4px 4px 0 0',\n borderBottom: 'none',\n width: 30,\n height: 28,\n fontSize: 16,\n fontWeight: 300,\n pointerEvents: 'auto',\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >+</button>\n <button\n type=\"button\"\n onClick={handleZoomOut}\n title=\"Zoom out\"\n aria-label=\"Zoom out\"\n style={{\n ...ctrlBtnBase,\n borderRadius: '0 0 4px 4px',\n width: 30,\n height: 28,\n fontSize: 16,\n fontWeight: 300,\n pointerEvents: 'auto',\n }}\n onMouseEnter={ctrlHover}\n onMouseLeave={ctrlLeave}\n >−</button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default GroundTrackMapLeaflet;\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zendir/ui",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "React UI components for space operations, built on the Astro UX Design System",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",