<template>
    <div class="flight-map-wrapper">
        <PlaneLoader v-if="!mapReady" class="map-loader" />
        <div ref="mapContainer" class="map-container" :class="{ 'map-hidden': !mapReady }" />
        <div v-if="!flights.length" class="empty-state">
            <span class="mdi mdi-earth-off" />
            <p>No flight data available</p>
        </div>
    </div>
</template>

<script lang="ts">
import { defineComponent, ref, onMounted, onBeforeUnmount, watch, nextTick, PropType } from 'vue'
import maplibregl from 'maplibre-gl'
import 'maplibre-gl/dist/maplibre-gl.css'
import { SharedProps } from '@/Types/types'
import { usePage } from '@inertiajs/vue3'
import { Flight, Airport } from '@/Types/types'
import PlaneLoader from "@/Components/FlightsGoneBy/PlaneLoader.vue";

interface RouteFlightBucket {
    historical: Flight[]
    future: Flight[]
}

type LngLat = [number, number]

interface RouteFeatureProperties {
    color?: string
    routeKey: string
    depId: number
    arrId: number
}

interface AirportFeatureProperties {
    id: number
}

interface RoutesGeoJSON {
    historical: GeoJSON.FeatureCollection<GeoJSON.LineString, RouteFeatureProperties>
    future:     GeoJSON.FeatureCollection<GeoJSON.LineString, RouteFeatureProperties>
}


function greatCircleGeoJSON(from: LngLat, to: LngLat, steps?: number): LngLat[] {
    const dist = Math.sqrt((to[0] - from[0]) ** 2 + (to[1] - from[1]) ** 2)
    const s = steps ?? (dist > 60 ? 64 : dist > 20 ? 32 : 16)

    const toRad = (d: number): number => d * Math.PI / 180
    const toDeg = (r: number): number => r * 180 / Math.PI
    const lat1 = toRad(from[1]), lng1 = toRad(from[0])
    const lat2 = toRad(to[1]),   lng2 = toRad(to[0])
    const d = 2 * Math.asin(Math.sqrt(
        Math.sin((lat2 - lat1) / 2) ** 2 +
        Math.cos(lat1) * Math.cos(lat2) * Math.sin((lng2 - lng1) / 2) ** 2
    ))
    if (d === 0) return [[from[0], from[1]], [to[0], to[1]]]
    const points: LngLat[] = []
    for (let i = 0; i <= s; i++) {
        const f = i / s
        const A = Math.sin((1 - f) * d) / Math.sin(d)
        const B = Math.sin(f * d) / Math.sin(d)
        const x = A * Math.cos(lat1) * Math.cos(lng1) + B * Math.cos(lat2) * Math.cos(lng2)
        const y = A * Math.cos(lat1) * Math.sin(lng1) + B * Math.cos(lat2) * Math.sin(lng2)
        const z = A * Math.sin(lat1) + B * Math.sin(lat2)
        points.push([toDeg(Math.atan2(y, x)), toDeg(Math.atan2(z, Math.sqrt(x * x + y * y)))])
    }
    for (let i = 1; i < points.length; i++) {
        const diff = points[i][0] - points[i - 1][0]
        if (diff > 180)  points[i][0] -= 360
        if (diff < -180) points[i][0] += 360
    }
    return points
}

function airportPopupHTML(airport: Airport): string {
    const elevation = airport.elevation_ft !== null
        ? `<div class="ap-row"><span class="ap-label">Elevation</span><span class="ap-value">${airport.elevation_ft.toLocaleString()} ft</span></div>`
        : ''
    const city = airport.municipality
        ? `<div class="ap-row"><span class="ap-label">City</span><span class="ap-value">${airport.municipality}</span></div>`
        : ''
    const country = airport.region?.country
        ? `<div class="ap-row"><span class="ap-label">Country</span><span class="ap-value">${airport.region.country.name} <span class="fi fi-${airport.region.country.code.toLowerCase()}"></span></span></div>`
        : ''
    const iata = airport.iata_code ? `<span class="ap-badge">${airport.iata_code}</span>` : ''
    const icao = airport.icao_code ? `<span class="ap-badge">${airport.icao_code}</span>` : ''
    return `
        <div class="ap-tooltip glass">
            <div class="ap-header">
                <div class="ap-name">${airport.name}</div>
                <div class="ap-badges">${iata}${icao}</div>
            </div>
            <div class="ap-divider"></div>
            <div class="ap-rows">
                ${city}${country}${elevation}
                <div class="ap-row"><span class="ap-label">Timezone</span><span class="ap-value ap-mono">${airport.timezone}</span></div>
                <div class="ap-row"><span class="ap-label">Coordinates</span><span class="ap-value ap-mono ap-muted">${airport.latitude_deg.toFixed(4)}, ${airport.longitude_deg.toFixed(4)}</span></div>
            </div>
        </div>`
}

