<?php
/**
 * Office Dashboard — Kiosk Command Center
 * 7 auto-rotating slides, dark theme, fullscreen support.
 */
$db = getDB();
$todayShift = getShiftForDate();

// Data for server-rendered slides
$incidents = $db->query("SELECT * FROM incidents_cache WHERE received_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR) ORDER BY received_at DESC LIMIT 15")->fetchAll();
$incidentCount = count($incidents);

$emsSummary = null;
try { $emsSummary = $db->query("SELECT * FROM eso_ems_daily ORDER BY report_date DESC LIMIT 1")->fetch(PDO::FETCH_ASSOC); } catch(Exception $e) {}

$fireSummary = null;
try { $fireSummary = $db->query("SELECT * FROM eso_fire_daily ORDER BY report_date DESC LIMIT 1")->fetch(PDO::FETCH_ASSOC); } catch(Exception $e) {}
?>

<!-- Kiosk: ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@3/dist/echarts-liquidfill.min.js"></script>

<style>
/* ═══ KIOSK DARK COMMAND CENTER ═══ */
.kiosk {
    background: linear-gradient(135deg, #070F1B 0%, #0B2240 100%);
    min-height: calc(100vh - var(--top-offset) - var(--footer-height));
    margin: -24px;
    padding: 0;
    color: #fff;
    position: relative;
}

.kiosk-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 24px;
    border-bottom: 1px solid rgba(255,255,255,0.06);
    background: rgba(7,15,27,0.6);
    backdrop-filter: blur(12px);
}
.kiosk-toolbar-left { display: flex; align-items: center; gap: 12px; }
.kiosk-toolbar h1 { font-size: 14px; font-weight: 700; letter-spacing: 0.2px; color: rgba(255,255,255,0.85); }
.kiosk-shift {
    padding: 4px 12px; border-radius: 20px; font-size: 11px; font-weight: 700; color: #fff;
}
.kiosk-toolbar-right { display: flex; align-items: center; gap: 8px; }

.kiosk-btn {
    background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.1);
    color: rgba(255,255,255,0.6); padding: 6px 14px; border-radius: 8px;
    font-size: 11px; font-weight: 600; cursor: pointer; transition: all 0.2s;
    display: inline-flex; align-items: center; gap: 6px;
}
.kiosk-btn:hover { background: rgba(255,255,255,0.1); color: #fff; }
.kiosk-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }

/* Slides */
.kiosk-viewport {
    position: relative;
    height: calc(100vh - var(--top-offset) - var(--footer-height) - 52px - 200px);
    overflow: hidden;
}
.kiosk-slide {
    position: absolute;
    inset: 0;
    padding: 24px;
    opacity: 0;
    transition: opacity 1.5s ease-in-out;
    overflow-y: auto;
}
.kiosk-slide.active { opacity: 1; z-index: 2; }

/* Slide progress bar */
.kiosk-progress {
    position: absolute; bottom: 0; left: 0; right: 0; height: 3px;
    background: rgba(255,255,255,0.05); z-index: 10;
}
.kiosk-progress-bar {
    height: 100%; width: 0%;
    background: linear-gradient(90deg, var(--accent), var(--highlight));
}

/* Slide dots */
.kiosk-dots {
    position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%);
    display: flex; gap: 6px; z-index: 10;
}
.kiosk-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: rgba(255,255,255,0.2); cursor: pointer; transition: all 0.3s;
}
.kiosk-dot.active { background: #fff; width: 24px; border-radius: 4px; }
.kiosk-dot-label {
    position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%);
    font-size: 10px; color: rgba(255,255,255,0.3); text-transform: uppercase;
    letter-spacing: 1px; white-space: nowrap;
}

/* Dark panels */
.k-panel {
    background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.06);
    border-radius: 12px; padding: 20px; position: relative;
}
.k-panel-title {
    font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.2px;
    color: rgba(255,255,255,0.35); margin-bottom: 12px;
}
.k-grid { display: grid; gap: 16px; }
.k-grid-2 { grid-template-columns: 1fr 1fr; }
.k-grid-3 { grid-template-columns: 1fr 1fr 1fr; }
.k-grid-4 { grid-template-columns: repeat(4, 1fr); }

.k-stat { text-align: center; padding: 16px; }
.k-stat-value { font-size: 36px; font-weight: 800; line-height: 1; }
.k-stat-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.8px; color: rgba(255,255,255,0.4); margin-top: 6px; }

.k-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.k-table th { text-align: left; padding: 8px 12px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.8px; color: rgba(255,255,255,0.3); border-bottom: 1px solid rgba(255,255,255,0.06); }
.k-table td { padding: 10px 12px; border-bottom: 1px solid rgba(255,255,255,0.04); color: rgba(255,255,255,0.8); }
.k-table tr:hover td { background: rgba(255,255,255,0.03); }

.k-badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 700; }
.k-badge-red { background: rgba(220,38,38,0.2); color: #FCA5A5; }
.k-badge-orange { background: rgba(255,149,0,0.2); color: #FCD34D; }
.k-badge-green { background: rgba(140,198,63,0.2); color: #BEF264; }
.k-badge-blue { background: rgba(27,108,176,0.2); color: #93C5FD; }

.k-unit { display: inline-block; padding: 2px 7px; background: rgba(27,108,176,0.3); color: #93C5FD; border-radius: 6px; font-size: 10px; font-weight: 700; margin: 1px; }

/* Camera grid */
.k-camera-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.k-camera { border-radius: 8px; overflow: hidden; position: relative; background: rgba(255,255,255,0.03); }
.k-camera img { width: 100%; height: 140px; object-fit: cover; display: block; }
.k-camera-label { position: absolute; bottom: 0; left: 0; right: 0; padding: 4px 8px; background: rgba(0,0,0,0.7); font-size: 10px; color: rgba(255,255,255,0.7); }

/* Fullscreen */
.kiosk-fullscreen .sidebar,
.kiosk-fullscreen .header,
.kiosk-fullscreen .footer { display: none !important; }
.kiosk-fullscreen .main-content { margin: 0 !important; margin-top: 0 !important; }
.kiosk-fullscreen .kiosk { min-height: 100vh; }
.kiosk-fullscreen .kiosk-viewport { height: calc(100vh - 52px - 200px); }
.kiosk-fullscreen .ticker-bar { display: none !important; }

/* Story slide */
.k-story {
    position: relative; height: 100%; border-radius: 12px; overflow: hidden;
    background-size: cover; background-position: center;
}
.k-story::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(0deg, rgba(7,15,27,0.95) 0%, rgba(7,15,27,0.4) 50%, rgba(7,15,27,0.1) 100%);
}
.k-story-content { position: absolute; bottom: 40px; left: 40px; right: 40px; z-index: 2; }
.k-story-title { font-size: 32px; font-weight: 800; line-height: 1.2; max-width: 700px; }
.k-story-sub { font-size: 16px; color: rgba(255,255,255,0.6); margin-top: 8px; max-width: 600px; }

/* ═══ KIOSK CAROUSEL ═══ */
.kiosk-carousel {
    position: relative; width: 100%; height: 200px; overflow: hidden;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.kc-slides { position: relative; width: 100%; height: 100%; }
.kc-slide {
    position: absolute; inset: 0; opacity: 0; transition: opacity 1.5s ease-in-out;
    background-size: cover; background-position: center; cursor: pointer;
}
.kc-slide.active { opacity: 1; z-index: 2; }
.kc-slide.prev { opacity: 0; z-index: 1; }
.kc-slide::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(0deg, rgba(7,15,27,0.92) 0%, rgba(7,15,27,0.5) 40%, rgba(7,15,27,0.1) 80%, rgba(7,15,27,0.05) 100%);
}
.kc-content { position: absolute; bottom: 0; left: 0; right: 0; padding: 16px 28px; z-index: 3; color: #fff; }
.kc-badge {
    display: inline-block; padding: 2px 10px; border-radius: 16px; font-size: 9px;
    font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px; margin-bottom: 6px;
    backdrop-filter: blur(8px);
}
.kc-badge[data-cat="news"] { background: rgba(27,108,176,0.6); }
.kc-badge[data-cat="sports"] { background: rgba(140,198,63,0.6); }
.kc-badge[data-cat="events"] { background: rgba(0,166,160,0.6); }
.kc-badge[data-cat="fire"] { background: rgba(220,38,38,0.6); }
.kc-title { font-size: 18px; font-weight: 800; line-height: 1.25; max-width: 800px; text-shadow: 0 1px 4px rgba(0,0,0,0.4); }
.kc-sub { font-size: 12px; color: rgba(255,255,255,0.5); margin-top: 4px; max-width: 700px; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.kc-time { font-size: 10px; color: rgba(255,255,255,0.3); margin-top: 4px; }
.kc-progress { position: absolute; bottom: 0; left: 0; right: 0; height: 2px; background: rgba(255,255,255,0.08); z-index: 5; }
.kc-progress-bar { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent), var(--highlight)); transition: width 0.3s linear; }
.kc-dots { position: absolute; bottom: 10px; right: 28px; display: flex; gap: 5px; z-index: 5; }
.kc-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,0.25); cursor: pointer; transition: all 0.3s; }
.kc-dot.active { background: #fff; width: 18px; border-radius: 3px; }
.kc-nav {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
    background: rgba(255,255,255,0.08); backdrop-filter: blur(8px); border: 1px solid rgba(255,255,255,0.1);
    color: #fff; width: 30px; height: 30px; border-radius: 50%; font-size: 16px;
    cursor: pointer; display: flex; align-items: center; justify-content: center;
    opacity: 0; transition: opacity 0.3s;
}
.kiosk-carousel:hover .kc-nav { opacity: 1; }
.kc-nav:hover { background: rgba(255,255,255,0.15); }
.kc-prev { left: 10px; }
.kc-next { right: 10px; }

/* ═══ DATA SLIDE HEADER ═══ */
.k-data-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 8px 0; margin-bottom: 12px;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.k-data-header-left { display: flex; align-items: baseline; gap: 12px; }
.k-data-header-title {
    font-size: 13px; font-weight: 700; color: rgba(255,255,255,0.85);
    letter-spacing: 0.3px;
}
.k-data-header-date {
    font-size: 12px; color: rgba(255,255,255,0.4); font-weight: 500;
}
.k-data-header-right { display: flex; align-items: center; gap: 8px; }
.k-data-freshness {
    width: 7px; height: 7px; border-radius: 50%;
}
.k-data-freshness.fresh { background: #00E676; box-shadow: 0 0 6px #00E67680; }
.k-data-freshness.stale { background: #FCD34D; box-shadow: 0 0 6px #FCD34D80; }

/* ═══ 5-DAY SCHEDULE GRID ═══ */
.sched-col {
    flex: 1; padding: 16px 14px; overflow-y: hidden; position: relative;
}
.sched-col-inner {
    transition: transform 0.5s ease-in-out;
}
.sched-col + .sched-col { border-left: 1px solid rgba(255,255,255,0.08); }
.sched-col.today { background: rgba(91,164,217,0.06); }
.sched-day-label {
    font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.8px;
    color: rgba(255,255,255,0.4); margin-bottom: 4px;
}
.sched-day-date { font-size: 20px; font-weight: 800; color: #fff; margin-bottom: 14px; }
.sched-section {
    font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px;
    padding: 6px 0 4px; margin-top: 8px; display: flex; align-items: center; gap: 6px;
}
.sched-section::after { content: ''; flex: 1; height: 1px; background: rgba(255,255,255,0.06); }
.sched-item {
    padding: 6px 0; border-bottom: 1px solid rgba(255,255,255,0.03); font-size: 12px;
}
.sched-item-time { font-size: 10px; font-weight: 600; color: #5BA4D9; }
.sched-item-title { font-weight: 600; color: rgba(255,255,255,0.85); line-height: 1.3; margin-top: 1px; }
.sched-item-sub { font-size: 10px; color: rgba(255,255,255,0.3); margin-top: 1px; }
.sched-council { border-left: 2px solid #00A6A0; padding-left: 6px; margin-left: -6px; }
.sched-saints { border-left: 2px solid #d3bc8d; padding-left: 6px; margin-left: -6px; }
.sched-empty { font-size: 11px; color: rgba(255,255,255,0.2); font-style: italic; padding: 4px 0; }

/* Weather skyline background — swaps day/night via JS class */
.k-weather-bg {
    background: center/cover no-repeat !important;
    overflow: hidden;
}
.k-weather-bg.k-weather-night {
    background-image: url('https://www.jaredweberphotography.com/images/xl/cincinnati-ohio-skyline-at-night.jpg') !important;
}
.k-weather-bg.k-weather-day {
    background-image: url('https://www.travelandleisure.com/thmb/9Sl5ZaA9tp3iZaG30JjAyJApL4I=/750x0/filters:no_upscale():max_bytes(150000):strip_icc():format(webp)/TAL-lead-image-CINCINNATIOH1025-a8633becfd6949ebbb4a139be66db9ef.jpg') !important;
}
.k-weather-bg::before {
    content: ''; position: absolute; inset: 0; border-radius: 12px;
    z-index: 0;
}
.k-weather-bg.k-weather-night::before {
    background: linear-gradient(180deg, rgba(7,15,27,0.7) 0%, rgba(7,15,27,0.65) 50%, rgba(7,15,27,0.8) 100%);
}
.k-weather-bg.k-weather-day::before {
    background: linear-gradient(180deg, rgba(7,15,27,0.75) 0%, rgba(7,15,27,0.7) 50%, rgba(7,15,27,0.82) 100%);
}
.k-weather-bg > * { position: relative; z-index: 1; }
</style>

<div class="kiosk" id="kiosk">
    <!-- Toolbar -->
    <div class="kiosk-toolbar" style="justify-content:space-between;">
        <!-- Logo + Title -->
        <div style="display:flex; align-items:center; gap:10px; flex:1;">
            <img src="assets/img/city-logo.png" alt="" style="height:24px; width:auto; filter:brightness(0) invert(1); opacity:0.7;">
            <h1>Cincinnati Fire Department</h1>
        </div>

        <!-- Weather -->
        <div style="flex:1; display:flex; justify-content:center;">
            <div id="kioskWeatherMini" style="display:flex; align-items:center; gap:5px; font-size:12px; color:rgba(255,255,255,0.5);"></div>
        </div>

        <!-- Shift Badge -->
        <div style="flex:1; display:flex; justify-content:center;">
            <span class="kiosk-shift" style="background:<?= $todayShift['color'] ?>;"><?= $todayShift['unit'] ?></span>
        </div>

        <!-- Date/Time -->
        <div style="flex:1; display:flex; justify-content:center;">
            <div style="display:flex; flex-direction:column; align-items:center; line-height:1.2;">
                <span id="kioskDate" style="font-size:12px; font-weight:600; color:rgba(255,255,255,0.6);"></span>
                <span id="kioskTime" style="font-size:18px; font-weight:300; color:#fff; letter-spacing:1px; font-variant-numeric:tabular-nums;"></span>
            </div>
        </div>

        <!-- River Level -->
        <div style="flex:1; display:flex; justify-content:center;">
            <div style="display:flex; align-items:center; gap:4px; padding:3px 10px; background:rgba(255,255,255,0.06); border-radius:16px; font-size:12px;">
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#5BA4D9" stroke-width="2" style="animation:riverWave 2.5s ease-in-out infinite;"><path d="M2 12c2-2 4-2 6 0s4 2 6 0 4-2 6 0"/><path d="M2 18c2-2 4-2 6 0s4 2 6 0 4-2 6 0"/></svg>
                <span id="kioskRiverVal" style="font-weight:700; color:rgba(255,255,255,0.8);">--</span>
                <span style="font-size:10px; color:rgba(255,255,255,0.3);">ft</span>
            </div>
        </div>

        <!-- Controls -->
        <div style="flex:1; display:flex; justify-content:flex-end; gap:8px;">
            <button class="kiosk-btn" id="kioskPauseBtn" onclick="toggleKioskPause()">
                <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>
                Pause
            </button>
            <button class="kiosk-btn" onclick="kioskFullscreen()">
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>
                Fullscreen
            </button>
        </div>
    </div>

    <!-- Story Carousel (persistent, updates while slides rotate) -->
    <div class="kiosk-carousel" id="kioskCarousel">
        <div class="kc-slides" id="kcSlides">
            <div class="kc-slide active" style="background:#0B2240;">
                <div class="kc-content"><span class="kc-badge">Loading</span><div class="kc-title">Loading stories...</div></div>
            </div>
        </div>
        <div class="kc-progress"><div class="kc-progress-bar" id="kcProgressBar"></div></div>
        <div class="kc-dots" id="kcDots"></div>
        <button class="kc-nav kc-prev" id="kcPrev">&#8249;</button>
        <button class="kc-nav kc-next" id="kcNext">&#8250;</button>
    </div>

    <!-- Viewport -->
    <div class="kiosk-viewport" id="kioskViewport">

        <!-- SLIDE 1: Active Incidents Map -->
        <div class="kiosk-slide active" data-label="Active Incidents">
            <?php $p1=0; foreach($incidents as $i) if(($i['priority']??'')=='1') $p1++; ?>
            <!-- Layer toggles -->
            <div style="position:absolute; bottom:40px; left:24px; z-index:5; display:flex; gap:6px;">
                <button class="kiosk-btn active" id="kBtnDistricts" onclick="toggleKioskLayer('districts',this)">Districts</button>
                <button class="kiosk-btn active" id="kBtnStations" onclick="toggleKioskLayer('stations',this)">Stations</button>
            </div>
            <!-- Full-size map -->
            <div id="kioskIncidentMap" style="position:absolute; inset:0; border-radius:12px; overflow:hidden;"></div>
        </div>

        <!-- SLIDE 2: Weather & Radar -->
        <div class="kiosk-slide" data-label="Weather">
            <div style="display:flex; gap:16px; height:100%; padding:16px; box-sizing:border-box;">
                <div class="k-panel k-weather-bg" id="kioskWeather" style="flex:1; display:flex; flex-direction:column; justify-content:center; align-items:center; min-height:0;">
                    <div style="font-size:14px; color:rgba(255,255,255,0.4); position:relative; z-index:1;">Loading weather...</div>
                </div>
                <div class="k-panel" style="flex:1; padding:0; overflow:hidden; border-radius:12px; min-height:0; position:relative;">
                    <iframe src="https://radar.weather.gov/ridge/standard/KILN_loop.gif" style="width:100%; height:100%; border:0; filter:brightness(0.85);" loading="lazy"
                            onerror="this.src='https://radar.weather.gov/ridge/standard/KILN_0.gif';"></iframe>
                    <div style="position:absolute; bottom:8px; left:12px; font-size:10px; color:rgba(255,255,255,0.3);">NWS Cincinnati Radar — KILN</div>
                </div>
            </div>
        </div>

        <!-- SLIDE 3: Live Operations Today (Active911) -->
        <div class="kiosk-slide" data-label="Live Ops">
            <div class="k-data-header">
                <div class="k-data-header-left">
                    <span class="k-data-freshness fresh" style="animation:trafficPulse 2s ease-in-out infinite;"></span>
                    <span class="k-data-header-title">Live Operations</span>
                    <span class="k-data-header-date" id="kioskLiveDate">Today</span>
                </div>
                <div class="k-data-header-right">
                    <span style="color:rgba(255,255,255,0.4); font-size:11px;" id="kioskLiveUpdated">Loading...</span>
                    <span style="color:rgba(255,255,255,0.15);">|</span>
                    <span style="color:rgba(255,255,255,0.3); font-size:10px;">Source: Active911 (real-time)</span>
                </div>
            </div>
            <div class="k-grid k-grid-4" style="margin-bottom:16px;">
                <div class="k-panel k-stat"><div class="k-stat-value" id="klRunsToday" style="color:#5BA4D9;">--</div><div class="k-stat-label">This Shift</div></div>
                <div class="k-panel k-stat"><div class="k-stat-value" id="klStructCount" style="color:#FCA5A5;">--</div><div class="k-stat-label">Structure Fires</div></div>
                <div class="k-panel k-stat"><div class="k-stat-value" id="klAlarms" style="color:#FCD34D;">--</div><div class="k-stat-label">Fire Alarms</div></div>
                <div class="k-panel k-stat"><div class="k-stat-value" id="klYesterday" style="color:rgba(255,255,255,0.5);">--</div><div class="k-stat-label">Yesterday</div></div>
            </div>
            <div class="k-grid k-grid-2" style="margin-bottom:16px;">
                <div class="k-panel"><div class="k-panel-title">Hourly Volume — This Shift</div><div id="kioskLiveHourly" style="height:200px;"></div></div>
                <div class="k-panel"><div class="k-panel-title">Top Call Types — This Shift</div><div id="kioskLiveTypes" style="height:200px;"></div></div>
            </div>
            <div class="k-panel" style="padding:10px 20px;">
                <div style="display:flex; justify-content:space-around; align-items:center; gap:16px;">
                    <div style="text-align:center;">
                        <div style="font-size:22px; font-weight:800; color:#5BA4D9;" id="klYtdTotal">--</div>
                        <div style="font-size:9px; color:rgba(255,255,255,0.4); font-weight:600; text-transform:uppercase; letter-spacing:0.5px;">Total Runs</div>
                    </div>
                    <span style="color:rgba(255,255,255,0.08); font-size:24px;">|</span>
                    <div style="text-align:center;">
                        <div style="font-size:22px; font-weight:800; color:#FCA5A5;" id="klYtdStruct">--</div>
                        <div style="font-size:9px; color:rgba(255,255,255,0.4); font-weight:600; text-transform:uppercase; letter-spacing:0.5px;">Structure Fires</div>
                    </div>
                    <span style="color:rgba(255,255,255,0.08); font-size:24px;">|</span>
                    <div style="text-align:center;">
                        <div style="font-size:22px; font-weight:800; color:#FCD34D;" id="klYtdAlarms">--</div>
                        <div style="font-size:9px; color:rgba(255,255,255,0.4); font-weight:600; text-transform:uppercase; letter-spacing:0.5px;">Fire Alarms</div>
                    </div>
                    <span style="color:rgba(255,255,255,0.08); font-size:24px;">|</span>
                    <div style="text-align:center;">
                        <div style="font-size:10px; color:rgba(255,255,255,0.3);" id="klYtdSince">Since --</div>
                        <div style="font-size:9px; color:rgba(255,255,255,0.4); font-weight:600; text-transform:uppercase; letter-spacing:0.5px;">YTD Tracking</div>
                    </div>
                </div>
            </div>
        </div>

        <!-- SLIDE 4: Fire Summary -->
        <div class="kiosk-slide" data-label="Fire">
            <?php if ($fireSummary):
                $fireDate = date('l, F j, Y', strtotime($fireSummary['report_date']));
                $fireSync = $fireSummary['updated_at'] ?? $fireSummary['created_at'] ?? '';
                $fireSyncAgo = $fireSync ? round((time() - strtotime($fireSync)) / 3600) : null;
                $fireFresh = $fireSyncAgo !== null && $fireSyncAgo < 24;
            ?>
            <div class="k-data-header">
                <div class="k-data-header-left">
                    <span class="k-data-header-title">Yesterday's Fire Briefing</span>
                    <span class="k-data-header-date"><?= $fireDate ?></span>
                </div>
                <div class="k-data-header-right">
                    <span class="k-data-freshness <?= $fireFresh ? 'fresh' : 'stale' ?>"></span>
                    <span style="color:rgba(255,255,255,0.4); font-size:11px;">
                        Synced <?= $fireSyncAgo !== null ? ($fireSyncAgo < 1 ? 'just now' : $fireSyncAgo . 'h ago') : 'unknown' ?>
                    </span>
                    <span style="color:rgba(255,255,255,0.15);">|</span>
                    <span style="color:rgba(255,255,255,0.3); font-size:10px;">Source: ESO / Snowflake</span>
                </div>
            </div>
            <div class="k-grid k-grid-4" style="margin-bottom:16px;">
                <div class="k-panel k-stat"><div class="k-stat-value" style="color:#5BA4D9;"><?= $fireSummary['total_incidents'] ?? 0 ?></div><div class="k-stat-label">Total Incidents</div></div>
                <div class="k-panel k-stat"><div class="k-stat-value" style="color:#FCA5A5;"><?= ($fireSummary['structure_fires']??0)+($fireSummary['vehicle_fires']??0) ?></div><div class="k-stat-label">Fires</div></div>
                <div class="k-panel k-stat"><div class="k-stat-value" style="color:#FCD34D;"><?= $fireSummary['false_alarms'] ?? 0 ?></div><div class="k-stat-label">False Alarms</div></div>
                <div class="k-panel k-stat"><div class="k-stat-value" style="color:#FCA5A5; font-size:20px;">$<?= number_format(($fireSummary['total_property_loss']??0)+($fireSummary['total_content_loss']??0)) ?></div><div class="k-stat-label">Property Loss</div></div>
            </div>
            <?php
            $fireTurnout = json_decode($fireSummary['apparatus_turnout_json'] ?? '{}', true) ?: [];
            ksort($fireTurnout);
            if (!empty($fireTurnout)):
            ?>
            <div class="k-panel" style="margin-bottom:16px; padding:12px 16px;">
                <div class="k-panel-title">Engine / Truck / Hazmat Turnout Times (seconds)</div>
                <div id="kioskFireGauges" style="display:flex; gap:4px; justify-content:center; flex-wrap:nowrap; overflow-x:auto;"></div>
            </div>
            <?php endif; ?>
            <div class="k-grid k-grid-2">
                <div class="k-panel"><div class="k-panel-title">Incident Types</div><div id="kioskFireTypes" style="height:180px;"></div></div>
                <div class="k-panel"><div class="k-panel-title">Apparatus Activity</div><div id="kioskFireApparatus" style="height:180px;"></div></div>
            </div>
            <?php else: ?>
            <div style="display:flex; align-items:center; justify-content:center; height:100%; color:rgba(255,255,255,0.3);">Fire data not available — run Snowflake sync</div>
            <?php endif; ?>
        </div>

        <!-- SLIDE 5: Live Traffic Map -->
        <div class="kiosk-slide" data-label="Traffic Map">
            <div id="kioskTrafficMap" style="position:absolute;inset:0;"></div>
            <div class="k-traffic-header">
                <div style="display:flex;align-items:center;gap:8px;">
                    <div style="width:8px;height:8px;background:#00E676;border-radius:50%;animation:trafficPulse 2s ease-in-out infinite;"></div>
                    <span style="font-size:13px;font-weight:700;letter-spacing:0.5px;">LIVE TRAFFIC</span>
                    <span style="color:rgba(255,255,255,0.4);font-size:12px;">Cincinnati Metro</span>
                </div>
                <div id="kioskTrafficTime" style="font-size:11px;color:rgba(255,255,255,0.4);"></div>
            </div>
            <div class="k-traffic-legend" id="kioskTrafficLegend">
                <div style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.8px;color:rgba(255,255,255,0.5);margin-bottom:8px;">Traffic Flow</div>
                <div class="k-tl-row"><span class="k-tl-line" style="background:#00E676;"></span> Free Flow</div>
                <div class="k-tl-row"><span class="k-tl-line" style="background:#FFEB3B;"></span> Light</div>
                <div class="k-tl-row"><span class="k-tl-line" style="background:#FF9800;"></span> Moderate</div>
                <div class="k-tl-row"><span class="k-tl-line" style="background:#F44336;"></span> Heavy</div>
                <div class="k-tl-row"><span class="k-tl-line" style="background:#880E4F;"></span> Stopped</div>
                <div style="border-top:1px solid rgba(255,255,255,0.08);margin:8px 0;"></div>
                <div class="k-tl-row"><span class="k-tl-dot" style="background:#F44336;"></span> <span id="klAccidents">0</span> Accidents</div>
                <div class="k-tl-row"><span class="k-tl-dot" style="background:#FF9800;"></span> <span id="klClosures">0</span> Closures</div>
                <div class="k-tl-row"><span class="k-tl-dot" style="background:#FFC107;"></span> <span id="klConstruction">0</span> Construction</div>
            </div>
        </div>

        <!-- SLIDE 6: Traffic Cameras -->
        <div class="kiosk-slide" data-label="Cameras">
            <div class="k-panel-title" style="margin-bottom:12px;">Live Traffic Cameras — Cincinnati</div>
            <div class="k-camera-grid" id="kioskCameras">
                <div style="grid-column:1/-1; text-align:center; padding:40px; color:rgba(255,255,255,0.3);">Loading cameras...</div>
            </div>
        </div>

        <!-- SLIDE 6: News/Sports -->
        <div class="kiosk-slide" data-label="News">
            <div id="kioskStory" class="k-story" style="background-color:#0B2240;">
                <div class="k-story-content">
                    <div class="k-badge k-badge-blue" id="kioskStorySource" style="margin-bottom:12px;">Loading</div>
                    <h2 class="k-story-title" id="kioskStoryTitle">Loading stories...</h2>
                    <p class="k-story-sub" id="kioskStorySub"></p>
                </div>
            </div>
        </div>

        <!-- SLIDE 7: 5-Day Schedule Grid -->
        <div class="kiosk-slide" data-label="Schedule">
            <div id="kioskScheduleGrid" style="display:flex;height:100%;gap:0;color:rgba(255,255,255,0.5);">Loading 5-day schedule...</div>
        </div>

    </div>

    <!-- Progress + Dots -->
    <div class="kiosk-progress"><div class="kiosk-progress-bar" id="kioskProgressBar"></div></div>
    <div class="kiosk-dots" id="kioskDots"></div>
    <div class="kiosk-dot-label" id="kioskSlideLabel"></div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
    const SLIDE_DURATION = 15000;
    const slides = document.querySelectorAll('.kiosk-slide');
    const dotsContainer = document.getElementById('kioskDots');
    const progressBar = document.getElementById('kioskProgressBar');
    const slideLabel = document.getElementById('kioskSlideLabel');
    let current = 0;
    let paused = false;
    let timer = null;

    // Build dots
    slides.forEach((s, i) => {
        const dot = document.createElement('div');
        dot.className = 'kiosk-dot' + (i === 0 ? ' active' : '');
        dot.onclick = () => goTo(i);
        dotsContainer.appendChild(dot);
    });
    slideLabel.textContent = slides[0]?.dataset.label || '';

    function goTo(idx) {
        slides[current]?.classList.remove('active');
        dotsContainer.children[current]?.classList.remove('active');
        current = idx;
        slides[current]?.classList.add('active');
        dotsContainer.children[current]?.classList.add('active');
        slideLabel.textContent = slides[current]?.dataset.label || '';
        resetProgress();
        onSlideEnter(current);
    }

    function next() { goTo((current + 1) % slides.length); }

    function resetProgress() {
        progressBar.style.transition = 'none';
        progressBar.style.width = '0%';
        requestAnimationFrame(() => requestAnimationFrame(() => {
            progressBar.style.transition = `width ${SLIDE_DURATION}ms linear`;
            progressBar.style.width = '100%';
        }));
    }

    function start() {
        resetProgress();
        timer = setInterval(() => { if (!paused) next(); }, SLIDE_DURATION);
    }

    window.toggleKioskPause = function() {
        paused = !paused;
        const btn = document.getElementById('kioskPauseBtn');
        btn.innerHTML = paused
            ? '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21"/></svg> Play'
            : '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg> Pause';
        btn.classList.toggle('active', paused);
    };

    window.kioskFullscreen = function() {
        if (!document.fullscreenElement) {
            document.documentElement.requestFullscreen();
            document.body.classList.add('kiosk-fullscreen');
        } else {
            document.exitFullscreen();
            document.body.classList.remove('kiosk-fullscreen');
        }
    };
    document.addEventListener('fullscreenchange', () => {
        if (!document.fullscreenElement) document.body.classList.remove('kiosk-fullscreen');
    });

    // Clock + Date
    function updateKioskClock() {
        const now = new Date();
        const dateEl = document.getElementById('kioskDate');
        const timeEl = document.getElementById('kioskTime');
        if (dateEl) dateEl.textContent = now.toLocaleDateString('en-US', {weekday:'long', month:'long', day:'numeric', year:'numeric'});
        if (timeEl) timeEl.textContent = now.toLocaleTimeString('en-US', {hour:'numeric',minute:'2-digit',second:'2-digit'});
    }
    updateKioskClock();
    setInterval(updateKioskClock, 1000);

    // ─── Live Operations (Active911) ─────────────────────
    let liveHourlyChart = null, liveTypesChart = null;
    let liveOpsTimer = null;

    async function loadKioskLiveOps() {
        const data = await window.portalAPI('incidents.php?action=today_stats');
        if (!data || data.error) return;

        // Update header with shift info
        const shiftLabel = data.shift ? `${data.shift.unit} · ${data.shift.name}` : 'Today';
        const shiftTime = data.shift_start ? new Date(data.shift_start.replace(' ','T')).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit'}) + ' – ' + new Date(data.shift_end.replace(' ','T')).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit'}) : '';
        document.getElementById('kioskLiveDate').innerHTML = `${data.date || 'Today'} <span style="color:${data.shift?.color || '#fff'};font-weight:700;margin-left:8px;">${shiftLabel}</span> <span style="color:rgba(255,255,255,0.3);font-size:10px;margin-left:4px;">${shiftTime}</span>`;
        document.getElementById('kioskLiveUpdated').textContent = 'Updated ' + new Date().toLocaleTimeString('en-US', {hour:'numeric', minute:'2-digit'});

        // Stat cards
        document.getElementById('klRunsToday').textContent = data.today || 0;
        document.getElementById('klStructCount').textContent = data.types?.['STRUCT'] || 0;
        const alarmCount = (data.types?.['FALARM'] || 0) + (data.types?.['CALARM'] || 0);
        document.getElementById('klAlarms').textContent = alarmCount;
        const prevLabel = data.prev_shift ? data.prev_shift.unit : 'Prev';
        const yEl = document.getElementById('klYesterday');
        yEl.textContent = data.yesterday || 0;
        yEl.closest('.k-stat').querySelector('.k-stat-label').textContent = prevLabel + ' Shift';

        // YTD
        document.getElementById('klYtdTotal').textContent = (data.ytd_total || 0).toLocaleString();
        document.getElementById('klYtdStruct').textContent = data.ytd_struct || 0;
        document.getElementById('klYtdAlarms').textContent = data.ytd_alarms || 0;
        const since = data.ytd_since ? new Date(data.ytd_since.replace(' ','T')).toLocaleDateString('en-US', {month:'short', day:'numeric'}) : '--';
        document.getElementById('klYtdSince').textContent = 'Since ' + since;

        // Hourly chart
        if (!liveHourlyChart) liveHourlyChart = initDarkChart('kioskLiveHourly');
        if (liveHourlyChart) {
            const hourLabels = Array.from({length:24},(_,i)=>i===0?'12a':i<12?i+'a':i===12?'12p':(i-12)+'p');
            const currentHour = new Date().getHours();
            liveHourlyChart.setOption({
                grid:{top:8,right:8,bottom:24,left:30}, backgroundColor:'transparent',
                xAxis:{type:'category', data:hourLabels, axisLabel:{color:'#555',fontSize:9}, axisLine:{show:false}, axisTick:{show:false}},
                yAxis:{type:'value', axisLabel:{color:'#555',fontSize:9}, splitLine:{lineStyle:{color:'rgba(255,255,255,0.03)'}}, axisLine:{show:false}},
                series:[{
                    type:'bar', data: data.hourly.map((v,i) => ({
                        value: v,
                        itemStyle: { color: i === currentHour ? '#5BA4D9' : (i < currentHour ? 'rgba(91,164,217,0.4)' : 'rgba(255,255,255,0.06)'), borderRadius: [3,3,0,0] }
                    })),
                    barWidth: '60%',
                    animationDuration: 1500,
                }]
            });
        }

        // Call types chart
        if (!liveTypesChart) liveTypesChart = initDarkChart('kioskLiveTypes');
        if (liveTypesChart) {
            const typeEntries = Object.entries(data.types || {}).slice(0, 10);
            const typeNames = typeEntries.map(t => t[0]).reverse();
            const typeVals = typeEntries.map(t => t[1]).reverse();
            const typeColors = typeNames.map(n => {
                const nl = n.toLowerCase();
                if (nl.includes('struct')) return '#FCA5A5';
                if (nl.includes('falarm') || nl.includes('calarm')) return '#FCD34D';
                if (nl.includes('ems') || nl.includes('sick') || nl.includes('breath') || nl.includes('faint')) return '#5BA4D9';
                if (nl.includes('acci')) return '#FF9800';
                return '#8CC63F';
            });
            liveTypesChart.setOption({
                grid:{top:4,right:36,bottom:4,left:8,containLabel:true}, backgroundColor:'transparent',
                xAxis:{type:'value',show:false},
                yAxis:{type:'category',data:typeNames,axisLabel:{color:'#888',fontSize:10},axisLine:{show:false},axisTick:{show:false}},
                series:[{type:'bar',data:typeVals.map((v,i)=>({value:v,itemStyle:{color:typeColors[i],borderRadius:[0,4,4,0]}})),barWidth:14,label:{show:true,position:'right',color:'#888',fontSize:10},animationDuration:1500}]
            });
        }

        // Auto-refresh every 60s
        if (liveOpsTimer) clearTimeout(liveOpsTimer);
        liveOpsTimer = setTimeout(loadKioskLiveOps, 60000);
    }

    // Weather mini (header)
    async function loadKioskWeatherMini() {
        const el = document.getElementById('kioskWeatherMini');
        if (!el) return;
        const data = await window.portalAPI('weather.php');
        if (!data || data.error) { el.innerHTML = '<span style="color:rgba(255,255,255,0.3);">--</span>'; return; }
        el.innerHTML = `<img src="https://openweathermap.org/img/wn/${data.icon}.png" width="24" height="24" style="margin:-4px 0;">
            <span style="font-weight:700; color:rgba(255,255,255,0.85); font-size:14px;">${Math.round(data.temp)}&deg;</span>
            <span style="color:rgba(255,255,255,0.4); font-size:12px;">${data.conditions}</span>`;
    }
    loadKioskWeatherMini();

    // River level (header)
    async function loadKioskRiver() {
        const el = document.getElementById('kioskRiverVal');
        if (!el) return;
        const data = await window.portalAPI('river.php');
        if (data && !data.error) el.textContent = data.level.toFixed(1);
    }
    loadKioskRiver();

    // ─── Persistent Story Carousel ───────────────────────
    (async function initKioskCarousel() {
        const kcSlides = document.getElementById('kcSlides');
        const kcDots = document.getElementById('kcDots');
        const kcProgress = document.getElementById('kcProgressBar');
        const KC_DURATION = 8000;
        let kcData = [], kcCurrent = 0, kcPaused = false, kcTimer = null;

        const data = await window.portalAPI('stories.php');
        if (!data || !data.stories || !data.stories.length) return;
        kcData = data.stories;

        function kcTimeAgo(d) {
            if (!d) return '';
            const s = Math.floor((Date.now() - new Date(d).getTime()) / 1000);
            if (s < 3600) return Math.floor(s/60) + 'm ago';
            if (s < 86400) return Math.floor(s/3600) + 'h ago';
            return Math.floor(s/86400) + 'd ago';
        }

        function kcRender() {
            kcSlides.innerHTML = kcData.map((s, i) => `
                <div class="kc-slide ${i===0?'active':''}" style="background-image:url('${s.image}')" onclick="if('${s.url}')window.open('${s.url}','_blank')">
                    <div class="kc-content">
                        <span class="kc-badge" data-cat="${s.category}">${s.source||''}</span>
                        <div class="kc-title">${s.title||''}</div>
                        ${s.subtitle?`<div class="kc-sub">${s.subtitle}</div>`:''}
                        ${s.time?`<div class="kc-time">${kcTimeAgo(s.time)}</div>`:''}
                    </div>
                </div>`).join('');
            kcDots.innerHTML = kcData.map((_, i) =>
                `<div class="kc-dot ${i===0?'active':''}" data-i="${i}"></div>`).join('');
            kcDots.querySelectorAll('.kc-dot').forEach(d => d.addEventListener('click', () => kcGo(parseInt(d.dataset.i))));
        }

        function kcGo(idx) {
            if (idx === kcCurrent) return;
            const slides = kcSlides.querySelectorAll('.kc-slide');
            const dots = kcDots.querySelectorAll('.kc-dot');
            if (slides[kcCurrent]) { slides[kcCurrent].classList.remove('active'); slides[kcCurrent].classList.add('prev'); }
            if (dots[kcCurrent]) dots[kcCurrent].classList.remove('active');
            kcCurrent = idx;
            if (slides[kcCurrent]) { slides[kcCurrent].classList.add('active'); slides[kcCurrent].classList.remove('prev'); }
            if (dots[kcCurrent]) dots[kcCurrent].classList.add('active');
            setTimeout(() => kcSlides.querySelectorAll('.prev').forEach(s => s.classList.remove('prev')), 1800);
            kcResetProgress();
        }

        function kcResetProgress() {
            kcProgress.style.transition = 'none';
            kcProgress.style.width = '0%';
            requestAnimationFrame(() => requestAnimationFrame(() => {
                kcProgress.style.transition = `width ${KC_DURATION}ms linear`;
                kcProgress.style.width = '100%';
            }));
        }

        kcRender();
        kcResetProgress();
        kcTimer = setInterval(() => { if (!kcPaused) kcGo((kcCurrent + 1) % kcData.length); }, KC_DURATION);

        const carousel = document.getElementById('kioskCarousel');
        carousel.addEventListener('mouseenter', () => kcPaused = true);
        carousel.addEventListener('mouseleave', () => kcPaused = false);
        document.getElementById('kcNext').addEventListener('click', e => { e.stopPropagation(); kcGo((kcCurrent+1)%kcData.length); });
        document.getElementById('kcPrev').addEventListener('click', e => { e.stopPropagation(); kcGo((kcCurrent-1+kcData.length)%kcData.length); });

        // Refresh stories every 30 min
        setInterval(async () => {
            const fresh = await window.portalAPI('stories.php');
            if (fresh && fresh.stories && fresh.stories.length) { kcData = fresh.stories; kcRender(); }
        }, 1800000);
    })();

    // ─── Slide data loaders ─────────────────────────────
    let storiesData = [], storyIdx = 0;

    function onSlideEnter(idx) {
        if (idx === 0) loadKioskMap();
        if (idx === 1) loadKioskWeather();
        if (idx === 2) loadKioskLiveOps();
        if (idx === 4) loadKioskTrafficMap();
        if (idx === 5) loadKioskCameras();
        if (idx === 6) showNextStory();
        if (idx === 7) loadKioskCalendar();
    }

    // Incident Map
    let kioskMap = null;
    let kioskLayers = {};
    function loadKioskMap() {
        if (kioskMap) return; // already loaded
        const mKey = window.CFD_PORTAL.mapsKey;
        if (!mKey) return;

        if (!window.google || !google.maps) {
            const s = document.createElement('script');
            s.src = `https://maps.googleapis.com/maps/api/js?key=${mKey}&callback=_initKioskMap`;
            s.async = true;
            window._initKioskMap = function() { loadKioskMap(); };
            document.head.appendChild(s);
            return;
        }

        const mapEl = document.getElementById('kioskIncidentMap');
        kioskMap = new google.maps.Map(mapEl, {
            center: { lat: 39.10, lng: -84.5120 },
            zoom: 11,
            mapTypeId: 'hybrid',
            disableDefaultUI: true,
            zoomControl: true,
            styles: [
                { featureType: 'poi', stylers: [{ visibility: 'off' }] },
                { featureType: 'transit', stylers: [{ visibility: 'off' }] }
            ]
        });

        // KMZ layers
        const baseUrl = window.location.origin;
        kioskLayers.districts = new google.maps.KmlLayer({
            url: baseUrl + '/assets/data/CFD_Districts.kmz',
            map: kioskMap, preserveViewport: true, suppressInfoWindows: true
        });
        kioskLayers.stations = new google.maps.KmlLayer({
            url: baseUrl + '/assets/data/CFD_Stations.kmz',
            map: kioskMap, preserveViewport: true, suppressInfoWindows: false
        });

        // Incident markers
        const incidents = <?= json_encode(array_map(fn($i) => [
            'lat' => (float)($i['latitude'] ?? 0),
            'lng' => (float)($i['longitude'] ?? 0),
            'type' => $i['incident_type'] ?? '',
            'addr' => $i['address'] ?? '',
            'units' => $i['units_assigned'] ?? '',
            'priority' => $i['priority'] ?? '3',
            'time' => date('g:i A', strtotime($i['received_at'])),
        ], $incidents)) ?>;

        incidents.forEach(inc => {
            if (!inc.lat || !inc.lng || (inc.lat === 0 && inc.lng === 0)) return;
            const color = inc.priority === '1' ? '#FF3B30' : (inc.priority === '2' ? '#FF9500' : '#8CC63F');
            const marker = new google.maps.Marker({
                position: { lat: inc.lat, lng: inc.lng },
                map: kioskMap,
                icon: {
                    path: 'M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5S10.62 6.5 12 6.5s2.5 1.12 2.5 2.5S13.38 11.5 12 11.5z',
                    scale: 1.2, fillColor: color, fillOpacity: 0.95,
                    strokeWeight: 1, strokeColor: '#fff',
                    anchor: new google.maps.Point(12, 22),
                },
                title: inc.type
            });
            const iw = new google.maps.InfoWindow({
                content: `<div style="font-family:-apple-system,system-ui,sans-serif;padding:4px;max-width:250px;">
                    <strong style="font-size:13px;">${inc.type}</strong><br>
                    <span style="font-size:12px;color:#666;">${inc.addr}</span><br>
                    <span style="font-size:11px;color:#999;">Units: ${inc.units} &middot; ${inc.time}</span>
                </div>`
            });
            marker.addListener('click', () => iw.open(kioskMap, marker));
        });
    }

    window.toggleKioskLayer = function(name, btn) {
        const layer = kioskLayers[name];
        if (!layer) return;
        if (btn.classList.contains('active')) {
            layer.setMap(null); btn.classList.remove('active');
        } else {
            layer.setMap(kioskMap); btn.classList.add('active');
        }
    };

    // Weather
    async function loadKioskWeather() {
        const el = document.getElementById('kioskWeather');
        const data = await window.portalAPI('weather.php?action=forecast');
        const cur = await window.portalAPI('weather.php');
        if (!cur || !data) { el.innerHTML = '<div style="color:rgba(255,255,255,0.3);">Weather unavailable</div>'; return; }

        const sunrise = new Date(cur.sunrise*1000).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit'});
        const sunset = new Date(cur.sunset*1000).toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit'});

        // Day/night skyline swap
        const nowTs = Math.floor(Date.now() / 1000);
        const isDay = cur.sunrise && cur.sunset && nowTs >= cur.sunrise && nowTs < cur.sunset;
        el.classList.remove('k-weather-day', 'k-weather-night');
        el.classList.add(isDay ? 'k-weather-day' : 'k-weather-night');

        el.innerHTML = `
            <div style="text-align:center; margin-bottom:20px; position:relative; z-index:1;">
                <div style="font-size:64px; font-weight:800; line-height:1; text-shadow:0 2px 16px rgba(0,0,0,0.6);">${Math.round(cur.temp)}&deg;</div>
                <div style="font-size:18px; color:rgba(255,255,255,0.85); text-transform:capitalize; text-shadow:0 1px 4px rgba(0,0,0,0.4); margin-top:4px;">${cur.conditions}</div>
            </div>
            <div style="display:grid; grid-template-columns:repeat(3,1fr); gap:8px; text-align:center; position:relative; z-index:1;">
                <div><div style="font-size:10px; color:rgba(255,255,255,0.5); font-weight:600; letter-spacing:0.5px;">FEELS LIKE</div><div style="font-weight:700; text-shadow:0 1px 4px rgba(0,0,0,0.3);">${Math.round(cur.feels_like)}&deg;</div></div>
                <div><div style="font-size:10px; color:rgba(255,255,255,0.5); font-weight:600; letter-spacing:0.5px;">WIND</div><div style="font-weight:700; text-shadow:0 1px 4px rgba(0,0,0,0.3);">${Math.round(cur.wind_speed)} mph</div></div>
                <div><div style="font-size:10px; color:rgba(255,255,255,0.5); font-weight:600; letter-spacing:0.5px;">HUMIDITY</div><div style="font-weight:700; text-shadow:0 1px 4px rgba(0,0,0,0.3);">${cur.humidity}%</div></div>
            </div>
            <div style="margin-top:20px; display:flex; gap:8px; flex-wrap:wrap; justify-content:center; position:relative; z-index:1;">
                ${(data.forecast||[]).slice(0,5).map((d,i) => `
                    <div style="text-align:center; padding:8px 12px; background:rgba(255,255,255,0.1); backdrop-filter:blur(4px); border-radius:8px; min-width:60px; border:1px solid rgba(255,255,255,0.08);">
                        <div style="font-size:11px; color:rgba(255,255,255,0.7); font-weight:600;">${i===0?'Today':d.day_name}</div>
                        <img src="https://openweathermap.org/img/wn/${d.icon}.png" width="32" height="32">
                        <div style="font-size:13px; font-weight:700;">${d.high}&deg;</div>
                        <div style="font-size:11px; color:rgba(255,255,255,0.5);">${d.low}&deg;</div>
                    </div>
                `).join('')}
            </div>
        `;
    }

    // ─── Live Traffic Map (Mapbox + HERE + OHGO) ───────────
    let trafficMap = null;
    let trafficOrbitTimer = null;

    async function loadKioskTrafficMap() {
        const container = document.getElementById('kioskTrafficMap');
        if (!container) return;

        // Load Mapbox if needed
        if (!window.mapboxgl) {
            if (!document.querySelector('link[href*="mapbox-gl"]')) {
                const link = document.createElement('link');
                link.rel = 'stylesheet';
                link.href = 'https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.css';
                document.head.appendChild(link);
            }
            if (!document.querySelector('script[src*="mapbox-gl"]')) {
                await new Promise(resolve => {
                    const s = document.createElement('script');
                    s.src = 'https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.js';
                    s.onload = resolve;
                    document.head.appendChild(s);
                });
            }
        }

        if (trafficMap) {
            refreshTrafficData();
            trafficMap.resize();
            return;
        }

        // Wait for slide to be visible before initializing Mapbox
        await new Promise(r => setTimeout(r, 1500));

        mapboxgl.accessToken = 'pk.eyJ1IjoiYm9iYnlodWciLCJhIjoiY21lZWp6eG1oMG1udDJpcTVxb2twMTVhNSJ9.5EW_XCxmcZt5VaPfAd0Kjg';
        container.style.cssText = 'position:absolute;inset:0;';

        try {
            trafficMap = new mapboxgl.Map({
                container: container,
                style: 'mapbox://styles/mapbox/navigation-night-v1',
                center: [-84.510, 39.097],
                zoom: 13,
                pitch: 45,
                bearing: 0,
                interactive: false,
            });

            trafficMap.on('load', function() {
                // Built-in Mapbox traffic layer
                trafficMap.addSource('mapbox-traffic', {
                    type: 'vector',
                    url: 'mapbox://mapbox.mapbox-traffic-v1'
                });
                trafficMap.addLayer({
                    id: 'traffic-flow',
                    type: 'line',
                    source: 'mapbox-traffic',
                    'source-layer': 'traffic',
                    paint: {
                        'line-color': [
                            'match', ['get', 'congestion'],
                            'low', '#00E676',
                            'moderate', '#FFEB3B',
                            'heavy', '#FF9800',
                            'severe', '#F44336',
                            '#00E676'
                        ],
                        'line-width': ['interpolate', ['linear'], ['zoom'], 8, 1, 14, 4],
                        'line-opacity': 0.8,
                    }
                });

                // Load HERE flow + incidents
                refreshTrafficData();
            });

            trafficMap.on('error', function() {
                container.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:rgba(255,255,255,0.3);">Traffic map unavailable</div>';
            });
        } catch(e) {
            container.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:rgba(255,255,255,0.3);">WebGL required for traffic map</div>';
        }
    }

    async function refreshTrafficData() {
        if (!trafficMap) return;
        const data = await window.portalAPI('traffic.php');
        if (!data) return;

        // Update timestamp
        const timeEl = document.getElementById('kioskTrafficTime');
        if (timeEl) timeEl.textContent = 'Updated ' + new Date().toLocaleTimeString('en-US', {hour:'numeric', minute:'2-digit'});

        // Update legend counts
        const c = data.counts || {};
        const lAcc = document.getElementById('klAccidents');
        const lClo = document.getElementById('klClosures');
        const lCon = document.getElementById('klConstruction');
        if (lAcc) lAcc.textContent = c.accident || 0;
        if (lClo) lClo.textContent = c.roadClosure || 0;
        if (lCon) lCon.textContent = c.construction || 0;

        // Draw HERE flow lines
        if (data.flow && data.flow.features && data.flow.features.length) {
            // Color-code by jamFactor
            data.flow.features.forEach(f => {
                const jf = f.properties.jamFactor || 0;
                f.properties.color = jf < 2 ? '#00E676' : jf < 4 ? '#FFEB3B' : jf < 6 ? '#FF9800' : jf < 8 ? '#F44336' : '#880E4F';
                f.properties.width = jf < 2 ? 2 : jf < 6 ? 3 : 4;
            });

            if (trafficMap.getSource('here-flow')) {
                trafficMap.getSource('here-flow').setData(data.flow);
            } else {
                trafficMap.addSource('here-flow', { type: 'geojson', data: data.flow });
                trafficMap.addLayer({
                    id: 'here-flow-glow',
                    type: 'line',
                    source: 'here-flow',
                    paint: {
                        'line-color': ['get', 'color'],
                        'line-width': ['get', 'width'],
                        'line-blur': 4,
                        'line-opacity': 0.4,
                    }
                });
                trafficMap.addLayer({
                    id: 'here-flow-line',
                    type: 'line',
                    source: 'here-flow',
                    paint: {
                        'line-color': ['get', 'color'],
                        'line-width': ['get', 'width'],
                        'line-opacity': 0.85,
                    }
                });
            }
        }

        // Clear old incident markers
        document.querySelectorAll('.traffic-marker').forEach(m => m.remove());

        // Add incident markers
        (data.incidents || []).forEach(inc => {
            if (!inc.lat || !inc.lng) return;
            const t = inc.type || 'other';
            const isAccident = t === 'accident' || t === 'congestion';
            const isClosure = t === 'roadClosure' || t === 'roadClosed';
            const isConstruction = t === 'construction';

            const color = isAccident ? '#F44336' : isClosure ? '#FF9800' : isConstruction ? '#FFC107' : '#9E9E9E';
            const icon = isAccident ? '!' : isClosure ? '✕' : isConstruction ? '▲' : '•';
            const size = isAccident ? 24 : 18;

            const el = document.createElement('div');
            el.className = 'traffic-marker';
            el.style.cssText = `width:${size}px;height:${size}px;background:${color};border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:${size*0.5}px;font-weight:900;color:#fff;border:2px solid rgba(255,255,255,0.3);cursor:pointer;box-shadow:0 0 12px ${color}80;`;
            if (isAccident) el.style.animation = 'trafficPulse 1.5s ease-in-out infinite';
            el.textContent = icon;
            el.title = (inc.description || '').substring(0, 100);

            new mapboxgl.Marker({ element: el })
                .setLngLat([inc.lng, inc.lat])
                .setPopup(new mapboxgl.Popup({ offset: 15, closeButton: false })
                    .setHTML(`<div style="font-size:12px;max-width:200px;"><strong>${t.replace(/([A-Z])/g,' $1').trim()}</strong><br>${(inc.description||'').substring(0,120)}${inc.road ? '<br><em>'+inc.road+'</em>' : ''}</div>`))
                .addTo(trafficMap);
        });

        // Schedule next refresh (2 min)
        setTimeout(refreshTrafficData, 120000);
    }

    // Cameras
    async function loadKioskCameras() {
        const el = document.getElementById('kioskCameras');
        const data = await window.portalAPI('cameras.php');
        if (!data || !data.cameras) return;
        const cams = data.cameras.slice(0, 9);
        el.innerHTML = cams.map(c => `
            <div class="k-camera">
                <img src="${c.image_url}" alt="" onerror="this.style.opacity='0.2';" loading="lazy">
                <div class="k-camera-label">${c.name}</div>
            </div>
        `).join('');
    }

    // Stories
    async function loadStories() {
        const data = await window.portalAPI('stories.php');
        if (data && data.stories) storiesData = data.stories;
    }
    function showNextStory() {
        if (storiesData.length === 0) return;
        const s = storiesData[storyIdx % storiesData.length];
        storyIdx++;
        const el = document.getElementById('kioskStory');
        el.style.backgroundImage = `url('${s.image}')`;
        document.getElementById('kioskStorySource').textContent = s.source;
        document.getElementById('kioskStoryTitle').textContent = s.title;
        document.getElementById('kioskStorySub').textContent = s.subtitle || '';
    }

    // 5-Day Schedule Grid
    async function loadKioskCalendar() {
        const el = document.getElementById('kioskScheduleGrid');

        // Fetch all 3 data sources in parallel
        const [calData, councilData, saintsData] = await Promise.all([
            window.portalAPI('calendar-today.php?days=5'),
            window.portalAPI('council.php'),
            window.portalAPI('saints.php'),
        ]);

        // Build 5 days
        const days = [];
        const today = new Date();
        today.setHours(0,0,0,0);
        for (let i = 0; i < 5; i++) {
            const d = new Date(today);
            d.setDate(d.getDate() + i);
            days.push({
                date: d,
                dateStr: d.toISOString().slice(0,10),
                label: i === 0 ? 'Today' : i === 1 ? 'Tomorrow' : d.toLocaleDateString('en-US',{weekday:'short'}),
                dayNum: d.getDate(),
                month: d.toLocaleDateString('en-US',{month:'short'}),
                isToday: i === 0,
            });
        }

        // Group CFD events by date
        const cfdByDate = {};
        (calData?.events || []).forEach(e => {
            const d = e.date || today.toISOString().slice(0,10);
            if (!cfdByDate[d]) cfdByDate[d] = [];
            cfdByDate[d].push(e);
        });

        // Group council meetings by date
        const councilByDate = {};
        (councilData?.meetings || []).forEach(m => {
            if (!councilByDate[m.date]) councilByDate[m.date] = [];
            councilByDate[m.date].push(m);
        });

        // Find Saints games by date
        const saintsByDate = {};
        (saintsData?.games || []).forEach(g => {
            if (!saintsByDate[g.date]) saintsByDate[g.date] = [];
            saintsByDate[g.date].push(g);
        });

        function esc(s) { const d = document.createElement('div'); d.textContent = s||''; return d.innerHTML; }

        el.innerHTML = days.map(day => {
            const cfdEvents = cfdByDate[day.dateStr] || [];
            const councilMeetings = councilByDate[day.dateStr] || [];
            const saintsGames = saintsByDate[day.dateStr] || [];
            const hasCfd = cfdEvents.length > 0;
            const hasCouncil = councilMeetings.length > 0;
            const hasSaints = saintsGames.length > 0;

            let html = `<div class="sched-col ${day.isToday ? 'today' : ''}">`;
            html += `<div class="sched-day-label">${esc(day.label)}</div>`;
            html += `<div class="sched-day-date">${esc(day.month)} ${day.dayNum}</div>`;
            html += `<div class="sched-col-inner">`;

            // CFD Events
            html += `<div class="sched-section" style="color:#5BA4D9;">
                <svg width="10" height="10" viewBox="0 0 24 24" fill="#5BA4D9"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/></svg>
                CFD Ops</div>`;
            if (hasCfd) {
                cfdEvents.forEach(e => {
                    html += `<div class="sched-item">
                        <div class="sched-item-time">${esc(e.time || 'All Day')}</div>
                        <div class="sched-item-title">${esc(e.summary)}</div>
                        ${e.location ? `<div class="sched-item-sub">${esc(e.location)}</div>` : ''}
                    </div>`;
                });
            } else {
                html += `<div class="sched-empty">No CFD events</div>`;
            }

            // Council
            html += `<div class="sched-section" style="color:#00A6A0;">
                <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#00A6A0" stroke-width="2"><path d="M3 21h18M3 10h18M5 6l7-3 7 3M4 10v11M20 10v11"/></svg>
                Council</div>`;
            if (hasCouncil) {
                councilMeetings.forEach(m => {
                    const isPubSafe = m.category === 'public-safety';
                    html += `<div class="sched-item sched-council" ${isPubSafe ? 'style="border-left-color:#00A6A0;background:rgba(0,166,160,0.05);"' : ''}>
                        <div class="sched-item-time">${esc(m.time)}</div>
                        <div class="sched-item-title">${esc(m.name)}</div>
                        <div class="sched-item-sub">${esc(m.location)}</div>
                    </div>`;
                });
            } else {
                html += `<div class="sched-empty">No meetings</div>`;
            }

            // Saints
            html += `<div class="sched-section" style="color:#d3bc8d;">
                <img src="https://a.espncdn.com/i/teamlogos/nfl/500/no.png" width="10" height="10" style="object-fit:contain;">
                Saints</div>`;
            if (hasSaints) {
                saintsGames.forEach(g => {
                    const resultColor = g.won === true ? '#d3bc8d' : g.won === false ? '#dc2626' : 'rgba(255,255,255,0.5)';
                    const resultText = g.won === true ? 'W' : g.won === false ? 'L' : '';
                    const score = g.saintsScore ? `${g.saintsScore}-${g.opponentScore}` : g.status;
                    html += `<div class="sched-item sched-saints">
                        <div style="display:flex;align-items:center;gap:6px;">
                            ${g.opponentLogo ? `<img src="${g.opponentLogo}" width="16" height="16" style="object-fit:contain;">` : ''}
                            <div>
                                <div class="sched-item-title">${g.home ? 'vs' : '@'} ${esc(g.opponent)}</div>
                                <div style="font-size:10px;color:${resultColor};font-weight:700;">${resultText} ${esc(score)}</div>
                            </div>
                        </div>
                    </div>`;
                });
            } else {
                html += `<div class="sched-empty">No game</div>`;
            }

            html += `</div></div>`; // close sched-col-inner + sched-col
            return html;
        }).join('');

        // Auto-scroll columns that overflow
        setTimeout(() => initSchedAutoScroll(), 500);
    }

    let schedScrollTimers = [];
    function initSchedAutoScroll() {
        schedScrollTimers.forEach(t => clearInterval(t));
        schedScrollTimers = [];

        document.querySelectorAll('.sched-col').forEach(col => {
            const inner = col.querySelector('.sched-col-inner');
            if (!inner) return;

            const colHeight = col.clientHeight - 50; // minus header space
            const contentHeight = inner.scrollHeight;
            if (contentHeight <= colHeight) return; // fits, no scroll needed

            const overflow = contentHeight - colHeight;
            let scrollPos = 0;
            let direction = 1;
            const PAUSE_TOP = 3000;    // pause at top 3s
            const PAUSE_BOTTOM = 3000; // pause at bottom 3s
            let pauseUntil = Date.now() + PAUSE_TOP;

            const timer = setInterval(() => {
                if (Date.now() < pauseUntil) return;

                scrollPos += direction * 0.5;

                if (scrollPos >= overflow) {
                    scrollPos = overflow;
                    direction = -1;
                    pauseUntil = Date.now() + PAUSE_BOTTOM;
                } else if (scrollPos <= 0) {
                    scrollPos = 0;
                    direction = 1;
                    pauseUntil = Date.now() + PAUSE_TOP;
                }

                inner.style.transform = `translateY(-${scrollPos}px)`;
            }, 30);

            schedScrollTimers.push(timer);
        });
    }

    // ─── ECharts (dark theme) ───────────────────────────
    function initDarkChart(id) {
        const dom = document.getElementById(id);
        if (!dom) return null;
        const c = echarts.init(dom, 'dark');
        c.setOption({ backgroundColor: 'transparent' });
        window.addEventListener('resize', () => c.resize());
        return c;
    }

    <?php if ($fireSummary):
        $fireTypes = json_decode($fireSummary['incident_types'] ?? '{}', true) ?: [];
        $fireApp = json_decode($fireSummary['apparatus_counts'] ?? '{}', true) ?: [];
    ?>
    const fireTypesChart = initDarkChart('kioskFireTypes');
    if (fireTypesChart) {
        const ftData = <?= json_encode(array_map(fn($k,$v)=>['name'=>$k,'value'=>$v], array_keys(array_slice($fireTypes,0,8)), array_values(array_slice($fireTypes,0,8)))) ?>;
        fireTypesChart.setOption({
            backgroundColor:'transparent',
            tooltip:{trigger:'item',backgroundColor:'#0B2240',textStyle:{color:'#fff'}},
            series:[{type:'treemap',data:ftData,roam:false,breadcrumb:{show:false},itemStyle:{borderRadius:4,borderWidth:2,borderColor:'rgba(7,15,27,0.8)'},label:{show:true,formatter:'{b}\n{c}',fontSize:10,color:'#fff',lineHeight:14},color:['#E74C3C','#E67E22','#8CC63F','#3498DB','#8E44AD','#00BCD4','#F39C12','#1B6CB0']}]
        });
    }
    const fireAppChart = initDarkChart('kioskFireApparatus');
    if (fireAppChart) {
        const appNames = <?= json_encode(array_reverse(array_keys(array_slice($fireApp,0,8)))) ?>;
        const appVals = <?= json_encode(array_reverse(array_values(array_slice($fireApp,0,8)))) ?>;
        fireAppChart.setOption({
            grid:{top:4,right:36,bottom:4,left:8,containLabel:true}, backgroundColor:'transparent',
            xAxis:{type:'value',show:false},
            yAxis:{type:'category',data:appNames,axisLabel:{color:'#666',fontSize:10},axisLine:{show:false},axisTick:{show:false}},
            series:[{type:'bar',data:appVals,barWidth:14,itemStyle:{borderRadius:[0,6,6,0],color:new echarts.graphic.LinearGradient(0,0,1,0,[{offset:0,color:'#C0392B'},{offset:1,color:'#E74C3C'}])},label:{show:true,position:'right',color:'#888',fontSize:10}}]
        });
    }
    <?php endif; ?>

    // Fire Apparatus Turnout Time Liquid Fill Gauges (E/T/H units)
    <?php if (!empty($fireTurnout)): ?>
    (function() {
        const container = document.getElementById('kioskFireGauges');
        if (!container) return;
        const turnoutData = <?= json_encode($fireTurnout) ?>;
        const units = Object.keys(turnoutData).sort();
        const goalSec = 90; // 90-second turnout goal

        units.forEach(unit => {
            const d = turnoutData[unit];
            const avg = d.avg || 0;
            const pct = Math.min(avg / (goalSec * 2), 1); // normalize to 0-1 (180s max)
            const prefix = unit.charAt(0).toUpperCase();
            // Color by unit type AND performance
            const baseColor = prefix === 'E' ? '#E74C3C' : prefix === 'T' ? '#3498DB' : '#FCD34D';
            const perfColor = avg <= 60 ? '#8CC63F' : (avg <= 90 ? '#5BA4D9' : (avg <= 120 ? '#FCD34D' : '#FCA5A5'));

            const div = document.createElement('div');
            div.style.cssText = 'flex:1; min-width:60px; max-width:80px;';
            div.innerHTML = `<div id="kFireGauge_${unit}" style="height:80px;"></div>
                <div style="text-align:center;font-size:10px;font-weight:700;color:rgba(255,255,255,0.6);margin-top:2px;">${unit}</div>
                <div style="text-align:center;font-size:8px;color:rgba(255,255,255,0.3);">${d.runs} runs</div>`;
            container.appendChild(div);

            const chart = echarts.init(document.getElementById('kFireGauge_' + unit), 'dark');
            chart.setOption({
                backgroundColor: 'transparent',
                series: [{
                    type: 'liquidFill',
                    data: [pct, pct - 0.05],
                    radius: '85%',
                    center: ['50%', '45%'],
                    color: [perfColor, perfColor + '99'],
                    backgroundStyle: { color: 'rgba(255,255,255,0.03)' },
                    outline: { borderDistance: 2, itemStyle: { borderWidth: 2, borderColor: perfColor, opacity: 0.4 } },
                    label: {
                        formatter: function() { return avg + 's'; },
                        fontSize: 12, fontWeight: 800, color: perfColor, insideColor: '#fff'
                    },
                    shape: 'circle',
                    animationDuration: 2000
                }]
            });
            window.addEventListener('resize', () => chart.resize());
        });
    })();
    <?php endif; ?>

    // Init
    loadStories();
    loadKioskMap();
    start();

    // ═══ STRUCTURE FIRE ALERT OVERLAY ═══════════════════
    let structOverlayActive = false;
    let structOrbitTimer = null;
    let structElapsedTimer = null;
    let structAutoDismissTimer = null;
    let structMap = null;
    let structHeading = 0;

    window.addEventListener('structureFire', function(e) {
        const inc = e.detail;
        if (structOverlayActive) return; // already showing
        showStructFireOverlay(inc);
    });

    function showStructFireOverlay(inc) {
        structOverlayActive = true;

        // Pause kiosk
        if (!paused) window.toggleKioskPause();

        const overlay = document.getElementById('structFireOverlay');
        const typeClean = (inc.incident_type || 'STRUCTURE FIRE').replace(/\s*(CFD|\().*$/i, '').replace(/^=/, '').trim() || 'STRUCTURE FIRE';
        const units = (inc.units_assigned || '').split(',').filter(u => u.trim());
        const addr = inc.address || 'Unknown Address';
        const city = inc.city || 'Cincinnati';
        const dispatchTime = inc.received_at ? new Date(inc.received_at.replace(' ', 'T')).toLocaleTimeString('en-US', {hour:'numeric',minute:'2-digit'}) : 'now';
        const cadMatch = (inc.incident_type || '').match(/CFD\d+/);
        const cadNum = cadMatch ? cadMatch[0] : inc.incident_id || '';

        // Fill content
        document.getElementById('sfAddress').textContent = addr + ', ' + city;
        document.getElementById('sfTime').textContent = dispatchTime;
        document.getElementById('sfType').textContent = typeClean;
        document.getElementById('sfUnits').innerHTML = units.map(u =>
            `<span style="display:inline-block;padding:4px 14px;background:rgba(220,38,38,0.15);border:1px solid rgba(220,38,38,0.3);border-radius:8px;font-size:14px;font-weight:700;color:#fff;letter-spacing:0.5px;">${u.trim()}</span>`
        ).join('');
        document.getElementById('sfCad').textContent = cadNum;
        document.getElementById('sfPriority').textContent = inc.priority || '1';

        // Elapsed timer
        const dispatchTs = inc.received_at ? new Date(inc.received_at.replace(' ', 'T')).getTime() : Date.now();
        const elapsedEl = document.getElementById('sfElapsed');
        function updateElapsed() {
            const diff = Math.floor((Date.now() - dispatchTs) / 1000);
            const m = Math.floor(diff / 60);
            const s = diff % 60;
            elapsedEl.textContent = m + ':' + String(s).padStart(2, '0');
        }
        updateElapsed();
        structElapsedTimer = setInterval(updateElapsed, 1000);

        // Show overlay
        overlay.style.display = 'flex';
        requestAnimationFrame(() => overlay.classList.add('active'));

        // Load maps
        const lat = parseFloat(inc.latitude) || 0;
        const lng = parseFloat(inc.longitude) || 0;

        if (lat && lng) {
            loadStructMaps(lat, lng);
        } else {
            // Geocode
            const geocoder = new google.maps.Geocoder();
            geocoder.geocode({ address: addr + ', ' + city + ', OH' }, function(results, status) {
                if (status === 'OK' && results[0]) {
                    const loc = results[0].geometry.location;
                    loadStructMaps(loc.lat(), loc.lng());
                } else {
                    document.getElementById('sfStreetView').innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:rgba(255,255,255,0.3);">Location not found</div>';
                }
            });
        }

        // Auto-dismiss after 5 minutes
        structAutoDismissTimer = setTimeout(dismissStructOverlay, 180000);
    }

    function loadStructMaps(lat, lng) {
        // Street View (left)
        const svContainer = document.getElementById('sfStreetView');
        svContainer.innerHTML = '';
        const svService = new google.maps.StreetViewService();
        svService.getPanorama({ location: { lat, lng }, radius: 150 }, function(data, status) {
            if (status === google.maps.StreetViewStatus.OK) {
                new google.maps.StreetViewPanorama(svContainer, {
                    position: data.location.latLng,
                    pov: { heading: google.maps.geometry ? 0 : 0, pitch: 5 },
                    zoom: 1,
                    addressControl: false,
                    showRoadLabels: true,
                    linksControl: false,
                    fullscreenControl: false,
                });
            } else {
                svContainer.innerHTML = `<div style="display:flex;align-items:center;justify-content:center;height:100%;"><img src="https://maps.googleapis.com/maps/api/staticmap?center=${lat},${lng}&zoom=18&size=800x600&maptype=hybrid&markers=color:red|${lat},${lng}&key=${window.CFD_PORTAL?.mapsKey || ''}" style="width:100%;height:100%;object-fit:cover;"></div>`;
            }
        });

        // Orbiting satellite map (right) — Mapbox GL JS
        const mapContainer = document.getElementById('sfSatelliteMap');
        mapContainer.innerHTML = '';
        structHeading = 0;

        // Load Mapbox GL JS if not already loaded
        if (!window.mapboxgl) {
            const link = document.createElement('link');
            link.rel = 'stylesheet';
            link.href = 'https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.css';
            document.head.appendChild(link);
            const script = document.createElement('script');
            script.src = 'https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.js';
            script.onload = () => initMapboxOrbit(lat, lng, mapContainer);
            document.head.appendChild(script);
        } else {
            initMapboxOrbit(lat, lng, mapContainer);
        }
    }

    function initMapboxOrbit(lat, lng, container) {
        mapboxgl.accessToken = 'pk.eyJ1IjoiYm9iYnlodWciLCJhIjoiY21lZWp6eG1oMG1udDJpcTVxb2twMTVhNSJ9.5EW_XCxmcZt5VaPfAd0Kjg';
        container.style.cssText = 'position:relative;width:100%;height:100%;';

        try {
            structMap = new mapboxgl.Map({
                container: container,
                style: 'mapbox://styles/mapbox/satellite-streets-v12',
                center: [lng, lat],
                zoom: 17,
                pitch: 60,
                bearing: 0,
                interactive: false,
            });

            structMap.on('load', function() {
                const markerEl = document.createElement('div');
                markerEl.innerHTML = `
                    <div style="position:relative;">
                        <div style="width:28px;height:28px;background:#dc2626;border:3px solid #fff;border-radius:50%;box-shadow:0 0 20px rgba(220,38,38,0.6);"></div>
                        <div style="position:absolute;inset:-8px;border:2px solid #dc2626;border-radius:50%;animation:sfMapPulse 2s ease-out infinite;"></div>
                    </div>`;
                new mapboxgl.Marker({ element: markerEl }).setLngLat([lng, lat]).addTo(structMap);

                structHeading = 0;
                structOrbitTimer = setInterval(() => {
                    structHeading = (structHeading + 0.3) % 360;
                    structMap.setBearing(structHeading);
                }, 50);
            });

            structMap.on('error', () => fallbackSatellite(lat, lng, container));
        } catch(e) {
            fallbackSatellite(lat, lng, container);
        }
    }

    function fallbackSatellite(lat, lng, container) {
        // Static satellite image fallback (no WebGL)
        const mapsKey = window.CFD_PORTAL?.mapsKey || '';
        container.innerHTML = `
            <div style="position:relative;width:100%;height:100%;">
                <img src="https://maps.googleapis.com/maps/api/staticmap?center=${lat},${lng}&zoom=17&size=800x800&maptype=satellite&markers=color:red|${lat},${lng}&key=${mapsKey}"
                    style="width:100%;height:100%;object-fit:cover;">
                <div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:32px;height:32px;background:#dc2626;border:3px solid #fff;border-radius:50%;box-shadow:0 0 20px rgba(220,38,38,0.6);"></div>
            </div>`;
    }

    window.dismissStructOverlay = function() {
        const overlay = document.getElementById('structFireOverlay');
        overlay.classList.remove('active');
        setTimeout(() => { overlay.style.display = 'none'; }, 500);
        structOverlayActive = false;
        if (structOrbitTimer) { clearInterval(structOrbitTimer); structOrbitTimer = null; }
        if (structElapsedTimer) { clearInterval(structElapsedTimer); structElapsedTimer = null; }
        if (structAutoDismissTimer) { clearTimeout(structAutoDismissTimer); structAutoDismissTimer = null; }
        if (structMap && structMap.remove) structMap.remove();
        structMap = null;
        // Resume kiosk
        if (paused) window.toggleKioskPause();
    };

    // Test: console → window.testStructFire()  |  keyboard → Ctrl+Shift+F
    window.testStructFire = function() {
        window.dispatchEvent(new CustomEvent('structureFire', { detail: {
            incident_id: 'TEST001',
            incident_type: '=STRUCT - (C) CFD260327TEST01',
            address: '312 ELM ST',
            city: 'CINCINNATI',
            latitude: '39.1079',
            longitude: '-84.5127',
            units_assigned: 'E1,L1,BC1,R1,M19,E14',
            priority: '1',
            received_at: new Date().toISOString().replace('T',' ').slice(0,19),
        }}));
    };

    document.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.shiftKey && e.key === 'F') {
            e.preventDefault();
            window.testStructFire();
        }
    });
});
</script>

<!-- Cincinnati Reds Live Game Banner -->
<div id="redsBanner" class="reds-banner">
    <div id="redsBannerContent"></div>
</div>

<!-- Reds Win Fireworks Overlay -->
<div id="redsFwOverlay" class="reds-fw-overlay" style="display:none;">
    <canvas id="redsFwCanvas"></canvas>
    <div class="fw-text-wrap">
        <img id="fwLogo" class="fw-logo" src="">
        <div class="fw-title" id="fwTitle">REDS WIN!</div>
        <div class="fw-score" id="fwScore"></div>
    </div>
</div>

<style>
/* ═══ REDS LIVE GAME BANNER ═══ */
.reds-banner {
    position:fixed; bottom:0; left:var(--sidebar-width, 240px); right:0; z-index:100; height:54px;
    background:linear-gradient(90deg, #C6011F 0%, #a00018 40%, #1a1a2e 100%);
    transform:translateY(100%); transition:transform 0.5s cubic-bezier(0.4,0,0.2,1);
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 -4px 20px rgba(0,0,0,0.4); border-top:1px solid rgba(255,255,255,0.08);
}
.kiosk-fullscreen .reds-banner { left:0; }
.reds-banner.visible { transform:translateY(0); }
.reds-banner-inner {
    display:flex; align-items:center; gap:16px; color:#fff; font-family:-apple-system,system-ui,sans-serif;
}
.rb-team { display:flex; align-items:center; gap:8px; }
.rb-team img { width:34px; height:34px; object-fit:contain; }
.rb-team-name { font-size:14px; font-weight:700; letter-spacing:0.5px; }
.rb-score { font-size:28px; font-weight:900; letter-spacing:1px; padding:0 12px; }
.rb-sep { color:rgba(255,255,255,0.15); font-size:24px; font-weight:200; }
.rb-detail { font-size:12px; color:rgba(255,255,255,0.7); font-weight:600; }
.rb-live { display:flex; align-items:center; gap:5px; font-size:11px; font-weight:700; color:#fff; text-transform:uppercase; letter-spacing:0.5px; }
.rb-live-dot { width:8px; height:8px; border-radius:50%; background:#C6011F; animation:rbPulse 1.5s ease-in-out infinite; }
@keyframes rbPulse { 0%,100%{box-shadow:0 0 0 0 rgba(198,1,31,0.6)} 50%{box-shadow:0 0 0 8px rgba(198,1,31,0)} }
.rb-outs { display:flex; gap:3px; }
.rb-out { width:8px; height:8px; border-radius:50%; border:1.5px solid rgba(255,255,255,0.3); }
.rb-out.filled { background:#FFD700; border-color:#FFD700; }
.rb-bases { display:grid; grid-template-areas:"x s2 x2" "s3 x3 s1" "x4 h x5"; gap:1px; }
.rb-base { width:10px; height:10px; transform:rotate(45deg); border:1.5px solid rgba(255,255,255,0.25); }
.rb-base.lit { background:#FFD700; border-color:#FFD700; }
.rb-base-1 { grid-area:s1; } .rb-base-2 { grid-area:s2; } .rb-base-3 { grid-area:s3; }
.rb-pregame { font-size:13px; color:rgba(255,255,255,0.6); }

/* ═══ FIREWORKS ═══ */
.reds-fw-overlay {
    position:fixed; inset:0; z-index:9500; background:rgba(0,0,0,0.85);
    display:flex; align-items:center; justify-content:center;
    opacity:0; transition:opacity 0.5s;
}
.reds-fw-overlay.active { opacity:1; }
.reds-fw-overlay canvas { position:absolute; inset:0; width:100%; height:100%; }
.fw-text-wrap { position:relative; z-index:2; text-align:center; color:#fff; }
.fw-logo { width:120px; height:120px; object-fit:contain; opacity:0; transform:scale(0); transition:all 0.6s cubic-bezier(0.34,1.56,0.64,1); }
.fw-logo.pop { opacity:1; transform:scale(1); }
.fw-title { font-size:72px; font-weight:900; text-shadow:0 0 40px rgba(198,1,31,0.8), 0 0 80px rgba(198,1,31,0.4); opacity:0; transform:scale(0.5); transition:all 0.5s cubic-bezier(0.34,1.56,0.64,1); }
.fw-title.pop { opacity:1; transform:scale(1); }
.fw-score { font-size:24px; color:rgba(255,255,255,0.7); margin-top:8px; opacity:0; transform:translateY(20px); transition:all 0.5s ease; }
.fw-score.pop { opacity:1; transform:translateY(0); }
</style>

<script>
// ═══ REDS LIVE GAME BANNER ═══════════════════════════════
(function() {
    const REDS_ID = '17';
    const ESPN_URL = 'https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/scoreboard';
    const banner = document.getElementById('redsBanner');
    const content = document.getElementById('redsBannerContent');
    let pollTimer = null;
    let lastState = null;
    let fireworksShown = false;

    async function checkGame() {
        try {
            const resp = await fetch(ESPN_URL);
            const data = await resp.json();

            let redsGame = null;
            for (const evt of (data.events || [])) {
                const comp = evt.competitions?.[0];
                if (!comp) continue;
                for (const c of comp.competitors || []) {
                    if (c.team?.id === REDS_ID || c.team?.abbreviation === 'CIN') {
                        redsGame = { event: evt, competition: comp };
                        break;
                    }
                }
                if (redsGame) break;
            }

            if (!redsGame) {
                // No game today — show next upcoming game from schedule
                showNextGame();
                schedulePoll(300000);
                return;
            }

            // Check localStorage for fireworks already shown for this game
            const fwKey = 'reds_fw_' + redsGame.event.id;
            try { if (localStorage.getItem(fwKey)) fireworksShown = true; } catch(e) {}

            const comp = redsGame.competition;
            const status = comp.status?.type;
            const state = status?.state; // pre, in, post
            const detail = status?.shortDetail || '';
            const situation = comp.situation || null;

            let away = null, home = null, reds = null, opponent = null;
            for (const c of comp.competitors) {
                if (c.homeAway === 'away') away = c;
                else home = c;
                if (c.team?.id === REDS_ID || c.team?.abbreviation === 'CIN') reds = c;
                else opponent = c;
            }

            if (state === 'pre') {
                const gameTime = new Date(redsGame.event.date);
                const hoursUntil = (gameTime - Date.now()) / 3600000;
                const timeStr = gameTime.toLocaleTimeString('en-US', {hour:'numeric', minute:'2-digit'});
                const dateStr = gameTime.toLocaleDateString('en-US', {weekday:'short', month:'short', day:'numeric'});
                const isToday = new Date().toDateString() === gameTime.toDateString();
                const label = isToday ? `First Pitch — ${timeStr}` : `${dateStr} · ${timeStr}`;
                showBanner(`
                    <div class="reds-banner-inner">
                        <div class="rb-team"><img src="${opponent?.team?.logo || ''}"><span class="rb-team-name">${opponent?.team?.displayName || ''}</span></div>
                        <span class="rb-sep">|</span>
                        <span class="rb-pregame">${isToday ? 'Today' : 'Next Game'} · ${label}</span>
                        <span class="rb-sep">|</span>
                        <div class="rb-team"><span class="rb-team-name">CIN</span><img src="${reds?.team?.logo || ''}"></div>
                    </div>
                `);
                schedulePoll(hoursUntil > 2 ? 300000 : 60000);
            } else if (state === 'in') {
                const awayScore = away?.score || '0';
                const homeScore = home?.score || '0';

                let situationHtml = '';
                if (situation) {
                    const outs = situation.outs || 0;
                    const balls = situation.balls ?? '-';
                    const strikes = situation.strikes ?? '-';
                    situationHtml = `
                        <span class="rb-sep">|</span>
                        <span class="rb-detail">${balls}-${strikes}</span>
                        <span class="rb-sep">|</span>
                        <div class="rb-outs">
                            <div class="rb-out ${outs >= 1 ? 'filled' : ''}"></div>
                            <div class="rb-out ${outs >= 2 ? 'filled' : ''}"></div>
                            <div class="rb-out ${outs >= 3 ? 'filled' : ''}"></div>
                        </div>
                        <span class="rb-sep">|</span>
                        <div class="rb-bases">
                            <div class="rb-base rb-base-2 ${situation.onSecond ? 'lit' : ''}"></div>
                            <div class="rb-base rb-base-3 ${situation.onThird ? 'lit' : ''}"></div>
                            <div class="rb-base rb-base-1 ${situation.onFirst ? 'lit' : ''}"></div>
                        </div>
                    `;
                }

                showBanner(`
                    <div class="reds-banner-inner">
                        <div class="rb-team"><img src="${away?.team?.logo || ''}"><span class="rb-team-name">${away?.team?.abbreviation || ''}</span></div>
                        <span class="rb-score">${awayScore} — ${homeScore}</span>
                        <div class="rb-team"><span class="rb-team-name">${home?.team?.abbreviation || ''}</span><img src="${home?.team?.logo || ''}"></div>
                        <span class="rb-sep">|</span>
                        <span class="rb-detail">${detail}</span>
                        ${situationHtml}
                        <span class="rb-sep">|</span>
                        <div class="rb-live"><div class="rb-live-dot"></div>LIVE</div>
                    </div>
                `);
                schedulePoll(30000);
            } else if (state === 'post') {
                const awayScore = away?.score || '0';
                const homeScore = home?.score || '0';
                const redsWon = reds?.winner === true;

                showBanner(`
                    <div class="reds-banner-inner">
                        <div class="rb-team"><img src="${away?.team?.logo || ''}"><span class="rb-team-name">${away?.team?.abbreviation || ''}</span></div>
                        <span class="rb-score">${awayScore} — ${homeScore}</span>
                        <div class="rb-team"><span class="rb-team-name">${home?.team?.abbreviation || ''}</span><img src="${home?.team?.logo || ''}"></div>
                        <span class="rb-sep">|</span>
                        <span class="rb-detail" style="${redsWon ? 'color:#FFD700;font-weight:800;' : ''}">FINAL${redsWon ? ' — REDS WIN!' : ''}</span>
                    </div>
                `);

                // Only fire fireworks if: Reds won, not already shown, and game ended within last hour
                const gameEndedRecently = redsGame.event.date ? (Date.now() - new Date(redsGame.event.date).getTime()) < 6 * 3600000 : false;
                if (redsWon && !fireworksShown && gameEndedRecently) {
                    fireworksShown = true;
                    try { localStorage.setItem(fwKey, '1'); } catch(e) {}
                    launchFireworks(reds?.team?.logo || '', awayScore, homeScore, opponent?.team?.displayName || '');
                }

                setTimeout(hideBanner, 1800000); // hide after 30 min
                schedulePoll(300000);
            }

            lastState = state;
        } catch (e) {
            schedulePoll(60000);
        }
    }

    function showBanner(html) { content.innerHTML = html; banner.classList.add('visible'); }

    async function showNextGame() {
        try {
            const resp = await fetch('https://site.api.espn.com/apis/site/v2/sports/baseball/mlb/teams/17/schedule');
            const data = await resp.json();
            const now = Date.now();
            let nextEvt = null;
            for (const evt of (data.events || [])) {
                const evtDate = new Date(evt.date);
                if (evtDate > now) { nextEvt = evt; break; }
            }
            if (!nextEvt) { hideBanner(); return; }

            const comp = nextEvt.competitions?.[0];
            if (!comp) { hideBanner(); return; }
            let opponent = null, reds = null;
            for (const c of comp.competitors || []) {
                if (c.team?.id === REDS_ID || c.team?.abbreviation === 'CIN') reds = c;
                else opponent = c;
            }
            const gameTime = new Date(nextEvt.date);
            const dateStr = gameTime.toLocaleDateString('en-US', {weekday:'short', month:'short', day:'numeric'});
            const timeStr = gameTime.toLocaleTimeString('en-US', {hour:'numeric', minute:'2-digit'});

            showBanner(`
                <div class="reds-banner-inner">
                    <div class="rb-team"><img src="${opponent?.team?.logo || ''}"><span class="rb-team-name">${opponent?.team?.displayName || ''}</span></div>
                    <span class="rb-sep">|</span>
                    <span class="rb-pregame">Next Game · ${dateStr} · ${timeStr}</span>
                    <span class="rb-sep">|</span>
                    <div class="rb-team"><span class="rb-team-name">CIN</span><img src="${reds?.team?.logo || ''}"></div>
                </div>
            `);
        } catch(e) { hideBanner(); }
    }
    function hideBanner() { banner.classList.remove('visible'); }
    function schedulePoll(ms) { if (pollTimer) clearTimeout(pollTimer); pollTimer = setTimeout(checkGame, ms); }

    // ── FIREWORKS ENGINE ──────────────────────────────
    function launchFireworks(logo, awayScore, homeScore, oppName) {
        const overlay = document.getElementById('redsFwOverlay');
        const canvas = document.getElementById('redsFwCanvas');
        const ctx = canvas.getContext('2d');
        overlay.style.display = 'flex';
        requestAnimationFrame(() => overlay.classList.add('active'));

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        document.getElementById('fwLogo').src = logo;
        document.getElementById('fwScore').textContent = `${homeScore} — ${awayScore} vs ${oppName}`;

        setTimeout(() => document.getElementById('fwLogo').classList.add('pop'), 500);
        setTimeout(() => document.getElementById('fwTitle').classList.add('pop'), 1000);
        setTimeout(() => document.getElementById('fwScore').classList.add('pop'), 1500);

        const colors = ['#C6011F','#C6011F','#C6011F','#FFFFFF','#FFFFFF','#FFD700','#FFA500'];
        const particles = [];
        const rockets = [];
        let frame = 0;
        const DURATION = 20 * 60; // 20 sec at 60fps

        function addRocket() {
            rockets.push({
                x: Math.random() * canvas.width,
                y: canvas.height,
                targetY: canvas.height * (0.1 + Math.random() * 0.35),
                speed: 6 + Math.random() * 4,
                exploded: false,
            });
        }

        function explode(x, y) {
            const count = 60 + Math.floor(Math.random() * 40);
            const color = colors[Math.floor(Math.random() * colors.length)];
            for (let i = 0; i < count; i++) {
                const angle = (Math.PI * 2 * i) / count + (Math.random() - 0.5) * 0.3;
                const speed = 2 + Math.random() * 4;
                particles.push({
                    x, y,
                    vx: Math.cos(angle) * speed,
                    vy: Math.sin(angle) * speed,
                    life: 1,
                    decay: 0.01 + Math.random() * 0.015,
                    color,
                    size: 1.5 + Math.random() * 2,
                });
            }
        }

        function animate() {
            if (frame > DURATION) {
                overlay.classList.remove('active');
                setTimeout(() => {
                    overlay.style.display = 'none';
                    document.getElementById('fwLogo').classList.remove('pop');
                    document.getElementById('fwTitle').classList.remove('pop');
                    document.getElementById('fwScore').classList.remove('pop');
                }, 1500);
                return;
            }
            frame++;
            requestAnimationFrame(animate);

            ctx.fillStyle = 'rgba(0,0,0,0.15)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // Launch rockets
            if (frame % 15 === 0 && frame < DURATION - 120) addRocket();

            // Update rockets
            for (let i = rockets.length - 1; i >= 0; i--) {
                const r = rockets[i];
                r.y -= r.speed;
                ctx.fillStyle = '#FFA500';
                ctx.fillRect(r.x - 1, r.y, 2, 6);
                if (r.y <= r.targetY && !r.exploded) {
                    r.exploded = true;
                    explode(r.x, r.y);
                    rockets.splice(i, 1);
                }
            }

            // Update particles
            for (let i = particles.length - 1; i >= 0; i--) {
                const p = particles[i];
                p.x += p.vx;
                p.y += p.vy;
                p.vy += 0.04; // gravity
                p.life -= p.decay;
                if (p.life <= 0) { particles.splice(i, 1); continue; }

                ctx.globalAlpha = p.life * 0.15;
                ctx.beginPath();
                ctx.arc(p.x, p.y, p.size * 2.5, 0, Math.PI * 2);
                ctx.fillStyle = p.color;
                ctx.fill();

                ctx.globalAlpha = p.life;
                ctx.beginPath();
                ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
                ctx.fill();
            }
            ctx.globalAlpha = 1;
        }

        animate();
    }

    // Start polling
    checkGame();
})();
</script>

<!-- Structure Fire Alert Overlay -->
<div id="structFireOverlay" class="struct-fire-overlay" style="display:none;">
    <div class="sf-header">
        <div class="sf-alert-badge">
            <span class="sf-pulse"></span>
            <svg width="20" height="20" viewBox="0 0 24 24" fill="#fff"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/></svg>
            <span class="sf-alert-text" id="sfType">STRUCTURE FIRE</span>
        </div>
        <div class="sf-header-center">
            <div class="sf-address" id="sfAddress"></div>
            <div class="sf-dispatch-time">Dispatched <span id="sfTime"></span> &middot; Elapsed <span id="sfElapsed" style="font-variant-numeric:tabular-nums;">0:00</span></div>
        </div>
        <button class="sf-dismiss" onclick="dismissStructOverlay()">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
            Dismiss
        </button>
    </div>
    <div class="sf-body">
        <div class="sf-panel" id="sfStreetView">
            <div style="display:flex;align-items:center;justify-content:center;height:100%;color:rgba(255,255,255,0.3);">Loading Street View...</div>
        </div>
        <div class="sf-panel" id="sfSatelliteMap">
            <div style="display:flex;align-items:center;justify-content:center;height:100%;color:rgba(255,255,255,0.3);">Loading satellite...</div>
        </div>
    </div>
    <div class="sf-footer">
        <div class="sf-units" id="sfUnits"></div>
        <div class="sf-meta">
            <span>Priority <strong id="sfPriority">1</strong></span>
            <span style="color:rgba(255,255,255,0.15);">|</span>
            <span>CAD <strong id="sfCad"></strong></span>
            <span style="color:rgba(255,255,255,0.15);">|</span>
            <span style="color:#dc2626;font-weight:700;">ACTIVE</span>
        </div>
    </div>
</div>

<style>
/* ═══ STRUCTURE FIRE ALERT OVERLAY ═══ */
.struct-fire-overlay {
    position: fixed; inset: 0; z-index: 9000;
    background: linear-gradient(135deg, #0a0a0a 0%, #1a0505 100%);
    flex-direction: column;
    opacity: 0; transform: translateY(-20px);
    transition: opacity 0.5s, transform 0.5s cubic-bezier(0.4,0,0.2,1);
    border: 3px solid rgba(220,38,38,0.6);
    box-shadow: inset 0 0 80px rgba(220,38,38,0.08);
}
.struct-fire-overlay.active { opacity: 1; transform: translateY(0); }

.sf-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 24px; background: rgba(220,38,38,0.12);
    border-bottom: 1px solid rgba(220,38,38,0.3);
    animation: sfHeaderPulse 3s ease-in-out infinite;
}
@keyframes sfHeaderPulse {
    0%,100% { background: rgba(220,38,38,0.12); }
    50% { background: rgba(220,38,38,0.2); }
}

.sf-alert-badge {
    display: flex; align-items: center; gap: 10px;
    background: #dc2626; padding: 6px 16px; border-radius: 8px;
    position: relative;
}
.sf-pulse {
    position: absolute; inset: -4px; border-radius: 12px;
    border: 2px solid #dc2626; opacity: 0;
    animation: sfPulseRing 2s ease-out infinite;
}
@keyframes sfPulseRing {
    0% { opacity: 0.8; inset: -2px; }
    100% { opacity: 0; inset: -16px; }
}
.sf-alert-text { font-size: 16px; font-weight: 800; color: #fff; letter-spacing: 1px; text-transform: uppercase; }

.sf-header-center { flex: 1; text-align: center; }
.sf-address { font-size: 20px; font-weight: 800; color: #fff; letter-spacing: 0.5px; }
.sf-dispatch-time { font-size: 12px; color: rgba(255,255,255,0.5); margin-top: 2px; }

.sf-dismiss {
    display: flex; align-items: center; gap: 6px;
    background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.15);
    color: rgba(255,255,255,0.6); padding: 8px 16px; border-radius: 8px;
    font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.2s;
}
.sf-dismiss:hover { background: rgba(255,255,255,0.15); color: #fff; }

.sf-body {
    flex: 1; display: flex; gap: 2px; padding: 2px; overflow: hidden;
}
.sf-panel {
    flex: 1; border-radius: 4px; overflow: hidden; background: #111;
    position: relative; min-height: 0;
}
.sf-panel .mapboxgl-map { position: absolute; inset: 0; }

.sf-footer {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 24px; background: rgba(0,0,0,0.4);
    border-top: 1px solid rgba(220,38,38,0.2);
}
.sf-units { display: flex; gap: 8px; flex-wrap: wrap; }
.sf-meta {
    display: flex; align-items: center; gap: 12px;
    font-size: 13px; color: rgba(255,255,255,0.5);
}
.sf-meta strong { color: #fff; }
/* ═══ TRAFFIC MAP ═══ */
.k-traffic-header {
    position: absolute; top: 12px; left: 12px; right: 12px; z-index: 5;
    display: flex; justify-content: space-between; align-items: center;
    padding: 8px 16px; background: rgba(7,15,27,0.7); backdrop-filter: blur(12px);
    border-radius: 10px; border: 1px solid rgba(255,255,255,0.06); color: #fff;
}
.k-traffic-legend {
    position: absolute; bottom: 24px; left: 16px; z-index: 5;
    padding: 12px 16px; background: rgba(7,15,27,0.75); backdrop-filter: blur(12px);
    border-radius: 10px; border: 1px solid rgba(255,255,255,0.06);
    color: rgba(255,255,255,0.7); font-size: 11px; min-width: 140px;
}
.k-tl-row { display: flex; align-items: center; gap: 8px; padding: 2px 0; }
.k-tl-line { width: 20px; height: 3px; border-radius: 2px; flex-shrink: 0; }
.k-tl-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
@keyframes trafficPulse { 0%,100% { opacity:1; } 50% { opacity:0.4; } }

@keyframes sfMapPulse {
    0% { opacity: 0.8; inset: -4px; }
    100% { opacity: 0; inset: -24px; }
}
</style>