function routePopupHTML(historical: Flight[], future: Flight[]): string {
    interface DirectionGroup {
        label: string
        airlines: string[]
    }

    const groupByDirection = (list: Flight[]): DirectionGroup[] => {
        const logoApiUrl = usePage<SharedProps>().props.logo_api_url

        const dirs = new Map<string, DirectionGroup>()
        list.forEach(f => {
            const key   = `${f.departure_airport.id}-${f.arrival_airport.id}`
            const label = `${f.departure_airport.municipality} to ${f.arrival_airport.municipality}`
            if (!dirs.has(key)) dirs.set(key, { label, airlines: [] })
            const airline = `<span style="display:inline-flex;align-items:center;gap:6px;">
                <img src="${logoApiUrl}/airlines/logos/tail/id/${f.airline?.id}" width="24" height="24" alt="${f.airline?.IATA_code}" style="flex-shrink:0;" />
                ${f.airline?.name}
            </span>`
            if (airline && !dirs.get(key)!.airlines.includes(airline)) {
                dirs.get(key)!.airlines.push(airline)
            }
        })
        return [...dirs.values()]
    }

    const renderSection = (title: string, list: Flight[]): string => {
        if (!list.length) return ''
        const rows = groupByDirection(list).map(({ label, airlines }) => `
            <div class="rp-direction">
                <div class="rp-route">${label}</div>
                <div class="rp-airlines">${airlines.join('<br/>') || '—'}</div>
            </div>`).join('')
        return `<div class="rp-section"><div class="rp-section-title">${title}</div>${rows}</div>`
    }

    const divider = historical.length && future.length ? '<div class="rp-divider"></div>' : ''
    return `
        <div class="rp-tooltip glass">
            ${renderSection('Flown', historical)}
            ${divider}
            ${renderSection('Upcoming', future)}
        </div>`
}

export default defineComponent({
    name: 'FlightMap',
    components: {PlaneLoader},

    props: {
        flights: {
            type: Array as PropType<Flight[]>,
            default: (): Flight[] => [],
        },
    },

    setup(props) {
        const mapContainer = ref<HTMLDivElement | null>(null)
        let map:        maplibregl.Map | null = null
        let popup:      maplibregl.Popup | null = null
        let pulseFrame: number | null = null

        const PULSE_PHASES    = 6
        const TOUCH_RADIUS    = 20
        const airportById     = new Map<number, Airport>()
        const routeFlights    = new Map<string, RouteFlightBucket>()
        const arcCache        = new Map<string, LngLat[]>()
        let selectedAirportId: number | null = null

        const isTouchDevice = (): boolean => window.matchMedia('(pointer: coarse)').matches

        const showPopup = (lngLat: maplibregl.LngLatLike, html: string): void => {
            popup!.setLngLat(lngLat).setHTML(html).addTo(map!)
        }

        // ── Filter ────────────────────────────────────────────────────────────
        const applyFilter = (): void => {
            if (!map || !map.isStyleLoaded()) return
            const id = selectedAirportId

            const routeFilter: maplibregl.FilterSpecification | null = id
                ? ['any', ['==', ['get', 'depId'], id], ['==', ['get', 'arrId'], id]]
                : null

            map.setFilter('routes-line',        routeFilter)
            map.setFilter('routes-hit',         routeFilter)
            map.setFilter('routes-future-line', routeFilter)
            map.setFilter('routes-future-hit',  routeFilter)

            // Use setFilter on airport layers — GPU-side, no style recompilation
            for (let i = 0; i < PULSE_PHASES; i++) {
                const airportFilter: maplibregl.FilterSpecification | null = id
                    ? ['==', ['get', 'id'], id]
                    : null
                map.setFilter(`airports-dot-${i}`,   airportFilter)
                map.setFilter(`airports-pulse-${i}`, airportFilter)
            }
        }

        // ── Route flight lookup ───────────────────────────────────────────────
        const buildRouteFlights = (): void => {
            routeFlights.clear()
            const now = new Date()
            props.flights.forEach((flight) => {
                const key = [flight.departure_airport.id, flight.arrival_airport.id].sort().join('-')
                if (!routeFlights.has(key)) routeFlights.set(key, { historical: [], future: [] })
                routeFlights.get(key)![new Date(flight.departure_date) > now ? 'future' : 'historical'].push(flight)
            })
        }

        // ── Arc cache helper ──────────────────────────────────────────────────
        const getArc = (flight: Flight): LngLat[] => {
            const key = [flight.departure_airport.id, flight.arrival_airport.id].sort().join('-')
            if (!arcCache.has(key)) {
                arcCache.set(key, greatCircleGeoJSON(
                    [flight.departure_airport.longitude_deg, flight.departure_airport.latitude_deg],
                    [flight.arrival_airport.longitude_deg,   flight.arrival_airport.latitude_deg],
                ))
            }
            return arcCache.get(key)!
        }

        // ── GeoJSON builders ──────────────────────────────────────────────────
        const buildRoutesGeoJSON = (): RoutesGeoJSON => {
            buildRouteFlights()
            const now = new Date()

            const routeCounts = new Map<string, number>()
            props.flights.forEach((flight) => {
                if (new Date(flight.departure_date) > now) return
                const key = [flight.departure_airport.id, flight.arrival_airport.id].sort().join('-')
                routeCounts.set(key, (routeCounts.get(key) ?? 0) + 1)
            })

            const routeColor = (count: number): string => {
                if (count >= 5) return '#f97316'
                if (count >= 3) return '#eab308'
                if (count >= 2) return '#22c55e'
                return '#a150d5'
            }

            const seenHistorical = new Set<string>()
            const historicalFeatures: GeoJSON.Feature<GeoJSON.LineString, RouteFeatureProperties>[] = []
            props.flights
                .filter(f => new Date(f.departure_date) <= now)
                .forEach((flight) => {
                    const key = [flight.departure_airport.id, flight.arrival_airport.id].sort().join('-')
                    if (seenHistorical.has(key)) return
                    seenHistorical.add(key)
                    const count = routeCounts.get(key) ?? 1
                    historicalFeatures.push({
                        type: 'Feature',
                        properties: {
                            color: routeColor(count), routeKey: key,
                            depId: flight.departure_airport.id,
                            arrId: flight.arrival_airport.id,
                        },
                        geometry: { type: 'LineString', coordinates: getArc(flight) },
                    })
                })

            const historicalKeys = new Set(routeCounts.keys())
            const seenFuture = new Set<string>()
            const futureFeatures: GeoJSON.Feature<GeoJSON.LineString, RouteFeatureProperties>[] = []
            props.flights
                .filter((flight) => {
                    if (new Date(flight.departure_date) <= now) return false
                    const key = [flight.departure_airport.id, flight.arrival_airport.id].sort().join('-')
                    return !historicalKeys.has(key)
                })
                .forEach((flight) => {
                    const key = [flight.departure_airport.id, flight.arrival_airport.id].sort().join('-')
                    if (seenFuture.has(key)) return
                    seenFuture.add(key)
                    futureFeatures.push({
                        type: 'Feature',
                        properties: { routeKey: key, depId: flight.departure_airport.id, arrId: flight.arrival_airport.id },
                        geometry: { type: 'LineString', coordinates: getArc(flight) },
                    })
                })

            return {
                historical: { type: 'FeatureCollection', features: historicalFeatures },
                future:     { type: 'FeatureCollection', features: futureFeatures },
            }
        }

        const buildAirportsGeoJSON = (): GeoJSON.FeatureCollection<GeoJSON.Point, AirportFeatureProperties>[] => {
            const seen = new Map<number, Airport>()
            props.flights.forEach(({ departure_airport: dep, arrival_airport: arr }) => {
                if (!seen.has(dep.id)) seen.set(dep.id, dep)
                if (!seen.has(arr.id)) seen.set(arr.id, arr)
            })
            const buckets: Airport[][] = Array.from({ length: PULSE_PHASES }, () => [])
            ;[...seen.values()].forEach(airport => buckets[airport.id % PULSE_PHASES].push(airport))
            return buckets.map(airports => ({
                type: 'FeatureCollection',
                features: airports.map(airport => ({
                    type: 'Feature',
                    properties: { id: airport.id },
                    geometry: { type: 'Point', coordinates: [airport.longitude_deg, airport.latitude_deg] },
                })),
            }))
        }

        // ── Map layers ────────────────────────────────────────────────────────
        const addLayers = (): void => {
            const { historical, future } = buildRoutesGeoJSON()

            map!.addSource('routes', { type: 'geojson', data: historical })
            map!.addLayer({
                id: 'routes-line', type: 'line', source: 'routes',
                paint: { 'line-color': ['get', 'color'], 'line-opacity': 0.75, 'line-width': 1.8 },
                layout: { 'line-join': 'round', 'line-cap': 'round' },
            })
            map!.addLayer({
                id: 'routes-hit', type: 'line', source: 'routes',
                paint: { 'line-color': 'transparent', 'line-width': 12 },
            })

            map!.addSource('routes-future', { type: 'geojson', data: future })
            map!.addLayer({
                id: 'routes-future-line', type: 'line', source: 'routes-future',
                paint: { 'line-color': '#ffffff', 'line-opacity': 0.5, 'line-width': 1.5, 'line-dasharray': [3, 3] },
                layout: { 'line-join': 'round', 'line-cap': 'round' },
            })
            map!.addLayer({
                id: 'routes-future-hit', type: 'line', source: 'routes-future',
                paint: { 'line-color': 'transparent', 'line-width': 12 },
            })

            const airportBuckets = buildAirportsGeoJSON()
            airportBuckets.forEach((data, i) => {
                map!.addSource(`airports-${i}`, { type: 'geojson', data })
                map!.addLayer({
                    id: `airports-pulse-${i}`, type: 'circle', source: `airports-${i}`,
                    paint: {
                        'circle-radius': 8, 'circle-color': 'transparent',
                        'circle-stroke-width': 1.5, 'circle-stroke-color': 'rgba(77,166,255,0.6)',
                        'circle-stroke-opacity': 0.6,
                    },
                })
                map!.addLayer({
                    id: `airports-dot-${i}`, type: 'circle', source: `airports-${i}`,
                    paint: {
                        'circle-radius': 5, 'circle-color': '#4da6ff',
                        'circle-stroke-width': 1.5, 'circle-stroke-color': 'rgba(255,255,255,0.9)',
                    },
                })
            })

            const isTouch = isTouchDevice()
            popup = new maplibregl.Popup({
                closeButton: isTouch,
                closeOnClick: false,
                className: 'ap-popup',
                maxWidth: 'none',
                offset: 12,
            })

            const airportLayerIds = Array.from({ length: PULSE_PHASES }, (_, i) => `airports-dot-${i}`)

            // ── Desktop hover events ──────────────────────────────────────────
            if (!isTouch) {
                for (let i = 0; i < PULSE_PHASES; i++) {
                    map!.on('mouseenter', `airports-dot-${i}`, (e) => {
                        map!.getCanvas().style.cursor = 'pointer'
                        const airport = airportById.get(Number(e.features![0].properties.id))
                        const geom = e.features![0].geometry
                        if (airport && geom.type === 'Point') {
                            showPopup(geom.coordinates as LngLat, airportPopupHTML(airport))
                        }
                    })
                    map!.on('mouseleave', `airports-dot-${i}`, () => {
                        map!.getCanvas().style.cursor = ''
                        popup!.remove()
                    })
                }

                map!.on('mouseenter', 'routes-hit', (e) => {
                    map!.getCanvas().style.cursor = 'pointer'
                    const rf = routeFlights.get(e.features![0].properties.routeKey as string)
                    if (rf) showPopup(e.lngLat, routePopupHTML(rf.historical, rf.future))
                })
                map!.on('mouseleave', 'routes-hit', () => {
                    map!.getCanvas().style.cursor = ''
                    popup!.remove()
                })

                map!.on('mouseenter', 'routes-future-hit', (e) => {
                    map!.getCanvas().style.cursor = 'pointer'
                    const rf = routeFlights.get(e.features![0].properties.routeKey as string)
                    if (rf) showPopup(e.lngLat, routePopupHTML(rf.historical, rf.future))
                })
                map!.on('mouseleave', 'routes-future-hit', () => {
                    map!.getCanvas().style.cursor = ''
                    popup!.remove()
                })
            }

            // ── Unified click handler ─────────────────────────────────────────
            map!.on('click', (e) => {
                const airportQuery = isTouch
                    ? [[e.point.x - TOUCH_RADIUS, e.point.y - TOUCH_RADIUS], [e.point.x + TOUCH_RADIUS, e.point.y + TOUCH_RADIUS]] as [maplibregl.PointLike, maplibregl.PointLike]
                    : e.point as maplibregl.PointLike

                const airportFeatures = map!.queryRenderedFeatures(airportQuery, { layers: airportLayerIds })

                if (airportFeatures.length) {
                    const id = Number(airportFeatures[0].properties.id)
                    selectedAirportId = selectedAirportId === id ? null : id
                    applyFilter()

                    if (isTouch) {
                        const airport = airportById.get(id)
                        const geom = airportFeatures[0].geometry
                        if (airport && geom.type === 'Point') {
                            showPopup(geom.coordinates as LngLat, airportPopupHTML(airport))
                        }
                    }
                    return
                }

                const routeFeatures = map!.queryRenderedFeatures(e.point, {
                    layers: ['routes-hit', 'routes-future-hit'],
                })

                if (routeFeatures.length) {
                    const rf = routeFlights.get(routeFeatures[0].properties.routeKey as string)
                    if (rf) showPopup(e.lngLat, routePopupHTML(rf.historical, rf.future))
                    return
                }

                selectedAirportId = null
                applyFilter()
                popup!.remove()
            })

            // ── Pulse animation ───────────────────────────────────────────────
            const period = 2200
            const animate = (): void => {
                const now = Date.now()
                for (let i = 0; i < PULSE_PHASES; i++) {
                    const t = ((now + (i / PULSE_PHASES) * period) % period) / period
                    map!.setPaintProperty(`airports-pulse-${i}`, 'circle-radius', 5 + t * 13)
                    if (!selectedAirportId) {
                        map!.setPaintProperty(`airports-pulse-${i}`, 'circle-stroke-opacity', 0.7 * (1 - t))
                    }
                }
                pulseFrame = requestAnimationFrame(animate)
            }
            animate()
        }

        const fitBounds = (): void => {
            if (!props.flights.length) return
            let minLng = Infinity, maxLng = -Infinity, minLat = Infinity, maxLat = -Infinity
            props.flights.forEach(f => {
                minLng = Math.min(minLng, f.departure_airport.longitude_deg, f.arrival_airport.longitude_deg)
                maxLng = Math.max(maxLng, f.departure_airport.longitude_deg, f.arrival_airport.longitude_deg)
                minLat = Math.min(minLat, f.departure_airport.latitude_deg,  f.arrival_airport.latitude_deg)
                maxLat = Math.max(maxLat, f.departure_airport.latitude_deg,  f.arrival_airport.latitude_deg)
            })
            map!.fitBounds([[minLng, minLat], [maxLng, maxLat]], { padding: 60, duration: 0 })
        }

        // ── Map init ──────────────────────────────────────────────────────────
        const initMap = (): void => {
            nextTick(() => {
                map = new maplibregl.Map({
                    container: mapContainer.value!,
                    style: {
                        version: 8,
                        sources: {
                            'carto-dark': {
                                type: 'raster',
                                tiles: [
                                    'https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
                                    'https://b.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
                                    'https://c.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
                                    'https://d.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
                                ],
                                tileSize: 256,
                                attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="https://carto.com/attributions">CARTO</a>',
                                maxzoom: 19,
                            },
                        },
                        layers: [{ id: 'carto-dark', type: 'raster', source: 'carto-dark' }],
                    },
                    center: [0, 20],
                    zoom: 2,
                    renderWorldCopies: true,
                })
                map.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'top-right')
                map.on('load', () => {
                    addLayers()
                    fitBounds()
                    mapReady.value = true  // ← add this
                })
            })
        }

        // ── Data updates ──────────────────────────────────────────────────────
        const updateData = (): void => {
            if (!map || !map.isStyleLoaded()) return
            arcCache.clear()
            airportById.clear()
            props.flights.forEach(({ departure_airport: dep, arrival_airport: arr }) => {
                airportById.set(dep.id, dep)
                airportById.set(arr.id, arr)
            })
            const { historical, future } = buildRoutesGeoJSON();
            (map.getSource('routes') as maplibregl.GeoJSONSource)?.setData(historical);
            (map.getSource('routes-future') as maplibregl.GeoJSONSource)?.setData(future)
            buildAirportsGeoJSON().forEach((data, i) =>
                (map!.getSource(`airports-${i}`) as maplibregl.GeoJSONSource)?.setData(data)
            )
            fitBounds()
        }

        onMounted(() => {
            props.flights.forEach(({ departure_airport: dep, arrival_airport: arr }) => {
                airportById.set(dep.id, dep)
                airportById.set(arr.id, arr)
            })
            initMap()
        })

        watch(() => props.flights, updateData)

        onBeforeUnmount(() => {
            if (pulseFrame !== null) cancelAnimationFrame(pulseFrame)
            if (map) { map.remove(); map = null }
        })

        const mapReady = ref(false)

        return { mapContainer, mapReady }
    },
})
</script>

<style scoped>
.flight-map-wrapper {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    display: flex;
    align-items: center;
    justify-content: center;
}

.map-container {
    position: absolute;
    inset: 0;
}

.map-loader {
    z-index: 10;
}

.map-hidden {
    visibility: hidden;
}

.empty-state {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #3a4a58;
    gap: 12px;
    z-index: 900;
    pointer-events: none;
}

.empty-state .mdi { font-size: 48px; }
.empty-state p    { font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; margin: 0; }


</style>

<style>
.ap-popup .maplibregl-popup-content {
    background: transparent !important;
    border: none; border-radius: 0; padding: 0;
    box-shadow: none; backdrop-filter: none;
    color: #c8cdd8; width: max-content;
}
.ap-popup .maplibregl-popup-tip { border-top-color: rgba(10,14,22,0.95); }

.ap-popup .maplibregl-popup-close-button {
    color: #556677;
    font-size: 18px;
    padding: 4px 8px;
    right: 4px;
    top: 4px;
    line-height: 1;
    background: transparent;
    border: none;
}
.ap-popup .maplibregl-popup-close-button:hover { color: #c8cdd8; }

.ap-tooltip { padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }
.ap-header  { display: flex; flex-direction: column; gap: 6px; }
.ap-name    { font-size: 1.2em; color: #e0e6f0; line-height: 1.3; white-space: nowrap; }
.ap-badges  { display: flex; gap: 4px; flex-wrap: wrap; }
.ap-badge   {
    font-family: 'Share Tech Mono', monospace;
    font-size: 0.65rem; letter-spacing: 0.1em;
    background: rgba(77,166,255,0.12); border: 1px solid rgba(77,166,255,0.25);
    color: #4da6ff; border-radius: 3px; padding: 1px 6px;
}
.ap-divider { height: 1px; background: rgba(255,255,255,0.08); }
.ap-rows    { display: flex; flex-direction: column; gap: 4px; }
.ap-row     { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.ap-label   {
    font-family: 'Share Tech Mono', monospace;
    font-size: 0.6rem; letter-spacing: 0.15em; color: #445566;
    text-transform: uppercase; flex-shrink: 0;
}
.ap-value   { font-size: 0.78rem; color: #c8cdd8; text-align: right; }
.ap-mono    { font-family: 'Share Tech Mono', monospace; font-size: 0.7rem; letter-spacing: 0.03em; }
.ap-muted   { font-family: 'Share Tech Mono', monospace; font-size: 0.68rem; color: #556677; letter-spacing: 0.03em; }
.ap-value .fi { display: inline-block; vertical-align: middle; }

.rp-tooltip       { padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; min-width: 160px; }
.rp-section       { display: flex; flex-direction: column; gap: 6px; }
.rp-section-title {
    font-family: 'Share Tech Mono', monospace;
    font-size: 0.65rem; letter-spacing: 0.12em;
    text-transform: uppercase; color: #c8cdd8; margin-bottom: 2px;
}
.rp-direction { display: flex; flex-direction: column; gap: 2px; }
.rp-route     { font-size: 0.82rem; color: #e0e6f0; }
.rp-airlines  { font-size: 0.75rem; color: #778899; }
.rp-divider   { height: 1px; background: rgba(255,255,255,0.08); margin: 2px 0; }

.maplibregl-ctrl-group { background: rgba(10,14,22,0.85) !important; border: 1px solid rgba(255,255,255,0.08) !important; }
.maplibregl-ctrl-group button { color: #a0b4c8 !important; }
.maplibregl-ctrl-group button:hover { background: rgba(77,166,255,0.15) !important; color: #4da6ff !important; }
.maplibregl-ctrl-attrib { background: rgba(10,14,22,0.7) !important; color: #666 !important; }
.maplibregl-ctrl-attrib a { color: #666 !important; }



</style>
