<?php
// Public Event Dashboard - No authentication required
include 'includes/db.php';
include 'includes/category_colors.php';

// Get event ID for category colors
$event_id = $_GET['event_id'] ?? null;
$category_colors_data = [];
if ($event_id) {
    $category_colors_data = getAllCategoryColors($pdo, $event_id);
}

// Only keep server handlers for report proxies; moved data actions to api/public_dashboard_api.php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax'])) {
    header('Content-Type: application/json');

    if (isset($_POST['action']) && $_POST['action'] === 'load_summary_table') {
        $config_id = $_POST['config_id'] ?? null;
        
        if ($config_id) {
            try {
                // Get configuration details
                $config_stmt = $pdo->prepare("
                    SELECT * FROM result_configurations WHERE id = ?
                ");
                $config_stmt->execute([$config_id]);
                $config = $config_stmt->fetch(PDO::FETCH_ASSOC);
                
                if ($config) {
                    // Use HTML format directly - same as backend
                    $summaryScript = 'api/summary_table_api.php';

                    // Request HTML format directly from API
                    $params = [
                        'config_id' => (int)$config_id,
                        'format' => 'html',
                        't' => time() // cache buster
                    ];

                    // Make internal request to the API for HTML format
                    $query = http_build_query($params);
                    $full_url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . '/' . $summaryScript . '?' . $query;

                    $ctx = stream_context_create(['http' => ['timeout' => 8]]);
                    $html_content = @file_get_contents($full_url, false, $ctx);
                    if ($html_content === false) {
                        $err = error_get_last();
                        throw new Exception('Failed to fetch summary table API: ' . ($err['message'] ?? 'unknown error'));
                    }

                    // Return HTML directly
                    echo json_encode([
                        'success' => true,
                        'html' => $html_content,
                        'config_name' => $config['name'],
                        'type' => 'summary_table'
                    ]);
                } else {
                    echo json_encode(['success' => false, 'message' => 'Configuration not found']);
                }
                
            } catch (Exception $e) {
                echo json_encode([
                    'success' => false,
                    'message' => 'Error loading summary table: ' . $e->getMessage()
                ]);
            }
        } else {
            echo json_encode(['success' => false, 'message' => 'Missing configuration ID']);
        }
        exit;
    }
    
    if (isset($_POST['action']) && $_POST['action'] === 'load_start_list') {
        $event_id = $_POST['event_id'] ?? null;
        $heat_number = $_POST['heat_number'] ?? null;
        $config_id = $_POST['config_id'] ?? null;
        
        if ($event_id) {
            try {
                // Use the same API endpoint as event_start_list.php
                $api_url = "api/start_list_api.php?event_id=" . $event_id;
                
                // Add heat filter if specified
                if ($heat_number) {
                    $api_url .= "&heat_number=" . $heat_number;
                }
                
                // Add config_id if specified
                if ($config_id) {
                    $api_url .= "&config_id=" . $config_id;
                }
                
                // Add format parameter for HTML (same as event_start_list.php)
                $api_url .= "&format=html";
                
                // Make internal request to the API
                $full_url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']) . '/' . $api_url;
                
                $html_content = file_get_contents($full_url);
                
                // Also get JSON data for processing
                $json_url = str_replace('&format=html', '&format=json', $full_url);
                $json_content = file_get_contents($json_url);
                $json_data = json_decode($json_content, true);
                
                echo json_encode([
                    'success' => true,
                    'data' => $json_data,
                    'html_content' => $html_content,
                    'heat_number' => $heat_number,
                    'type' => 'start_list'
                ]);
                
            } catch (Exception $e) {
                echo json_encode([
                    'success' => false,
                    'message' => 'Error loading start list: ' . $e->getMessage()
                ]);
            }
        } else {
            echo json_encode(['success' => false, 'message' => 'Missing event ID']);
        }
        exit;
    }

    echo json_encode(['success' => false, 'message' => 'Invalid action']);
    exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Live Event Dashboard</title>
    <!-- style skin holder -->
    <?php include_once 'includes/stylesheets.php'; ?>
    <style>
        <?php if (!empty($category_colors_data)): ?>
        /* Dynamic Category Colors */
        <?= generateCategoryColorsCSS($category_colors_data) ?>
        
        /* Category-specific enhancements for dashboard */
        .participant-card[data-category] {
            border-left: 4px solid var(--category-border-color, #dee2e6);
            transition: all 0.3s ease;
        }
        
        .participant-card[data-category]:hover {
            background-color: var(--category-bg-light, #f8f9fa);
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
        
        .category-badge-custom {
            display: inline-flex;
            align-items: center;
            gap: 4px;
            padding: 4px 8px;
            border-radius: 6px;
            font-size: 0.8rem;
            font-weight: 500;
        }
        
        .category-color-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            display: inline-block;
            border: 1px solid rgba(0,0,0,0.1);
        }
        <?php endif; ?>
        
        /* Modern gradient background for event header */
        .bg-gradient-primary {
            background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
        }
        
        /* Navbar customizations */
        .navbar-brand {
            font-size: 1.5rem;
        }
        
        .navbar-nav .nav-link {
            border-radius: 0.375rem;
            margin: 0 0.125rem;
            transition: all 0.2s ease;
        }
        
        .navbar-nav .nav-link:hover {
            background-color: rgba(255, 255, 255, 0.1);
            transform: translateY(-1px);
        }
        
        .navbar-nav .nav-link.active {
            background-color: rgba(255, 255, 255, 0.2);
            font-weight: 600;
        }
        
        .dropdown-menu {
            border: none;
            box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
            border-radius: 0.5rem;
        }
        
        /* Enhanced shadow for cards */
        .shadow-sm {
            box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.1) !important;
        }
        
        /* Modern rounded elements */
        .rounded-3 {
            border-radius: 0.75rem !important;
        }
        
        .rounded-pill {
            border-radius: 50rem !important;
        }
        
        /* Optimize layout for two-column design */
        .event-head-card {
            min-height: 400px;
            position: sticky;
            top: 20px;
            z-index: 10;
        }
        
        .heat-wrapper {
            
        }
        
        .heat-wrapper:empty {
            display: flex !important;
            align-items: center;
            justify-content: center;
            color: #6c757d;
        }
        
        .heat-wrapper:empty::before {
            content: "Select an event to view heat details";
            font-style: italic;
        }
        
        /* Compact event statistics */
        .event-head-card .row.g-2 > div {
            padding: 0.25rem;
        }
        
        .event-head-card .bg-opacity-10 {
            padding: 0.5rem !important;
        }
        
        .event-head-card .rounded-circle {
            width: 25px !important;
            height: 25px !important;
            font-size: 0.7rem;
        }
        
        /* Make heat details more compact */
        .heat-wrapper .card-body {
            padding: 0.75rem;
        }
        
        .heat-wrapper .border.rounded {
            padding: 0.75rem;
        }
        
        /* Apply consistent table styling */
        .table th {
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 10;
    font-weight: 600;
    font-size: .85em;
    text-transform: uppercase;
}
        
        .table td {
            border-color: #dee2e6;
            font-size: 0.875rem;
            padding: 0.5rem;
        }
        .data-table th, .data-table td {
            padding: 0.5em !important;
        }
        
        
        .summary-stats .badge {
            font-size: 0.7em;
        }
        
        /* Compact card styling */
        .card-body {
            padding: 1rem;
        }
        
        .card-body.p-2 {
            padding: 0.5rem !important;
        }
        
        .card-header {
            padding: 0.5rem 1rem;
        }
        
        .card-header.py-2 {
            padding-top: 0.5rem !important;
            padding-bottom: 0.5rem !important;
        }
        
        /* Table responsive with max height */
        .table-responsive {
            /* ...existing code... */
            overflow-y: auto;
            border: none;
            
        }
        /* NEW: non-blocking overlay for report-card refresh */
        .report-updating-overlay {
            pointer-events: none;
            z-index: 5;
        }
        /* Summary table row movement indicators */
        .summary-table tbody tr.moved-up td {
            animation: flashUp 1.2s ease;
        }
        .summary-table tbody tr.moved-down td {
            animation: flashDown 1.2s ease;
        }
        .summary-table tbody tr.changed td {
            animation: flashChange 2.4s ease;
        }
        .summary-table tbody tr.latest td {
    position: relative;
    background-color: rgba(0, 123, 255, 0.1);
}
.summary-table tbody tr.latest::before {   
    
}
.summary-table tbody tr.latest.moved-up td,
.summary-table tbody tr.latest.moved-down td,
.summary-table tbody tr.latest.changed td {
    animation: flashLatest 2.4s ease;
}
@keyframes flashLatest {
    0% { background-color: rgba(0, 123, 255, 0.3); }
    50% { background-color: rgba(0, 123, 255, 0.1); }
    100% { background-color: rgba(0, 123, 255, 0.2); }
}
        @keyframes flashUp {
            0% { background-color: rgba(40, 167, 69, 0.25); }
            100% { background-color: transparent; }
        }
        @keyframes flashDown {
            0% { background-color: rgba(220, 53, 69, 0.25); }
            100% { background-color: transparent; }
        }
        @keyframes flashChange {
            0% { background-color: rgba(255, 193, 7, 0.25); }
            25% { background-color: transparent; }
            50% { background-color: rgba(255, 193, 7, 0.25); }
            100% { background-color: transparent; }
        }
        .move-indicator {
            position: absolute;
            display: inline-flex;
            align-items: center;
            gap: 4px;
            margin-left: .5rem;
            font-size: .8rem;
        }

        .move-indicator.up { color: #28a745; }   /* green */
        .move-indicator.down { color: #dc3545; } /* red */
.summary-table tbody tr {
    transition: transform 1200ms ease, opacity 1200ms ease;
    will-change: transform, opacity;
}
td.col-best {
    background-color: var(--bs-table-bg) !important;
}
@keyframes heatRowUpdated {
    0% { background-color: rgba(13, 110, 253, 0.1); }
    100% { background-color: transparent; }
}

tr.heat-row-updated {
    animation: heatRowUpdated 2s ease;
}
/* Animation for live heat details updates */
@keyframes highlightUpdate {
    0% { background-color: rgba(255, 193, 7, 0.4); }
    100% { background-color: transparent; }
}
.fullscreen{
    overflow:auto
}

.fullscreen .navbar, .fullscreen .event-head-card, .fullscreen .card-general-reports  {
    display: none;
}

/* Hide toast notifications in fullscreen mode for clean presentation */
.fullscreen #toast-container {
    display: none;
}
.col-figures {
    width: 5%;
}
td.col-figures {
    font-size: .6em;

}
.animation-puls{animation: pulse-subtle 2s;}

@keyframes pulse-subtle {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.7; }
}

/* Participant Profile Photo Styles */
.participant-photo {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid #fff;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    transition: transform 0.2s ease;
}

.participant-photo:hover {
    transform: scale(1.1);
}

.participant-photo-placeholder {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-weight: bold;
    font-size: 14px;
    border: 2px solid #fff;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* Facts Icon Styles */
.facts-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
    color: #333;
    font-size: 12px;
    cursor: pointer;
    transition: all 0.2s ease;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    position: relative;
}

.facts-icon:hover {
    transform: scale(1.1);
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

/* Facts Tooltip Styles */
.facts-tooltip {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(5px);
    background: rgba(0,0,0,0.9);
    color: white;
    padding: 12px;
    border-radius: 8px;
    font-size: 12px;
    white-space: nowrap;
    max-width: 300px;
    z-index: 1000;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}

/* Default tooltip arrow pointing up (for bottom placement) */
.facts-tooltip::after {
    content: '';
    position: absolute;
    top: -6px;
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-bottom-color: rgba(0,0,0,0.9);
}

/* Alternative tooltip positioning for top placement when no space below */
.facts-tooltip.position-top {
    top: auto;
    bottom: 100%;
    transform: translateX(-50%) translateY(-5px);
}

.facts-tooltip.position-top::after {
    top: auto;
    bottom: -6px;
    border-bottom-color: transparent;
    border-top-color: rgba(0,0,0,0.9);
}

.facts-icon:hover .facts-tooltip {
    opacity: 1;
    visibility: visible;
}

.facts-icon:hover .facts-tooltip:not(.position-top) {
    transform: translateX(-50%) translateY(10px);
}

.facts-icon:hover .facts-tooltip.position-top {
    transform: translateX(-50%) translateY(-10px);
}

.fact-item {
    margin-bottom: 6px;
    padding-bottom: 6px;
    border-bottom: 1px solid rgba(255,255,255,0.2);
}

.fact-item:last-child {
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: none;
}

.fact-title {
    font-weight: bold;
    color: #ffd700;
    margin-bottom: 2px;
}

.fact-text {
    color: #fff;
    line-height: 1.3;
}
.p_media_info {
    display: flex;
    flex-direction: column;
    align-content: center;
    flex-wrap: nowrap;
    gap: 4px;
}

.pinned-card-popup img.participant-photo.me-2 {
    width: 90px;
    height: 90px;
    position: absolute;
    z-index: -1;
    top: -65px;
}
.pinned-card-popup .p_media_info {
    display: flex;
    flex-direction: row;
    align-content: flex-end;
    flex-wrap: wrap;
    gap: 4px;
    justify-content: flex-start;
    position: relative;
    top: 65px;
}
.pinned-card-popup .css-bib {   
    width: 40px !important;
    height: 40px !important;  
}
.navbar-brand-logo img {
    height: 35px;
}
    </style>
</head>

<body class="body-bg-aurora-bright">
     <?php 
     $hidenav = true;
    // Include essential scripts and notification system
    include_once __DIR__ . '/menu.php';
    ?>
    <!-- Sticky Navigation Bar -->
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top shadow-sm">
        <div class="container">
            <a class="navbar-brand navbar-brand-logo" href="index.php">
            <img src="<?php echo ASSETS_URL; ?>img/SVG/logo-ss-_2.svg" alt="Logo" class="me-2">
        </a>
            
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
                <span class="navbar-toggler-icon"></span>
            </button>
            
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav me-auto">
                    <li class="nav-item">
                        <a class="nav-link active" href="public_event_dashboard.php">
                            <i class="fas fa-chart-line me-1"></i>
                            Live Dashboard
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="index.php">
                            <i class="fas fa-home me-1"></i>
                            Events
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="toggleDashboardFullscreen()">
                            <i class="fas fa-expand me-1"></i>
                            Fullscreen
                        </a>
                    </li>
                </ul>
                
                <ul class="navbar-nav">
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle" href="#" id="refreshDropdown" role="button" data-bs-toggle="dropdown">
                            <i class="fas fa-cog me-1"></i>
                            Settings
                        </a>
                        <ul class="dropdown-menu dropdown-menu-end">
                            <li><h6 class="dropdown-header">Auto-Refresh</h6></li>
                            <li>
                                <div class="dropdown-item-text">
                                    <div class="form-check form-switch">
                                        <input class="form-check-input" type="checkbox" id="autoRefreshToggle" checked>
                                        <label class="form-check-label" for="autoRefreshToggle">
                                            Enable Auto-Refresh
                                        </label>
                                    </div>
                                </div>
                            </li>
                            <li><hr class="dropdown-divider"></li>
                            <li>
                                <div class="dropdown-item-text">
                                    <label for="refreshIntervalSelectxx" class="form-label small">Refresh Interval:</label>
                                    <select class="form-select form-select-sm" id="refreshIntervalSelectxx">
                                        <option value="5000">5 seconds</option>
                                        <option value="10000">10 seconds</option>
                                        <option value="30000" selected>30 seconds</option>
                                        <option value="60000">1 minute</option>
                                        <option value="300000">5 minutes</option>
                                    </select>
                                </div>
                            </li>
                        </ul>
                    </li>
                    <li class="nav-item">
                        <span class="navbar-text small" id="refreshIndicator">
                            <i class="fas fa-sync-alt text-success me-1"></i>
                            <span class="text-success">Auto-refresh: ON</span>
                        </span>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    
    <!-- Toast container for notifications -->
    <div id="toast-container" class="position-fixed top-0 end-0 p-3" style="z-index: 9999;">
        <!-- Toast notifications will be dynamically added here -->
    </div>
    
    <!-- Main content with top padding to account for sticky navbar -->
    <div style="padding-top: 20px;"></div>

    <div class="container container-StyleScore p-4">
        <div class="row mb-3">
            <div class="col-12">
                <div class="border-0 shadow-none card text-primary">
                    <div class="border-0 shadow-none card-body p-3">
                        <div class="d-flex justify-content-between align-items-center">
                            <div>
                                <h4 class="card-title mb-1"><i class="fas fa-tv me-2"></i>Live Event Dashboard</h4>
                                <p class="card-text mb-0 small opacity-75">Real-time event monitoring and results</p>
                            </div>
                            <div class="d-flex align-items-center gap-2">
                                <div class="d-flex align-items-center gap-2">
                                    <label for="refreshIntervalSelect" class="form-label mb-0 small">Refresh every</label>
                                    <select id="refreshIntervalSelect" class="form-select form-select-sm" style="width: auto;">
                                        <option value="5000">5s</option>
                                        <option value="10000">10s</option>
                                        <option value="30000" selected>30s</option>
                                        <option value="60000">1 min</option>
                                        <option value="300000">5 min</option>
                                    </select>
                                </div>
                                <div class="btn-group" role="group">
                                    <button type="button" class="btn btn-outline-light btn-sm" id="toggleRefresh"><i class="fas fa-pause me-1"></i>Pause Updates</button>
                                    <button type="button" class="btn btn-outline-light btn-sm" onclick="runRefreshCycle()"><i class="fas fa-sync-alt me-1"></i>Refresh Now</button>
                                    <button type="button" class="btn btn-outline-light btn-sm" onclick="toggleDashboardFullscreen()"><i class="fas fa-expand me-1"></i>Fullscreen</button>
                                    <button type="button" class="btn btn-outline-info btn-sm" onclick="testNotifications()" title="Test notification system"><i class="fas fa-bell me-1"></i>Test</button>
                                </div>
                                <small class="">Last updated: <span id="lastUpdate">Loading...</span></small>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div id="eventsContainer">
            <div class="col-12 text-center py-5">
                <div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading events...</span></div>
                <p class="mt-3">Loading events...</p>
            </div>
        </div>

        <div class="modal fade" id="summaryTableModal" tabindex="-1">
            <div class="modal-dialog modal-xl">
                <div class="modal-content">
                    <div class="modal-header py-2">
                        <h6 class="modal-title" id="modalSummaryTitle">Summary Table</h6>
                        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body p-2">
                        <div class="summary-display" id="summaryTableDisplay"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
<!-- Alpine Plugins -->
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/morph@3.x.x/dist/cdn.min.js"></script>
 
<!-- Alpine Core -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

     <script>
        // Minimal helper to patch only changed DOM instead of full re-render
        function morphHtml(targetEl, html) {
            if (!targetEl) return;
            window.morphdom ? morphdom(targetEl, html, { childrenOnly: true }) : (targetEl.innerHTML = html);
        }

        // Now calling the standalone API for data
        const DASH_API = 'api/public_dashboard_api.php';

        let autoRefresh = true;
        let refreshInterval;
        let refreshMs = Number(localStorage.getItem('dashboardRefreshMs')) || 30000; // NEW
        // Offset summary-card refresh to reduce layout jumps; default ~30% of main interval (clamped 300-2000ms)
        let reportRefreshOffsetMs = Math.max(300, Math.min(2000, Math.floor(refreshMs * 0.3)));
        // Small jitter so multiple report-cards don’t refresh at the exact same moment
        let reportRefreshJitterMs = 250;
        let currentEventId = null;
        let currentConfigId = null;
        let openHeatContainers = new Set(); // Track which heat containers are open
        let activeReports = new Map(); // Track active reports in heat cards
        
        // Global category colors for dynamic styling
        const categoryColors = <?= json_encode($category_colors_data) ?>;
        
        // Debug: Log category colors on load
        console.log('Category colors loaded:', categoryColors);
        
        document.addEventListener('DOMContentLoaded', function() {
            // Initialize dashboard components
            initializeDashboard();
            
            // Show welcome notification after notification system is ready
            setTimeout(() => {
                if (window.notifySuccess) {
                    window.notifySuccess('Dashboard Ready', 'Public event dashboard loaded successfully');
                } else {
                    console.log('Dashboard loaded - notification system not yet available');
                }
            }, 2000);
            
            // Log notification system status
            setTimeout(() => {
                if (window.globalNotificationManager) {
                    console.log('Notification Manager Status:', {
                        eventId: window.globalNotificationManager.eventId,
                        localMode: window.globalNotificationManager.localMode,
                        apiAvailable: window.globalNotificationManager.apiAvailable,
                        pollingRate: window.globalNotificationManager.pollingRate,
                        connectionStatus: window.globalNotificationManager.connectionStatus
                    });
                } else {
                    console.log('Global notification manager not available');
                }
            }, 3000);
            
            // Init interval select
            const sel = document.getElementById('refreshIntervalSelect');
            if (sel) {
                // set current value
                if ([5000,10000,30000,60000,300000].includes(refreshMs)) {
                    sel.value = String(refreshMs);
                } else {
                    refreshMs = 30000;
                    sel.value = '30000';
                }
                sel.addEventListener('change', function() {
                    refreshMs = Number(this.value) || 30000;
                    localStorage.setItem('dashboardRefreshMs', String(refreshMs));
                    // Recalculate offset when interval changes
                    reportRefreshOffsetMs = Math.max(300, Math.min(2000, Math.floor(refreshMs * 0.3)));
                    if (autoRefresh) {
                        startAutoRefresh(); // restarts with new interval/offset
                        if (window.notifyInfo) {
                            window.notifyInfo('Refresh Interval Changed', `Now refreshing every ${getHumanIntervalLabel(refreshMs)}`);
                        }
                    } else {
                        updateRefreshIndicator();
                    }
                });
            }

            // Start auto-refresh
            startAutoRefresh();
            
            // Initialize Font Awesome to Lucide conversion and icons on page load
            if (window.convertFontAwesomeToLucide) {
                console.log('Initial page load: Converting Font Awesome icons to Lucide...');
                const converted = window.convertFontAwesomeToLucide();
                console.log('Initial page load: Converted', converted, 'Font Awesome icons');
            }
            if (window.initializeLucideIcons) {
                console.log('Initial page load: Initializing Lucide icons...');
                window.initializeLucideIcons();
            }
            
            // Initial load using staggered cycle
            runRefreshCycle();
            
            // Auto-refresh toggle in navbar
            const autoRefreshToggle = document.getElementById('autoRefreshToggle');
            if (autoRefreshToggle) {
                autoRefreshToggle.checked = autoRefresh;
                autoRefreshToggle.addEventListener('change', function() {
                    if (this.checked) {
                        autoRefresh = true;
                        startAutoRefresh();
                        if (window.notifySuccess) {
                            window.notifySuccess('Auto-Refresh ON', `Refreshing every ${getHumanIntervalLabel(refreshMs)}`);
                        }
                    } else {
                        autoRefresh = false;
                        stopAutoRefresh();
                        if (window.notifyWarning) {
                            window.notifyWarning('Auto-Refresh OFF', 'Manual refresh required');
                        }
                    }
                    updateRefreshIndicator();
                });
            }
        });
        
        function getHumanIntervalLabel(ms) { // NEW
            return ms >= 60000 ? (ms/60000) + ' min' : (ms/1000) + 's';
        }

        function updateRefreshIndicator() { // NEW
            const el = document.getElementById('refreshIndicator');
            if (!el) return;
            if (autoRefresh) {
                el.innerHTML = `<i class="fas fa-sync-alt text-success me-1"></i><span class="text-success">Auto-refresh: ON (${getHumanIntervalLabel(refreshMs)})</span>`;
            } else {
                el.innerHTML = '<i class="fas fa-pause text-warning me-1"></i><span class="text-warning">Auto-refresh: OFF</span>';
            }
            
            // Convert and initialize Lucide icons for the refresh indicator
            if (window.convertFontAwesomeToLucide) {
                window.convertFontAwesomeToLucide();
            }
            if (window.initializeLucideIcons) {
                window.initializeLucideIcons();
            }
        }

        function startAutoRefresh() {
            stopAutoRefresh(); // restart with current refreshMs
            refreshInterval = setInterval(runRefreshCycle, refreshMs);
            startHeatDetailsRefresh(); // Start the heat details refresh
            startLatestUpdatesRefresh(); // Start the latest updates refresh
            updateRefreshIndicator();
        }

        // Run one full refresh cycle: main first, then reports after an offset
        function runRefreshCycle() {
            refreshAllData();
            // Stagger summary-cards refresh to reduce LCP/CLS and visual jumps
            setTimeout(() => {
                refreshActiveReportsAuto();
            }, reportRefreshOffsetMs);
        }

        // NEW: auto-refresh any open report-cards unless paused per-card
        function refreshActiveReportsAuto() {
            if (!autoRefresh) return;
            // Spread refreshes with a small jitter per card
            activeReports.forEach((rep, key) => {
                if (rep && rep.auto !== false) {
                    const jitter = reportRefreshJitterMs ? Math.floor(Math.random() * reportRefreshJitterMs) : 0;
                    setTimeout(() => {
                        refreshReport(key);
                    }, jitter);
                }
            });
        }

        // NEW: toggle auto-refresh per report card
        function toggleReportAuto(reportKey) {
            const rep = activeReports.get(reportKey);
            if (!rep) return;
            rep.auto = rep.auto === false ? true : false;
            activeReports.set(reportKey, rep);
            // Re-render header controls to reflect new state without closing the card
            const [eventId, heatPart] = reportKey.split('-');
            const heatNumber = heatPart === 'all' ? null : Number(heatPart);
            if (rep.type === 'summary_table') {
                // re-render just the header by refreshing the report (keeps holder open)
                loadSummaryTableCard(Number(eventId), heatNumber, rep.configId, rep.configName, { refresh: true });
            } else if (rep.type === 'start_list') {
                loadStartListCard(Number(eventId), heatNumber, { refresh: true, config_id: rep.configId });
            }
        }
        
        function stopAutoRefresh() {
            if (refreshInterval) {
                clearInterval(refreshInterval);
                refreshInterval = null;
            }
            stopHeatDetailsRefresh(); // Stop the heat details refresh
            stopLatestUpdatesRefresh(); // Stop the latest updates refresh
        }
        
        function refreshAllData() {
            loadEventsOverview();
            updateLastUpdateTime();
        }
        
        function updateLastUpdateTime() {
            document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString();
        }
        
        function loadEventsOverview() {
            fetch(`${DASH_API}?action=get_events_overview`, { method: 'GET' })
                .then(r => r.json())
                .then(data => {
                    if (data.success) {
                        displayEvents(data.events);
                        // Remove notification for auto-refresh to prevent spam
                        // if (window.notifySuccess && data.events.length > 0) {
                        //     window.notifySuccess('Events Loaded', `${data.events.length} active event(s) found`);
                        // }
                    } else {
                        console.error('Error loading events:', data.message);
                        morphHtml(document.getElementById('eventsContainer'),
                            '<div class="col-12 py-2"><div class="alert alert-danger">Error loading events: ' + (data.message||'Unknown') + '</div></div>');
                        if (window.notifyError) {
                            window.notifyError('Events Load Failed', data.message || 'Unknown error occurred');
                        }
                    }
                })
                .catch(error => {
                    console.error('Error:', error);
                    morphHtml(document.getElementById('eventsContainer'),
                        '<div class="col-12 py-2"><div class="alert alert-danger">Network error loading events</div></div>');
                    if (window.notifyError) {
                        window.notifyError('Network Error', 'Failed to connect to server');
                    }
                });
        }
        
        async function displayEvents(events) {
            const container = document.getElementById('eventsContainer');
            
            // Helper function to validate if participant data is complete and valid
            function isValidParticipantData(data) {
                return data && 
                       data.bib_number && 
                       data.name && 
                       data.judge_scores && 
                       data.judge_scores.length > 0;
            }
            
            // Helper function to validate if next participant data is complete
            function isValidNextParticipantData(data) {
                return data && 
                       data.bib_number && 
                       data.first_name && 
                       data.last_name;
            }
            
            // Preserve existing heat container contents for open events to avoid flicker & reload delay
            const existingHeats = {};
            openHeatContainers.forEach(id => {
                const el = document.getElementById('heats-' + id);
                if (el) existingHeats[id] = el.innerHTML;
            });

            // Preserve existing latest updates content to avoid clearing populated data
            const existingLatestUpdates = {};
            events.forEach(event => {
                const latestScoreEl = document.getElementById(`latest-score-${event.id}`);
                const performingNowEl = document.getElementById(`performing-now-${event.id}`);
                const nextOnStartEl = document.getElementById(`next-on-start-${event.id}`);
                
                if (latestScoreEl) {
                    existingLatestUpdates[`latest-score-${event.id}`] = {
                        content: latestScoreEl.innerHTML,
                        visible: latestScoreEl.style.display !== 'none'
                    };
                }
                if (performingNowEl) {
                    existingLatestUpdates[`performing-now-${event.id}`] = {
                        content: performingNowEl.innerHTML,
                        visible: performingNowEl.style.display !== 'none'
                    };
                }
                if (nextOnStartEl) {
                    existingLatestUpdates[`next-on-start-${event.id}`] = {
                        content: nextOnStartEl.innerHTML,
                        visible: nextOnStartEl.style.display !== 'none'
                    };
                }
            });

            if (events.length === 0) {
                morphHtml(container, '<div class="col-12 py-2"><div class="alert alert-info">No active events found</div></div>');
                return;
            }

            let html = '';
            
            // Process events sequentially to get latest scores
            for (const event of events) {
                const isLive = ['in_progress','live'].includes(event.status);
                const nextBib = isValidNextParticipantData(event.next_bib) ? event.next_bib : null;
                const isHeatContainerOpen = openHeatContainers.has(event.id);
                
                // Get detailed latest score data with all judge scores
                const latestScore = await getLatestScoredParticipant(event.id);
                
                // Auto-open heat containers for all events on page load
                if (!isHeatContainerOpen) {
                    openHeatContainers.add(event.id);
                }
                
                html += `
                <div class="row mb-3">
                    <div class="col-12">
                    
                        <div class="event-head-card card mb-3 border-0 shadow-none" id="event-${event.id}">
                    <div class="border-0 shadow-none card-header bg-gradient-primary text-white border-0 position-relative overflow-hidden py-2">
                        <div class="position-absolute top-0 end-0 opacity-10" style="font-size: 4rem; line-height: 1; color: rgba(255,255,255,0.1);">
                            <i class="fas fa-trophy"></i>
                        </div>
                        <div class="row align-items-center position-relative">
                            <div class="col-md-8">
                                <h5 class="mb-1 fw-bold">
                                    <i class="fas fa-calendar-check me-2"></i>
                                    ${event.name}
                                </h5>
                                <p class="mb-0 text-white-50 small">
                                    <i class="fas fa-calendar me-1"></i>
                                    ${new Date(event.date).toLocaleDateString('en-US', { 
                                        weekday: 'long', 
                                        year: 'numeric', 
                                        month: 'long', 
                                        day: 'numeric' 
                                    })}
                                </p>
                            </div>
                            <div class="col-md-4 text-end">
                                <div class="d-flex flex-column align-items-end gap-1">
                                    ${isLive ? '<span class="badge bg-danger px-2 py-1 rounded-pill"><i class="fas fa-broadcast-tower me-1"></i>LIVE EVENT</span>' : ''}
                                    <span class="badge bg-light text-dark px-2 py-1 rounded-pill">
                                        <i class="fas fa-info-circle me-1"></i>
                                        ${event.status.replace('_',' ').toUpperCase()}
                                    </span>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="border-0 shadow-none card-body p-3">
                        <!-- Event Statistics Row -->
                        <div class="row g-2 mb-3">
                        <div class="row">
                            <div class="col-4">
                                <div class="d-flex align-items-center p-2 bg-primary bg-opacity-10 rounded">
                                    <div class="bg-primary text-white rounded-circle p-2 me-2" style="width: 35px; height: 35px; display: flex; align-items-center; justify-content: center;">
                                        <i class="fas fa-fire"></i>
                                    </div>
                                    <div>
                                        <div class="fw-bold text-primary">${event.current_heat_name || event.current_heat || '—'}</div>
                                        <small class="text-muted">Active Heat</small>
                                    </div>
                                </div>
                            </div>
                            <div class="col-4">
                                <div class="d-flex align-items-center p-2 bg-success bg-opacity-10 rounded">
                                    <div class="bg-success text-white rounded-circle p-2 me-2" style="width: 35px; height: 35px; display: flex; align-items-center; justify-content: center;">
                                        <i class="fas fa-play"></i>
                                    </div>
                                    <div>
                                        <div class="fw-bold text-success">${event.current_run || '—'}</div>
                                        <small class="text-muted">Current Run</small>
                                    </div>
                                </div>
                            </div>
                            <div class="col-4">
                                <div class="d-flex align-items-center p-2 bg-info bg-opacity-10 rounded">
                                    <div class="bg-info text-white rounded-circle p-2 me-2" style="width: 35px; height: 35px; display: flex; align-items: center; justify-content: center;">
                                        <i class="fas fa-users"></i>
                                    </div>
                                    <div>
                                        <div class="fw-bold text-info">${event.total_participants || 0}</div>
                                        <small class="text-muted">Athletes</small>
                                    </div>
                                </div>
                            </div>
                           </div>
                           <div class="row">
                            <!-- Latest Score - in same row -->
                            <div class="col-4" id="latest-score-${event.id}">
                                <div class="border-0 shadow-none bg-success bg-opacity-10 h-100 p-2 rounded">
                                    <div class="text-center py-2 text-muted">
                                        <i class="fas fa-clock fs-4 mb-1"></i>
                                        <p class="mb-0 small">No scores yet</p>
                                    </div>
                                </div>
                            </div>
                            
                            <!-- PERFORMING NOW - in same row -->
                            <div class="col-4" id="performing-now-${event.id}">
                                <div class="border-0 shadow-none bg-warning bg-opacity-10 h-100 p-2 rounded">
                                    <div class="text-center py-2 text-muted">
                                        <i class="fas fa-pause-circle fs-4 mb-1"></i>
                                        <p class="mb-0 small">No one performing</p>
                                    </div>
                                </div>
                            </div>
                            
                            <!-- Next on Start - in same row -->
                            <div class="col-4" id="next-on-start-${event.id}">
                                <div class="border-0 shadow-none bg-primary bg-opacity-10 h-100 p-2 rounded">
                                    <div class="text-center py-2 text-muted">
                                        <i class="fas fa-users fs-4 mb-1"></i>
                                        <p class="mb-0 small">No participants waiting</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                        </div>
                        <!-- Action Button -->
                        <div class="row">
                         <div class="col-md-4 id="performing-now-${event.id}">
                        <div class="text-center">
                                <div class="border-0 shadow-none card border-0 bg-success bg-opacity-10 h-100">
                                    <div class="border-0 shadow-none card-body p-2">
                                        
                                        <div class="text-center py-3 text-muted">
                                            <i class="fas fa-clock fs-2 mb-2"></i>
                                            <p class="mb-0 small">No scores yet</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            </div>
                            <!-- PERFORMING NOW Section -->
                            <div class="col-md-4" id="performing-now-${event.id}">
                                <div class="border-0 shadow-none card border-0 bg-warning bg-opacity-10 h-100">
                                    <div class="border-0 shadow-none card-body p-2">
                                        <div class="d-flex align-items-center mb-2">
                                            
                                            <h6 class="mb-0 text-warning fw-bold">PERFORMING NOW</h6>
                                        </div>
                                        <div class="text-center py-3 text-muted">
                                            <i class="fas fa-pause-circle fs-2 mb-2"></i>
                                            <p class="mb-0 small">No one performing</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            
                            <!-- Next on Start Section -->
                            <div class="col-md-4" id="next-on-start-${event.id}">
                                <div class="border-0 shadow-none card border-0 bg-primary bg-opacity-10 h-100">
                                    <div class="border-0 shadow-none card-body p-2">
                                        <div class="d-flex align-items-center mb-2">
                                            <div class="bg-primary text-white rounded-circle p-1 me-2" style="width: 30px; height: 30px; display: flex; align-items-center; justify-content: center;">
                                                <i class="fas fa-play"></i>
                                            </div>
                                            <h6 class="mb-0 text-primary fw-bold">Next on Start</h6>
                                        </div>
                                        <div class="text-center py-3 text-muted">
                                            <i class="fas fa-users fs-2 mb-2"></i>
                                            <p class="mb-0 small">No participants waiting</p>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        </div>
                        <!-- Action Button -->
                        <div class="text-center">
                            <button class="btn btn-primary px-2 py-1 rounded-pill shadow-none" onclick="loadEventHeats(${event.id}, '${event.name.replace(/'/g,"&apos;")}')">
                                <i class="fas fa-fire me-1"></i>
                                Hide Heat Details
                            </button>
                        </div>
                    </div>
                </div>
                    </div>
                    <div class="col-12">
                        <!-- Heats Wrapper -->
                        <div id="heats-${event.id}" class="heat-wrapper" style="display:block;">
                            ${openHeatContainers.has(event.id) ? (existingHeats[event.id] || "<div class='text-center py-2'><div class='spinner-border spinner-border-sm text-primary' role='status'></div><p class='mt-1 text-muted small'>Loading heat details...</p></div>") : "<div class='text-center py-2'><div class='spinner-border spinner-border-sm text-primary' role='status'></div><p class='mt-1 text-muted small'>Loading heat details...</p></div>"}
                        </div>
                    </div>
                </div>`;
            }

            morphHtml(container, html);

            // Restore preserved latest updates content to prevent clearing populated data
            Object.keys(existingLatestUpdates).forEach(elementId => {
                const el = document.getElementById(elementId);
                const preserved = existingLatestUpdates[elementId];
                
                if (el && preserved && preserved.content) {
                    // Only restore if the existing content is not empty placeholders and card was visible
                    const existingContent = preserved.content;
                    const wasVisible = preserved.visible;
                    
                    if (!existingContent.includes('No scores yet') && 
                        !existingContent.includes('No one performing') && 
                        !existingContent.includes('No participants waiting') &&
                        wasVisible) {
                        el.innerHTML = existingContent;
                        el.style.display = 'block'; // Ensure it's visible when restoring content
                    }
                }
            });

            // Auto-load heat details for all events on page load
            for (const event of events) {
                // Only trigger load if not already preserved or if content looks like loading
                const el = document.getElementById('heats-' + event.id);
                if (el && (!existingHeats[event.id] || /Loading heat details|Refreshing heat details|spinner/.test(el.innerHTML))) {
                    loadEventHeatsData(event.id, event.name);
                }
                
                // Update latest score display for each event
                getLatestScoredParticipant(event.id)
                    .then(latestParticipant => {
                        if (latestParticipant) {
                            updateLatestScoreDisplay(event.id, latestParticipant);
                        }
                    })
                    .catch(error => {
                        console.log('Error getting latest scored participant during initial load for event ' + event.id + ':', error);
                    });
            }
        }
        
        function showEventDetails(eventId, eventName) {
            // This function is kept for backward compatibility but redirects to loadEventHeats
            loadEventHeats(eventId, eventName);
        }
        
        function loadEventHeats(eventId, eventName) {
            const container = document.getElementById(`heats-${eventId}`);
            if (container.style.display === 'none') {
                openHeatContainers.add(eventId);
                container.style.display = 'block';
                loadEventHeatsData(eventId, eventName);
            } else {
                openHeatContainers.delete(eventId);
                activeReports.delete(`${eventId}`);
                container.style.display = 'none';
            }
        }
        
        function loadEventHeatsData(eventId, eventName) {
            const container = document.getElementById(`heats-${eventId}`);
            morphHtml(container, '<div class="text-center py-2"><div class="spinner-border spinner-border-sm" role="status"></div><p class="mt-1 small">Loading heat details...</p></div>');
            
            fetch(`${DASH_API}?action=get_event_heats&event_id=${encodeURIComponent(eventId)}`, { method: 'GET' })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        displayHeats(eventId, eventName, data.heats, data.configurations); // pass eventName
                    } else {
                        morphHtml(container, '<div class="alert alert-danger">Error loading heats: ' + (data.message||'Unknown') + '</div>');
                    }
                })
                .catch(error => {
                    console.error('Error:', error);
                    morphHtml(container, '<div class="alert alert-danger">Network error loading heats</div>');
                });
        }
        
        function refreshGeneralReports(eventId) {
            fetch(`${DASH_API}?action=get_configurations&event_id=${encodeURIComponent(eventId)}`, { method: 'GET' })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        updateGeneralReports(eventId, data.configurations);
                    } else {
                        console.error('Error refreshing reports:', data.message);
                    }
                })
                .catch(error => {
                    console.error('Error refreshing reports:', error);
                });
        }
        // Renders heats table + per-heat report containers and event-level General Reports
        function displayHeats(eventId, eventName, heats, configurations) { // accept eventName
            const container = document.getElementById(`heats-${eventId}`);
            if (!container) return;

            // helper to build clean button text
            const cleanBtnText = (cfgName, evtName, heatName, viewType) => {
                const parts = String(cfgName || '')
                    .split(/\s*-\s*/).filter(Boolean)
                    .filter(p => {
                        const t = p.trim();
                        if (!t) return false;
                        if (evtName && t.localeCompare(evtName, undefined, { sensitivity: 'accent' }) === 0) return false;
                        if (/^heat\s*\d+$/i.test(t)) return false;            // remove "Heat 1"
                        if (/^summary\s*table$/i.test(t)) return false;       // remove "Summary Table"
                        if (/^start\s*list$/i.test(t)) return false;          // remove "Start List"
                        return true;
                    });
                const extra = parts.join(' - ');
                const base = (heatName && String(heatName).trim()) ? heatName : '';
                return extra ? (base ? `${base} - ${extra}` : extra) : (base || 'Report');
            };

            // Group configurations by heat_number (or 'all' for general configs)
            const configsByHeat = {};
            (configurations || []).forEach(cfg => {
                const key = cfg.heat_number ? String(cfg.heat_number) : 'all';
                (configsByHeat[key] ||= []).push(cfg);
            });

            if (!heats || heats.length === 0) {
                morphHtml(container, `
                    <div class="border-0 shadow-none card mb-2">
                        <div class="border-0 shadow-none bg-transparent py-2"><strong>Heat Details</strong></div>
                        <div class="border-0 shadow-none card-body p-2"><div class="alert alert-info mb-0 py-2">No heats configured for this event</div></div>
                    </div>
                `);
                return;
            }

            let html = `
                <div class="card-general-reports border border-2 mb-2 p-3 rounded rounded-3">
                    <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                        <small class="text-uppercase fw-bold"><i class="fas fa-folder-open me-1"></i>General Reports</small>
                        <button class="btn btn-sm btn-outline-secondary" onclick="refreshGeneralReports(${eventId})">
                            <i class="fas fa-sync-alt"></i>
                        </button>
                    </div>
                    <div class="border-0 shadow-none card-body p-3" id="general-reports-${eventId}">
                        <div class="text-muted small">Loading general reports…</div>
                    </div>
                </div>
                <!-- Heats Details -->
                <div class="border-0 shadow-none card">
                    <div class="border-0 shadow-none bg-transparent p-3"><strong>Heat Details</strong></div>
                    <div class="border-0 shadow-none card-body p-2">
                    
                    `;
            // Render each heat
            heats.forEach(heat => {
                const completion = heat.expected_scores > 0
                    ? Math.round((Number(heat.total_scores || 0) / Number(heat.expected_scores)) * 100)
                    : 0;
                const progressClass = completion >= 100 ? 'bg-success' : (completion >= 50 ? 'bg-warning' : 'bg-primary');
                const heatStatusClass = Number(heat.is_active) === 1 ? 'bg-danger' : (completion >= 100 ? 'bg-success' : 'bg-secondary');
                const heatStatusText = Number(heat.is_active) === 1 ? 'Live' : (completion >= 100 ? 'Completed' : 'Upcoming');

                // Build a compact list of report actions
                const heatConfigs = (configsByHeat[String(heat.heat_number)] || []);
                const reportButtons = heatConfigs.map(cfg => {
                    const isSummary = cfg.view_type === 'summary_table';
                    const isStart = cfg.view_type === 'start_list';
                    const icon = isSummary ? 'fa-table' : (isStart ? 'fa-users' : 'fa-file');
                    const color = isSummary ? 'info' : (isStart ? 'success' : 'secondary');
                    const handler = isSummary
                        ? `loadSummaryTableCard(${eventId}, ${heat.heat_number}, ${cfg.id}, '${String(cfg.name).replace(/'/g, "\\'")}')`
                        : (isStart ? `loadStartListCard(${eventId}, ${heat.heat_number})` : '');
                    if (!handler) return '';
                    const btnText = cleanBtnText(cfg.name, eventName, heat.heat_name, cfg.view_type);
                    const safeText = String(btnText).replace(/&/g,'&amp;').replace(/</g,'&lt;');
                    return `<button class="btn btn-sm btn-${color} me-1 mb-1" onclick="${handler}" title="${safeText}"><i class="fas ${icon}"></i></button>`;
                }).filter(Boolean).join('');

                html += `<!-- Single Heat Details -->
                    <div class="border border-2 mb-3 p-3 rounded rounded-3" id="event-${eventId}-heat-${heat.heat_number}">
                        <div class="row align-items-center">
                            <div class="col-md-6">
                                <div class="d-flex align-items-center">
                                    <span class="badge ${heatStatusClass} me-2 px-2 py-1">${heatStatusText}</span>
                                    <div class="d-flex d-flex flex-column">
                                        <div class="d-flex gap-3">
                                            <div class="text-muted small">Heat ${heat.heat_number}</div>
                                            ${heat.heat_name ? `<strong class="h5 mb-0">${heat.heat_name}</strong>` : ''}
                                        </div>
                                        <div class="text-muted small">
                                            <i class="fas fa-clock me-1"></i>${heat.time_start ? (() => {
                                                try {
                                                    // If time_start is in HH:MM:SS format, format it to HH:MM
                                                    if (typeof heat.time_start === 'string' && heat.time_start.includes(':')) {
                                                        const timeParts = heat.time_start.split(':');
                                                        if (timeParts.length >= 2) {
                                                            const hours = timeParts[0].padStart(2, '0');
                                                            const minutes = timeParts[1].padStart(2, '0');
                                                            return `${hours}:${minutes}`;
                                                        }
                                                    }
                                                    // Fallback: return as-is
                                                    return heat.time_start;
                                                } catch (e) {
                                                    console.warn('Error formatting time_start:', e);
                                                    return heat.time_start;
                                                }
                                            })() : 'No time set'}
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-2 text-center">
                                <div class="d-flex flex-column align-items-center">
                                    <div class="align-items-md-center d-flex gap-1">
                                        <div class="bg-primary text-white rounded-circle p-2 mb-1" style="width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;">
                                            <span class="text-white">${heat.participants || 0}</span>
                                        </div>
                                        <small class="text-muted">Athletes</small>
                                        </div>
                                        
                                </div>
                            </div>
                            <div class="col-md-3">
                                <div class="text-center">
                                    <div class="progress mb-1" style="height:8px;">
                                        <div class="progress-bar ${progressClass}" style="width:${completion}%;"></div>
                                    </div>
                                    <small class="fw-bold ${completion >= 100 ? 'text-success' : 'text-muted'}">${completion}% Complete</small>
                                </div>
                            </div>
                            <div class="col-md-1 text-end">
                                <button class="btn btn-sm btn-outline-secondary rounded-circle" onclick="toggleHeatDetails(${eventId}, ${heat.heat_number})" title="Toggle Details">
                                    <i class="fas fa-chevron-down"></i>
                                </button>
                            </div>
                        </div>
                        
                        <!-- Categories Info -->
                        <div class="row mt-2 pt-2 border-top">
                            <div class="col-12">
                                <div class="d-flex align-items-center gap-2">
                                    <small class="text-muted fw-bold">Categories:</small>
                                    ${(() => {
                                        if (heat.category_names && Array.isArray(heat.category_names) && heat.category_names.length > 0) {
                                            return heat.category_names.map(categoryName => {
                                                const colors = (categoryColors && categoryColors[categoryName]) || {};
                                                const badgeStyle = colors['background-color'] ? 
                                                    `background-color: ${colors['background-color']}; color: ${colors['color'] || '#fff'}; border: 1px solid ${colors['border-color'] || '#000'};` : 
                                                    'background-color: #0dcaf0; color: #000;';
                                                return `<span class="badge" style="${badgeStyle}">${categoryName}</span>`;
                                            }).join(' ');
                                        }
                                        try { 
                                            const cats = heat.categories ? JSON.parse(heat.categories) : null;
                                            if (cats && Array.isArray(cats)) {
                                                return "<span class=\"badge bg-info scale-bg-" + cats.length + "\">" + (cats.length > 0 ? cats.join(', ') : 'All') + "</span>";
                                            } else {
                                                return "<span class=\"badge bg-info\">" + (heat.categories || 'All') + "</span>";
                                            }
                                        } catch(e) { 
                                            return "<span class=\"badge bg-info\">" + (heat.categories || 'All') + "</span>";
                                        }
                                    })()}
                                </div>
                            </div>
                        </div>
                        
                        <!-- Heat Reports Buttons -->
                        ${heatConfigs.length > 0 ? `
                        <div class="row mt-2 pt-2 border-top">
                            <div class="col-12">
                                <div class="d-flex align-items-center justify-content-between mb-3">
                                    <small class="text-muted fw-bold">Available Reports:</small>
                                </div>
                                <div class="row g-3">
                                    <!-- Start Lists Column -->
                                    <div class="col-md-6">
                                        <div class="d-flex align-items-center mb-2">
                                            <i class="fas fa-users text-success me-2"></i>
                                            <small class="text-muted fw-bold">Start Lists</small>
                                        </div>
                                        <div class="d-flex flex-column gap-2">
                                            ${heatConfigs.filter(cfg => cfg.view_type === 'start_list').map(cfg => {
                                                const handler = `loadStartListCard(${eventId}, ${heat.heat_number})`;
                                                const btnText = cleanBtnText(cfg.name, eventName, heat.heat_name, cfg.view_type);
                                                const safeText = String(btnText).replace(/&/g,'&amp;').replace(/</g,'&lt;');
                                                return `<button class="btn btn-outline-success btn-sm w-100 text-start" onclick="${handler}" title="${safeText}">
                                                    <i class="fas fa-users me-2"></i>${safeText}
                                                    <span class="badge ${heatStatusClass} float-end">${heatStatusText}</span>
                                                </button>`;
                                            }).join('') || '<div class="text-muted small">No start lists available</div>'}
                                        </div>
                                    </div>
                                    
                                    <!-- Summary Tables Column -->
                                    <div class="col-md-6">
                                        <div class="d-flex align-items-center mb-2">
                                            <i class="fas fa-table text-info me-2"></i>
                                            <small class="text-muted fw-bold">Summary Tables</small>
                                        </div>
                                        <div class="d-flex flex-column gap-2">
                                            ${heatConfigs.filter(cfg => cfg.view_type === 'summary_table').map(cfg => {
                                                const handler = `loadSummaryTableCard(${eventId}, ${heat.heat_number}, ${cfg.id}, '${String(cfg.name).replace(/'/g, "\\'")}')`;
                                                const btnText = cleanBtnText(cfg.name, eventName, heat.heat_name, cfg.view_type);
                                                const safeText = String(btnText).replace(/&/g,'&amp;').replace(/</g,'&lt;');
                                                return `<button class="btn btn-outline-info btn-sm w-100 text-start" onclick="${handler}" title="${safeText}">
                                                    <i class="fas fa-table me-2"></i>${safeText}
                                                    <span class="badge ${heatStatusClass} float-end">${heatStatusText}</span>
                                                </button>`;
                                            }).join('') || '<div class="text-muted small">No summary tables available</div>'}
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        ` : ''}
                        
                        <!-- Heat Details Expandable Section -->
                        <div id="heat-details-${eventId}-${heat.heat_number}" style="display:none;" class="mt-2 pt-2 border-top">
                            <div class="row g-2 small" id="heat-details-live-${eventId}-${heat.heat_number}">
                                <div class="col-12 mt-2">
                                    <div class="report-cards" id="report-cards-${eventId}-${heat.heat_number}"></div>
                                </div>
                            </div>
                        </div>
                    </div>`;
            });

            html += `
                    </div>
                </div>`;
            morphHtml(container, html);

            // Populate General Reports area for event-level configs (heat_number null)
            updateGeneralReports(eventId, configurations);

            // Restore any open report cards
            activeReports.forEach((rep, key) => {
            if (!key.startsWith(`${eventId}-`)) return;
            const parts = key.split('-'); // NEW parsing
            const heatPart = parts[1];
            const heatNum = heatPart === 'all' ? 'all' : String(heatPart);
            const holder = (heatNum === 'all')
                ? (document.getElementById(`general-report-cards-${eventId}`) || document.getElementById(`report-cards-${eventId}-all`))
                : document.getElementById(`report-cards-${eventId}-${heatNum}`);
            if (holder && rep.html) {
                morphHtml(holder, rep.html);
                if (heatNum !== 'all') {
                    const row = document.getElementById(`heat-details-${eventId}-${heatNum}`);
                    if (row) row.style.display = '';
                }
            }
        });
        }

        function toggleHeatDetails(eventId, heatNumber) {
            const row = document.getElementById(`heat-details-${eventId}-${heatNumber}`);
            const btn = document.querySelector(`#event-${eventId}-heat-${heatNumber} button[onclick*="toggleHeatDetails"]`);
            if (!row) return;
            
            const isVisible = row.style.display !== 'none';
            row.style.display = isVisible ? 'none' : 'block';
            
            // Update button icon
            if (btn) {
                const icon = btn.querySelector('i');
                if (icon) {
                    icon.className = isVisible ? 'fas fa-chevron-down' : 'fas fa-chevron-up';
                }
            }
        }

        // Event-level General Reports (heat_number null)
        function updateGeneralReports(eventId, configurations = []) {
            const container = document.getElementById(`general-reports-${eventId}`);
            if (!container) return;

            const oldHolder = document.getElementById(`general-report-cards-${eventId}`);
            const oldHtml = oldHolder ? oldHolder.innerHTML : '';

            const general = configurations.filter(c => !c.heat_number);
            if (general.length === 0) {
                morphHtml(container, `<div class="text-muted small">No general reports available</div>`);
                return;
            }

            const summaryTables = general.filter(c => c.view_type === 'summary_table');
            const startLists = general.filter(c => c.view_type === 'start_list');

            let html = '<div class="row g-3">';
            
            // Start Lists Column
            html += `
                <div class="col-md-6">
                    <div class="d-flex align-items-center mb-2">
                        <i class="fas fa-users text-success me-2"></i>
                        <small class="text-muted fw-bold">Start Lists</small>
                    </div>
                    <div class="d-flex flex-column gap-2">
                        ${startLists.length ? startLists.map(cfg => `
                            <button class="btn btn-outline-success btn-sm w-100 text-start"
                                onclick="loadStartListCard(${eventId}, null, { config_id: ${cfg.id} })"
                                title="${cfg.name}">
                                <i class="fas fa-users me-2"></i>${cfg.name}
                            </button>`).join('') : '<div class="text-muted small">No start lists available</div>'}
                    </div>
                </div>`;
                
            // Summary Tables Column
            html += `
                <div class="col-md-6">
                    <div class="d-flex align-items-center mb-2">
                        <i class="fas fa-table text-info me-2"></i>
                        <small class="text-muted fw-bold">Summary Tables</small>
                    </div>
                    <div class="d-flex flex-column gap-2">
                        ${summaryTables.length ? summaryTables.map(cfg => `
                            <button class="btn btn-outline-info btn-sm w-100 text-start"
                                onclick="loadSummaryTableCard(${eventId}, null, ${cfg.id}, '${String(cfg.name).replace(/'/g, "\\'")}')">
                                <i class="fas fa-table me-2"></i>${cfg.name}
                            </button>`).join('') : '<div class="text-muted small">No summary tables available</div>'}
                    </div>
                </div>`;
            // NEW: event-level holder for general report cards
            html += `
                <div class="col-12 mt-2">
                    <div class="general-report-cards" id="general-report-cards-${eventId}">${oldHtml}</div>
                </div>`;
            html += '</div>';
            morphHtml(container, html);
        }

        // Report handling
        function loadSummaryTableCard(eventId, heatNumber, configId, configName, options = {}) {
            const refresh = options.refresh === true;
            const reportKey = `${eventId}-${heatNumber ?? 'all'}-summary`;
            const holderId = `report-cards-${eventId}-${heatNumber ?? 'all'}`;
            let holder = document.getElementById(holderId);
            if (!holder && heatNumber == null) {
                holder = document.getElementById(`general-report-cards-${eventId}`) 
                      || document.querySelector(`[id^="report-cards-${eventId}-"]`);
            }
            if (!holder) return;

            // Ensure heat details row is open if heat-specific
            if (heatNumber != null) {
                const row = document.getElementById(`heat-details-${eventId}-${heatNumber}`);
                if (row) row.style.display = '';
            }

            // Toggle only on direct button click, not on refresh
            if (!refresh && activeReports.has(reportKey) && activeReports.get(reportKey).configId === configId) {
                activeReports.delete(reportKey);
                morphHtml(holder, '');
                return;
            }

            const hadContent = holder.innerHTML.trim().length > 0;
            if (hadContent) showReportUpdating(reportKey);
            else {
                morphHtml(holder, `
                    <div class="border-0 shadow-none card mb-3">
                        <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                            <small class="fw-bold"><i class="fas fa-table me-1"></i>${configName}</small>
                            <div class="d-flex align-items-center gap-1 table-buttons">
                                <span class="badge bg-info"><i class="fas fa-sync-alt fa-spin me-1"></i>Loading…</span>
                                <button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard('${reportKey}')"></button>
                            </div>
                        </div>
                        <div class="border-0 shadow-none card-body p-2 text-center">
                            <div class="spinner-border spinner-border-sm text-primary"></div>
                            <small class="ms-2">Loading summary table…</small>
                        </div>
                    </div>`);
            }

            fetch(window.location.href, {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: `ajax=1&action=load_summary_table&config_id=${encodeURIComponent(configId)}`
            })
            .then(r => r.json())
            .then(res => {
                if (!res.success) throw new Error(res.message || 'Failed to load summary table');

                // FLIP: capture "First" positions BEFORE DOM update
                const prevRects = getRowRects(reportKey);

                const prev = activeReports.get(reportKey);
                const auto = prev ? (prev.auto !== false) : true;
                
                // Use HTML directly from API (same as backend)
                const apiHtml = res.html || '';
                
                // Wrap in card with header and controls
                const html = '<div class="border-0 shadow-none card mb-3">' +
                    '<div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">' +
                    '<small class="fw-bold"><i class="fas fa-table me-1"></i>' + configName + '</small>' +
                    '<div class="d-flex align-items-center gap-1 table-buttons">' +
                    '<button class="btn btn-sm ' + (auto ? 'btn-success' : 'btn-secondary') + '" onclick="toggleAutoRefresh(\'' + reportKey + '\')" title="Toggle auto-refresh">' +
                    '<i class="fas fa-sync-alt' + (auto ? '' : '') + '"></i>' +
                    '</button>' +
                    '<button class="btn btn-sm btn-primary" onclick="refreshReport(\'' + reportKey + '\')" title="Refresh now">' +
                    '<i class="fas fa-redo"></i>' +
                    '</button>' +
                    '<button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard(\'' + reportKey + '\')"></button>' +
                    '</div></div>' +
                    '<div class="border-0 shadow-none card-body p-2">' + apiHtml + '</div>' +
                    '</div>';

                // Morph in new HTML (the order may change)
                morphHtml(holder, html);

                // FLIP: get "Last" and animate to new positions
                playFlipAnimation(reportKey, prevRects);

                // Previous movement/changed/latest marking still applies
                let maps;
                if (refresh && prev && prev.type === 'summary_table') {
                    maps = trackAndAnimateSummaryTable(reportKey, prev);
                } else {
                    maps = buildSummaryRowMaps(reportKey);
                }

                activeReports.set(reportKey, {
                    html,
                    type: 'summary_table',
                    configId,
                    configName,
                    auto,
                    rowIndexMap: maps.indexMap,
                    rowContentMap: maps.contentMap
                });
                
                // Show success notification for report loading
                if (!refresh && window.notifySuccess) {
                    window.notifySuccess('Report Loaded', `Summary table for ${configName} loaded successfully`);
                }
            })
            .catch(err => {
                console.error(err);
                if (!hadContent) {
                    morphHtml(holder, `
                        <div class="border-0 shadow-none card mb-3">
                            <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                                <small class="fw-bold"><i class="fas fa-table me-1"></i>${configName}</small>
                                <button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard('${reportKey}')"></button>
                            </div>
                            <div class="border-0 shadow-none card-body p-2"><div class="alert alert-danger py-2 mb-0">${err.message}</div></div>
                        </div>`);
                }
            })
            .finally(() => hideReportUpdating(reportKey));
        }

        function loadStartListCard(eventId, heatNumber, options = {}) {
            const refresh = options.refresh === true;
            const configId = options.config_id || null;
            const reportKey = `${eventId}-${heatNumber ?? 'all'}-start`; // NEW: include type to avoid collision

            // NEW: choose holder for event-level start list under general-reports
            let holder;
            if (heatNumber == null) {
                holder = document.getElementById(`general-report-cards-${eventId}`);
                if (!holder) {
                    const general = document.getElementById(`general-reports-${eventId}`);
                    if (general) {
                        const wrap = document.createElement('div');
                        wrap.className = 'general-report-cards';
                        wrap.id = `general-report-cards-${eventId}`;
                        general.appendChild(wrap);
                        holder = wrap;
                    }
                }
            } else {
                holder = document.getElementById(`report-cards-${eventId}-${heatNumber}`);
            }
            if (!holder) return;

            // Ensure heat details row is open if heat-specific
            if (heatNumber != null) {
                const row = document.getElementById(`heat-details-${eventId}-${heatNumber}`);
                if (row) row.style.display = 'block';
            }

            // Toggle only on direct button click, not on refresh
            if (!refresh && activeReports.has(reportKey) && activeReports.get(reportKey).type === 'start_list') {
                activeReports.delete(reportKey);
                morphHtml(holder, '');
                return;
            }

            const hadContent = holder.innerHTML.trim().length > 0;
            if (hadContent) {
                showReportUpdating(reportKey);
            } else {
                morphHtml(holder, `
                    <div class="border-0 shadow-none card mb-3">
                        <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                            <small class="fw-bold"><i class="fas fa-users me-1"></i>Start List - ${heatNumber ? `Heat ${heatNumber}` : 'All Heats'}</small>
                            <div class="d-flex align-items-center gap-1  table-buttons">
                                <span class="badge bg-info"><i class="fas fa-sync-alt fa-spin me-1"></i>Loading…</span>
                                <button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard('${reportKey}')"></button>
                            </div>
                        </div>
                        <div class="border-0 shadow-none card-body p-2 text-center">
                            <div class="spinner-border spinner-border-sm text-primary"></div>
                            <small class="ms-2">Loading start list…</small>
                        </div>
                    </div>`);
            }

            fetch(window.location.href, {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: `ajax=1&action=load_start_list&event_id=${encodeURIComponent(eventId)}${heatNumber ? `&heat_number=${encodeURIComponent(heatNumber)}` : ''}${configId ? `&config_id=${encodeURIComponent(configId)}` : ''}`
            })
            .then(r => r.json())
            .then(res => {
                if (!res.success) throw new Error(res.message || 'Failed to load start list');
                const prev = activeReports.get(reportKey);
                const auto = prev ? (prev.auto !== false) : true;
                const html = convertStartListToHTML(res, (heatNumber ? `Heat ${heatNumber}` : 'All Heats'), reportKey, { auto });
                morphHtml(holder, html);
                activeReports.set(reportKey, { html, type: 'start_list', auto, configId });
                
                // Show success notification for report loading
                if (!refresh && window.notifySuccess) {
                    const heatText = heatNumber ? `Heat ${heatNumber}` : 'All Heats';
                    window.notifySuccess('Start List Loaded', `Start list for ${heatText} loaded successfully`);
                }
            })
            .catch(err => {
                console.error(err);
                if (!hadContent) {
                    morphHtml(holder, `
                        <div class="border-0 shadow-none card mb-3">
                            <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                                <small class="fw-bold"><i class="fas fa-users me-1"></i>Start List - ${heatNumber ? `Heat ${heatNumber}` : 'All Heats'}</small>
                                <button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard('${reportKey}')"></button>
                            </div>
                            <div class="border-0 shadow-none card-body p-2"><div class="alert alert-danger py-2 mb-0">${err.message}</div></div>
                        </div>`);
                }
            })
            .finally(() => {
                hideReportUpdating(reportKey);
            });
        }

        function convertSummaryTableToHTML(apiData, configName, reportKey, opts = {}) {
            const auto = opts.auto !== false; // default true
            const table_badge_colors = apiData?.table_badge_colors || '';
            const tableHead = apiData?.table_head || '';
            const tableBody = apiData?.table_body || '';
            const participantCount = apiData?.participant_count ?? 0;
            const filterSummary = apiData?.filter_summary || '';

            const tableHTML = (tableHead || tableBody) ? `
                <div class="d-flex justify-content-between align-items-center mb-2">
                    <div class="d-flex align-items-center gap-2">
                        <span class="badge bg-primary">${participantCount} Participants</span>
                        ${auto ? `<span class="badge bg-success"><i class="fas fa-sync-alt me-1"></i>Auto ${getHumanIntervalLabel(refreshMs)}</span>` 
                               : `<span class="badge bg-secondary"><i class="fas fa-pause me-1"></i>Manual</span>`}
                    </div>
                    <div class="d-flex align-items-center gap-1 table-buttons">
                        <button class="btn btn-sm btn-outline-secondary" onclick="refreshReport('${reportKey}')" title="Refresh now">
                            <i class="fas fa-sync-alt"></i>
                        </button>
                        <button class="btn btn-sm ${auto ? 'btn-warning' : 'btn-success'}" onclick="toggleReportAuto('${reportKey}')" title="${auto ? 'Pause auto-refresh' : 'Resume auto-refresh'}">
                            <i class="fas ${auto ? 'fa-pause' : 'fa-play'}"></i>
                        </button>
                        <button class="btn btn-sm btn-outline-secondary" onclick="toggleDashboardFullscreen('${reportKey}')" title="Fullscreen">
                            <i class="fas fa-expand"></i>
                        </button>
                        <button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard('${reportKey}')"></button>
                    </div>
                </div>
                ${filterSummary ? `<div class="text-muted small mb-2">${filterSummary}</div>` : ''}
                <style>${table_badge_colors}</style>
                <div class="table-responsive summary-table" id="summary-table-${reportKey}">
                    <table class="table data-table mb-0 table-bordered">
                        ${tableHead}
                        ${tableBody}
                    </table>
                </div>` : `<div class="alert alert-info py-2 mb-0">No summary data available</div>`;

            return `
                <div class="border-0 shadow-none card mb-3">
                    <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                        <h6 class="fw-bold"><i class="fas fa-table me-1"></i>${configName}</h6>
                        <button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard('${reportKey}')"></button>
                    </div>
                    <div class="border-0 shadow-none card-body p-2">${tableHTML}</div>
                </div>`;
        }

        function initializeDashboard() {
            console.log('Initializing public dashboard components...');
            
            // Initialize refresh controls
            const refreshSelect = document.getElementById('refreshIntervalSelect');
            if (refreshSelect) {
                refreshSelect.addEventListener('change', function() {
                    updateRefreshInterval(parseInt(this.value));
                });
            }
            
            // Initialize toggle refresh button
            const toggleBtn = document.getElementById('toggleRefresh');
            if (toggleBtn) {
                toggleBtn.addEventListener('click', toggleAutoRefresh);
            }
            
            console.log('Dashboard components initialized');
        }

        function updateRefreshInterval(newInterval) {
            refreshMs = newInterval || 30000;
            localStorage.setItem('dashboardRefreshMs', String(refreshMs));
            
            // Recalculate offset when interval changes
            reportRefreshOffsetMs = Math.max(300, Math.min(2000, Math.floor(refreshMs * 0.3)));
            
            if (autoRefresh) {
                startAutoRefresh(); // restarts with new interval/offset
                if (window.notifyInfo) {
                    window.notifyInfo('Refresh Interval Changed', `Now refreshing every ${getHumanIntervalLabel(refreshMs)}`);
                }
            } else {
                updateRefreshIndicator();
            }
        }

        function toggleAutoRefresh() {
            const toggleBtn = document.getElementById('toggleRefresh');
            if (!toggleBtn) return;
            
            if (autoRefresh) {
                // Turn OFF auto-refresh
                autoRefresh = false;
                stopAutoRefresh();
                toggleBtn.innerHTML = '<i class="fas fa-play me-1"></i>Resume Updates';
                if (window.notifyWarning) {
                    window.notifyWarning('Auto-Refresh OFF', 'Manual refresh required');
                }
            } else {
                // Turn ON auto-refresh
                autoRefresh = true;
                startAutoRefresh();
                toggleBtn.innerHTML = '<i class="fas fa-pause me-1"></i>Pause Updates';
                if (window.notifySuccess) {
                    window.notifySuccess('Auto-Refresh ON', `Refreshing every ${getHumanIntervalLabel(refreshMs)}`);
                }
            }
            
            updateRefreshIndicator();
        }

        function testNotifications() {
            // Test all notification types
            if (window.notifySuccess) {
                window.notifySuccess('Test Success', 'Notification system is working!');
                
                setTimeout(() => {
                    if (window.notifyInfo) {
                        window.notifyInfo('Test Info', 'Information notifications are working');
                    }
                }, 1000);
                
                setTimeout(() => {
                    if (window.notifyWarning) {
                        window.notifyWarning('Test Warning', 'Warning notifications are working');
                    }
                }, 2000);
                
                setTimeout(() => {
                    if (window.notifyError) {
                        window.notifyError('Test Error', 'Error notifications are working');
                    }
                }, 3000);
                
                console.log('Notification test completed');
            } else {
                console.error('Notification functions not available');
                alert('Notification system not loaded properly');
            }
        }

function toggleDashboardFullscreen() {
    const container = document.getElementById('eventsContainer');
    if (!container) return;
    if (document.fullscreenElement) {
        document.exitFullscreen();
        if (window.notifyInfo) {
            window.notifyInfo('Fullscreen OFF', 'Exited fullscreen mode');
        }
    } else {
        if (container.requestFullscreen) {
            container.requestFullscreen();
            container.classList.add('fullscreen');
        } else if (container.webkitRequestFullscreen) {
            container.webkitRequestFullscreen();
            container.classList.add('fullscreen');
        } else if (container.mozRequestFullScreen) {
            container.mozRequestFullScreen();
            container.classList.add('fullscreen');
        } else if (container.msRequestFullscreen) {
            container.msRequestFullscreen();
            container.classList.add('fullscreen');
        }
        if (window.notifySuccess) {
            window.notifySuccess('Fullscreen ON', 'Entered presentation mode');
        }
    }
}

// Optionally, listen for fullscreenchange to remove the class
document.addEventListener('fullscreenchange', function() {
    const container = document.getElementById('eventsContainer');
    if (container && !document.fullscreenElement) {
        container.classList.remove('fullscreen');
    }
});
        function convertStartListToHTML(res, heatText, reportKey, opts = {}) {
            const auto = opts.auto !== false; // default true

            const htmlContent = res.html_content;
            const headerRight = `
                <div class="d-flex align-items-center gap-1  table-buttons">
                    ${auto ? `<span class="badge bg-success"><i class="fas fa-sync-alt me-1"></i>Auto ${getHumanIntervalLabel(refreshMs)}</span>` 
                           : `<span class="badge bg-secondary"><i class="fas fa-pause me-1"></i>Manual</span>`}
                    <button class="btn btn-sm btn-outline-secondary" onclick="refreshReport('${reportKey}')" title="Refresh now"><i class="fas fa-sync-alt"></i></button>
                    <button class="btn btn-sm ${auto ? 'btn-warning' : 'btn-success'}" onclick="toggleReportAuto('${reportKey}')" title="${auto ? 'Pause auto-refresh' : 'Resume auto-refresh'}">
                        <i class="fas ${auto ? 'fa-pause' : 'fa-play'}"></i>
                    </button>
                    <button class="btn btn-sm btn-close btn-close-white" onclick="closeReportCard('${reportKey}')"></button>
                </div>`;

            if (htmlContent) {
                return `
                    <div class="border-0 shadow-none card mb-3">
                        <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                            <h6 class="fw-bold"><i class="fas fa-users me-1"></i>Start List - ${heatText}</h6>
                            ${headerRight}
                        </div>
                        <div class="border-0 shadow-none card-body p-2 start-list" id="start-list-${reportKey}" style="overflow:auto;">
                            ${htmlContent}
                        </div>
                    </div>`;
            }

            const participants = res?.data?.participants || [];
            
            const listHTML = participants.length ? `
                <div class="list-group list-group-flush">
                    ${participants.map(p => {
                        const colors = (categoryColors && categoryColors[p.category]) || {};
                        const categoryStyle = colors['background-color'] ? 
                            `background-color: ${colors['background-light'] || '#f8f9fa'}; border-left: 4px solid ${colors['background-color']};` : '';
                        const badgeStyle = colors['background-color'] ? 
                            `background-color: ${colors['background-color']}; color: ${colors['color'] || '#fff'}; border-color: ${colors['border-color'] || '#000'};` : 
                            'background-color: #6c757d; color: #fff;';
                        
                        return `
                        <div class="list-group-item p-2 d-flex justify-content-between align-items-center" 
                             data-category="${p.category || ''}" style="${categoryStyle}">
                            <div>
                                <span class="badge bg-dark me-2">BIB ${p.bib_number}</span>
                                <strong>${p.first_name} ${p.last_name}</strong>
                                <div class="small mt-1">
                                    ${p.category ? `<span class="category-badge-custom" style="${badgeStyle}">
                                        ${colors['background-color'] ? `<span class="category-color-dot" style="background-color: ${colors['background-color']};"></span>` : ''}
                                        ${p.category}
                                    </span>` : ''}
                                </div>
                            </div>
                            <div class="text-end small">
                                ${p.club ? `<div>${p.club}</div>` : ''}
                                <div class="text-muted">Heat ${p.heat_number || '—'}</div>
                            </div>
                        </div>`;
                    }).join('')}
                </div>` : `<div class="alert alert-info py-2 mb-0">No participants found</div>`;

            return `
                <div class="border-0 shadow-none card mb-3">
                    <div class="border-0 shadow-none card-header d-flex justify-content-between align-items-center py-2">
                        <h6 class="fw-bold"><i class="fas fa-users me-1"></i>Start List - ${heatText}</h6>
                        ${headerRight}
                    </div>
                    <div class="border-0 shadow-none card-body p-2 start-list" id="start-list-${reportKey}" style="overflow:auto;">
                        ${listHTML}
                    </div>
                </div>`;
        }

        // Keep refreshReport logic; it now respects per-card auto flag via load*Card
        function refreshReport(reportKey) {
            const rep = activeReports.get(reportKey);
            if (!rep) return;
            const parts = reportKey.split('-'); // NEW: eventId-heat|all-type
            const eventId = Number(parts[0]);
            const heatPart = parts[1];
            const heatNumber = heatPart === 'all' ? null : Number(heatPart);
            if (rep.type === 'summary_table') {
                loadSummaryTableCard(eventId, heatNumber, rep.configId, rep.configName, { refresh: true });
            } else if (rep.type === 'start_list') {
                loadStartListCard(eventId, heatNumber, { refresh: true, config_id: rep.configId });
            }
        }

        // Helpers to manage non-intrusive updating overlay on report-cards
        function getReportHolder(reportKey) {
            const parts = (reportKey || '').split('-'); // eventId-heat|all-type
            const eventId = parts[0];
            const heatKey = parts[1] || 'all';
            if (heatKey === 'all') {
                const general = document.getElementById(`general-report-cards-${eventId}`);
                if (general) return general;
            }
            let holder = document.getElementById(`report-cards-${eventId}-${heatKey}`);
            if (!holder && heatKey === 'all') {
                holder = document.querySelector(`[id^="report-cards-${eventId}-"]`);
            }
            return holder;
        }

        // NEW: overlay show/hide to avoid clearing content during refresh
        function showReportUpdating(reportKey) {
            const holder = getReportHolder(reportKey);
            if (!holder) return false;
            if (holder.querySelector('.report-updating-overlay')) return true;
            if (!holder.style.position || holder.style.position === 'static') {
                holder.style.position = 'relative';
            }
            const overlay = document.createElement('div');
            overlay.className = 'report-updating-overlay position-absolute top-0 end-0 m-2';
            overlay.innerHTML = '<span class="badge bg-info"><i class="fas fa-sync-alt fa-spin me-1"></i>Updating…</span>';
            holder.appendChild(overlay);
            
            // Convert and initialize Lucide icons for the updating overlay
            if (window.convertFontAwesomeToLucide) {
                window.convertFontAwesomeToLucide();
            }
            if (window.initializeLucideIcons) {
                window.initializeLucideIcons();
            }
            
            return true;
        }

        function hideReportUpdating(reportKey) {
            const holder = getReportHolder(reportKey);
            if (!holder) return;
            const ov = holder.querySelector('.report-updating-overlay');
            if (ov) ov.remove();
        }

        function closeReportCard(reportKey) {
            activeReports.delete(reportKey);
            const holder = getReportHolder(reportKey);
            if (holder) morphHtml(holder, '');
        }

        // Build key from column 2 (second column) text
        function getRowKeyBySecondColumn(row) {
            const cells = row.querySelectorAll('td, th');
            if (cells.length >= 2) {
                return (cells[1].textContent || '').trim();
            }
            return (row.textContent || '').trim();
        }

        // Collect current row rects keyed by a stable key (2nd column text)
function getRowRects(reportKey) {
    const container = document.getElementById(`summary-table-${reportKey}`);
    const rows = container ? container.querySelectorAll('tbody tr') : null;
    const rects = {};
    if (!rows) return rects;
    rows.forEach(tr => {
        const key = getRowKeyBySecondColumn(tr);
        if (key) rects[key] = tr.getBoundingClientRect();
    });
    return rects;
}

// Play FLIP animation: invert from old rects to new, then animate to identity
function playFlipAnimation(reportKey, prevRects) {
    const container = document.getElementById(`summary-table-${reportKey}`);
    if (!container) return;
    const rows = container.querySelectorAll('tbody tr');
    rows.forEach(tr => {
        const key = getRowKeyBySecondColumn(tr);
        if (!key) return;

        const oldRect = prevRects[key];
        const newRect = tr.getBoundingClientRect();

        if (oldRect) {
            const dy = oldRect.top - newRect.top;
            if (Math.abs(dy) > 0.5) {
                tr.style.transition = 'none';
                tr.style.transform = `translateY(${dy}px)`;
                // force reflow
                void tr.offsetHeight;
                tr.style.transition = 'transform 1200ms ease, opacity 1200ms ease';
                tr.style.transform = '';
            }
        } else {
            // New row: fade+slide in
            tr.style.transition = 'none';
            tr.style.opacity = '0';
            tr.style.transform = 'translateY(8px)';
            void tr.offsetHeight;
            tr.style.transition = 'transform 1200ms ease, opacity 1200ms ease';
            tr.style.opacity = '1';
            tr.style.transform = '';
        }

        const cleanup = () => {
            tr.style.transition = '';
            tr.style.transform = '';
            tr.style.opacity = '';
            tr.removeEventListener('transitionend', cleanup);
        };
        tr.addEventListener('transitionend', cleanup);
    });
}

// Build current maps for a summary table
        function buildSummaryRowMaps(reportKey) {
            const container = document.getElementById(`summary-table-${reportKey}`);
            const rows = container ? container.querySelectorAll('tbody tr') : null;
            const indexMap = {};
            const contentMap = {};
            if (!rows) return { indexMap, contentMap };
            let idx = 0;
            rows.forEach(tr => {
                const key = getRowKeyBySecondColumn(tr);
                if (!key) return;
                indexMap[key] = idx++;
                contentMap[key] = (tr.textContent || '').trim();
            });
            return { indexMap, contentMap };
        }

        function addMoveIndicator(row, direction) {
            // put indicator into first cell
            const firstCell = row.querySelector('td, th');
            if (!firstCell) return;
            const existing = firstCell.querySelector('.move-indicator');
            if (existing) existing.remove();
            const span = document.createElement('span');
            span.className = `move-indicator ${direction}`;
            span.innerHTML = direction === 'up'
                ? '<span class="badge bg-success"><i class="fas fa-arrow-up"></i> Up</span>'
                : '<span class="badge bg-danger"><i class="fas fa-arrow-down"></i> Down</span>';
            firstCell.appendChild(span);
            
            // Convert and initialize Lucide icons for the movement indicators
            if (window.convertFontAwesomeToLucide) {
                window.convertFontAwesomeToLucide();
            }
            if (window.initializeLucideIcons) {
                window.initializeLucideIcons();
            }
            
            setTimeout(() => span.remove(), 5000);
        }

        // Compare previous vs current and animate row moves/changes
        function animateSummaryRowChanges(reportKey, prevIndexMap, prevContentMap, newIndexMap, newContentMap) {
            const container = document.getElementById(`summary-table-${reportKey}`);
            if (!container) return;

            const rows = container.querySelectorAll('tbody tr');
            
            // Find the most recent approval timestamp
            let latestTimestamp = null;
            rows.forEach(tr => {
                const approvedAt = tr.getAttribute('data-approved_at');
                if (approvedAt && (!latestTimestamp || approvedAt > latestTimestamp)) {
                    latestTimestamp = approvedAt;
                }
            });

        // Calculate the cutoff time (60 seconds ago)
            const sixtySecondsAgo = new Date();
            sixtySecondsAgo.setSeconds(sixtySecondsAgo.getSeconds() - 60);
            const cutoffTime = sixtySecondsAgo.toISOString();

            rows.forEach(tr => {
                const key = getRowKeyBySecondColumn(tr);
                if (!key) return;
                const prevIdx = prevIndexMap ? prevIndexMap[key] : undefined;
                const newIdx = newIndexMap[key];
                const prevContent = prevContentMap ? prevContentMap[key] : undefined;
                const newContent = newContentMap ? newContentMap[key] : undefined;

                // Clear any previous classes
                tr.classList.remove('moved-up', 'moved-down', 'changed', 'latest');

                // Mark rows with the most recent approval timestamp ONLY if it's within the last 60 seconds
                const approvedAt = tr.getAttribute('data-approved_at');
                if (approvedAt && approvedAt === latestTimestamp && approvedAt > cutoffTime) {
                    tr.classList.add('latest');
                }

                if (prevIdx !== undefined && newIdx !== undefined) {
                    const delta = prevIdx - newIdx;
                    if (delta > 0) {
                        tr.classList.add('moved-up');
                        addMoveIndicator(tr, 'up');
                    } else if (delta < 0) {
                        tr.classList.add('moved-down');
                        addMoveIndicator(tr, 'down');
                    } else if (prevContent !== undefined && prevContent !== newContent) {
                        tr.classList.add('changed');
                    }
                } else if (prevIdx === undefined && newIdx !== undefined) {
                    // New row: highlight as changed
                    tr.classList.add('changed');
                }
            });
        }

        // Orchestrate building maps + animating; return new maps for storage
        function trackAndAnimateSummaryTable(reportKey, prevMeta) {
            const prevIndexMap = prevMeta && prevMeta.rowIndexMap ? prevMeta.rowIndexMap : {};
            const prevContentMap = prevMeta && prevMeta.rowContentMap ? prevMeta.rowContentMap : {};
            const maps = buildSummaryRowMaps(reportKey);
            animateSummaryRowChanges(reportKey, prevIndexMap, prevContentMap, maps.indexMap, maps.contentMap);
            return maps;
        }

        // Get heat live details independently (smaller, more frequent update)
function refreshHeatLiveDetails() {
    if (!autoRefresh) return;
    
    // Collect all visible active heat detail sections
    const activeHeatDetails = document.querySelectorAll('[id^="heat-details-live-"]');
    if (!activeHeatDetails.length) return;
    
    // Build array of event_id and heat_number pairs to refresh
    const heatsToRefresh = [];
    activeHeatDetails.forEach(el => {
        const idParts = el.id.split('-');
        if (idParts.length >= 5) {
            const eventId = idParts[3];
            const heatNumber = idParts[4];
            
            // Only if this heat is marked as active
            if (document.getElementById(`active-run-${eventId}-${heatNumber}`)) {
                heatsToRefresh.push({eventId, heatNumber});
            }
        }
    });
    
    if (!heatsToRefresh.length) return;
    
    // Fetch updated details for all active heats
    const eventIds = [...new Set(heatsToRefresh.map(h => h.eventId))];
    
    // Fetch data for each event (better than fetching individual heats)
    eventIds.forEach(eventId => {
        fetch(`${DASH_API}?action=get_active_heat_details&event_id=${eventId}`)
            .then(r => r.json())
            .then(data => {
                if (!data.success) return;
                
                // Process each heat's data
                Object.entries(data.heats || {}).forEach(([heatNumber, heatData]) => {
                    const activeRunEl = document.getElementById(`active-run-${eventId}-${heatNumber}`);
                    const bibStartEl = document.getElementById(`bib-start-${eventId}-${heatNumber}`);
                    const latestBipEl = document.getElementById(`latest-bib-${eventId}-${heatNumber}`);
                    
                    if (activeRunEl) {
                        activeRunEl.innerHTML = `<strong>Active Run:</strong> ${heatData.active_run || 1}`;
                    }
                    if (bibStartEl) {
                        bibStartEl.innerHTML = `<strong>BIB Start:</strong> ${heatData.bib_on_start ? 
                            `<span class="badge bg-secondary">${heatData.bib_on_start}</span> ${heatData.bib_start_name || ''}` : '—'}`;
                    }
                    if (latestBipEl) {
                        latestBipEl.innerHTML = `<strong>Latest BIB:</strong> ${heatData.bib_latest_on_run ? 
                            `<span class="badge bg-secondary">${heatData.bib_latest_on_run}</span> ${heatData.bib_latest_name || ''}` : '—'}`;
                        
                        // Highlight the latest BIB with a flash animation when it changes
                        if (latestBipEl.dataset.lastValue !== String(heatData.bib_latest_on_run)) {
                            latestBipEl.classList.add('highlight-update');
                            setTimeout(() => {
                                latestBipEl.classList.remove('highlight-update');
                            }, 2000);
                        }
                        latestBipEl.dataset.lastValue = String(heatData.bib_latest_on_run);
                    }
                });
                
                // Convert and initialize Lucide icons after heat details update
                if (window.convertFontAwesomeToLucide) {
                    window.convertFontAwesomeToLucide();
                }
                if (window.initializeLucideIcons) {
                    window.initializeLucideIcons();
                }
            })
            .catch(err => console.error('Error refreshing heat details:', err));
    });
}

// Refresh just the heat rows in the event table without reloading full heat details
function refreshHeatRows() {
    if (!autoRefresh) return;
    
    // Find all visible event heat rows
    const eventRows = document.querySelectorAll('tr.event-row');
    if (!eventRows.length) return;
    
    // Group by event ID to minimize API calls
    const eventMap = {};
    eventRows.forEach(row => {
        const idParts = row.id.split('-');
        if (idParts.length >= 4) {
            const eventId = idParts[1];
            const heatNumber = idParts[3];
            
            if (!eventMap[eventId]) {
                eventMap[eventId] = [];
            }
            eventMap[eventId].push(heatNumber);
        }
    });
    
    // Fetch updated heat data for each event
    Object.entries(eventMap).forEach(([eventId, heats]) => {
        fetch(`${DASH_API}?action=get_heat_rows&event_id=${eventId}`)
            .then(r => r.json())
            .then(data => {
                if (!data.success) return;
                
                // Update each heat row with new data
                data.heats.forEach(heat => {
                    const rowId = `event-${eventId}-heat-${heat.heat_number}`;
                    const row = document.getElementById(rowId);
                    if (!row) return;
                    
                    // Calculate completion percentage
                    const completion = heat.expected_scores > 0
                        ? Math.round((Number(heat.total_scores || 0) / Number(heat.expected_scores)) * 100)
                        : 0;
                    const progressClass = completion >= 100 ? 'bg-success' : (completion >= 50 ? 'bg-warning' : 'bg-info');
                    const heatStatusClass = Number(heat.is_active) === 1 ? 'bg-danger' : (completion >= 100 ? 'bg-success' : 'bg-secondary');
                    const heatStatusText = Number(heat.is_active) === 1 ? 'Live' : (completion >= 100 ? 'Completed' : 'Upcoming');
                    
                    // Update first cell (heat status + name)
                    const statusCell = row.cells[0];
                    if (statusCell) {
                        const statusBadge = statusCell.querySelector('.badge');
                        if (statusBadge) {
                            statusBadge.className = `badge ${heatStatusClass} me-2`;
                            statusBadge.textContent = heatStatusText;
                        }
                        
                        const heatInfoDiv = statusCell.querySelector('div > div');
                        if (heatInfoDiv) {
                            const nameElement = heatInfoDiv.querySelector('strong');
                            if (nameElement) {
                                nameElement.textContent = `Heat ${heat.heat_number}: ${heat.heat_name || ''}`;
                            }
                            
                            const infoElement = heatInfoDiv.querySelector('.small');
                            if (infoElement) {
                                infoElement.textContent = `${heat.scoring_type || ''} • ${heat.runs_count || 0} runs`;
                            }
                        }
                    }
                    
                    // Update participant count (3rd cell)
                    if (row.cells[2]) {
                        row.cells[2].textContent = heat.participants || 0;
                    }
                    
                    // Update progress bar (4th cell)
                    const progressCell = row.cells[3];
                    if (progressCell) {
                        const progressBar = progressCell.querySelector('.progress-bar');
                        if (progressBar) {
                            progressBar.className = `progress-bar ${progressClass}`;
                            progressBar.style.width = `${completion}%`;
                        }
                        
                        const progressText = progressCell.querySelector('small');
                        if (progressText) {
                            progressText.textContent = `${completion}%`;
                        }
                    }
                    
                    // Highlight the row briefly to show it was updated
                    row.classList.add('heat-row-updated');
                    setTimeout(() => {
                        row.classList.remove('heat-row-updated');
                    }, 2000);
                });
            })
            .catch(err => console.error('Error refreshing heat rows:', err));
    });
}

// Add to refresh cycle with faster updates for active heat details
let heatDetailsInterval;
function startHeatDetailsRefresh() {
    stopHeatDetailsRefresh();
    // Update active heat details more frequently (every 5 seconds)
    heatDetailsInterval = setInterval(() => {
        refreshHeatLiveDetails();
        refreshHeatRows(); // Also refresh heat rows
    }, 5000);
}

function stopHeatDetailsRefresh() {
    if (heatDetailsInterval) {
        clearInterval(heatDetailsInterval);
        heatDetailsInterval = null;
    }
}

        // Latest Updates (Latest Score + Next on Start) refresh functionality
        let latestUpdatesInterval;
        function startLatestUpdatesRefresh() {
            stopLatestUpdatesRefresh();
            // Update latest score and next on start more frequently (every 3 seconds)
            latestUpdatesInterval = setInterval(() => {
                refreshLatestUpdates();
            }, 3000);
        }

        function stopLatestUpdatesRefresh() {
            if (latestUpdatesInterval) {
                clearInterval(latestUpdatesInterval);
                latestUpdatesInterval = null;
            }
        }

        // Helper function to create participant photo element
        function createParticipantPhoto(participant) {
            console.log('createParticipantPhoto called with:', participant);
            
            if (participant && participant.photo && participant.photo.trim() !== '') {
                const photoUrl = participant.photo.startsWith('http') ? participant.photo : `${participant.photo}`;
                return `<img src="${photoUrl}" alt="${(participant.first_name || '')} ${(participant.last_name || '')}" class="participant-photo me-2" 
                            onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
                        <div class="participant-photo-placeholder me-2" style="display:none;">${((participant.first_name || '').charAt(0) + (participant.last_name || '').charAt(0)).toUpperCase()}</div>`;
            } else {
                const initials = ((participant?.first_name || '').charAt(0) + (participant?.last_name || '').charAt(0)).toUpperCase() || '??';
                return `<div class="participant-photo-placeholder me-2">${initials}</div>`;
            }
        }

        // Helper function to create photo placeholder
        function createPhotoPlaceholder(firstName, lastName) {
            const initials = ((firstName || '').charAt(0) + (lastName || '').charAt(0)).toUpperCase();
            return `<div class="participant-photo-placeholder me-2">${initials}</div>`;
        }

        // Helper function to create facts icon with tooltip
        function createFactsIcon(eventId, bibNumber) {
            return `<div class="facts-icon ms-2" onclick="loadParticipantFacts(${eventId}, '${bibNumber}', this)">
                        <i class="fas fa-info"></i>
                        <div class="facts-tooltip" id="facts-tooltip-${bibNumber}">
                            <div class="fact-item">
                                <div class="fact-title">Loading...</div>
                            </div>
                        </div>
                    </div>`;
        }

        // Function to load participant facts
        async function loadParticipantFacts(eventId, bibNumber, iconElement) {
            const tooltip = iconElement.querySelector('.facts-tooltip');
            
            // Smart positioning: check if there's enough space below
            const iconRect = iconElement.getBoundingClientRect();
            const viewportHeight = window.innerHeight;
            const spaceBelow = viewportHeight - iconRect.bottom;
            const estimatedTooltipHeight = 100; // Estimated tooltip height
            
            // If not enough space below, position tooltip above
            if (spaceBelow < estimatedTooltipHeight && iconRect.top > estimatedTooltipHeight) {
                tooltip.classList.add('position-top');
            } else {
                tooltip.classList.remove('position-top');
            }
            
            try {
                const response = await fetch(`${DASH_API}?action=get_participant_by_bib&event_id=${eventId}&bib_number=${bibNumber}`);
                const data = await response.json();
                
                if (data.success && data.participant && data.participant.facts && data.participant.facts.length > 0) {
                    const factsHtml = data.participant.facts.map(fact => `
                        <div class="fact-item">
                            <div class="fact-title">${fact.title}</div>
                            <div class="fact-text">${fact.fact}</div>
                        </div>
                    `).join('');
                    
                    tooltip.innerHTML = factsHtml;
                } else {
                    tooltip.innerHTML = `
                        <div class="fact-item">
                            <div class="fact-title">No Facts Available</div>
                            <div class="fact-text">No additional information available for this participant.</div>
                        </div>
                    `;
                }
            } catch (error) {
                console.error('Error loading participant facts:', error);
                tooltip.innerHTML = `
                    <div class="fact-item">
                        <div class="fact-title">Error</div>
                        <div class="fact-text">Could not load participant facts.</div>
                    </div>
                `;
            }
        }

        // Global pinned cards management
        let pinnedCardsManager = {
            cards: new Map(),
            zIndexCounter: 10000,
            
            getNextPosition() {
                const existingCards = Array.from(this.cards.values());
                let top = 20;
                let right = 20;
                
                // Find the next available position to avoid overlap
                existingCards.forEach(card => {
                    const rect = card.element.getBoundingClientRect();
                    if (Math.abs(rect.top - top) < 50 && Math.abs(window.innerWidth - rect.right - right) < 50) {
                        top += 60; // Stack vertically with offset
                        if (top > window.innerHeight - 200) {
                            top = 20;
                            right += 50; // Move to next column
                        }
                    }
                });
                
                return { top, right };
            },
            
            bringToFront(pinnedId) {
                const card = this.cards.get(pinnedId);
                if (card) {
                    card.element.style.zIndex = ++this.zIndexCounter;
                }
            }
        };

        // Function to create pinned card popup
        function createPinnedCard(cardType, eventId, clickedElement) {
            // Find the parent card element
            const cardElement = clickedElement.closest('.card');
            if (!cardElement) return;
            
            // Create unique ID for this pinned card
            const pinnedId = `pinned-${cardType}-${eventId}-${Date.now()}`;
            
            // Clone the card content
            const cardClone = cardElement.cloneNode(true);
            
            // Remove any existing pinned cards of the same type to prevent duplicates
            const existingPinned = document.querySelectorAll(`[id^="pinned-${cardType}-${eventId}"]`);
            existingPinned.forEach(el => {
                pinnedCardsManager.cards.delete(el.id);
                el.remove();
            });
            
            // Get next available position
            const position = pinnedCardsManager.getNextPosition();
            
            // Create the popup/modal container
            const popup = document.createElement('div');
            popup.id = pinnedId;
            popup.className = 'pinned-card-popup position-fixed';
            popup.style.cssText = `
                top: ${position.top}px;
                right: ${position.right}px;
                width: 400px;
                max-width: 90vw;
                z-index: ${++pinnedCardsManager.zIndexCounter};
                animation: slideInRight 0.3s ease-out;
                cursor: move;
                user-select: none;
            `;
            
            // Create the popup content
            popup.innerHTML = `
                <div class="card shadow-lg border-0" style="background: rgba(255, 255, 255, 0.98); backdrop-filter: blur(10px);">
                    <div class="card-header d-flex justify-content-between align-items-center py-2 bg-dark text-white draggable-header" style="cursor: move;">
                        <div class="d-flex align-items-center">
                            <i class="fas fa-thumbtack me-2"></i>
                            <span class="fw-bold">Pinned: ${getPinnedCardTitle(cardType)}</span>
                            <small class="ms-2 text-muted">(drag to move)</small>
                        </div>
                        <button class="btn btn-sm btn-close btn-close-white" onclick="closePinnedCard('${pinnedId}')" title="Close pinned card" style="cursor: pointer;"></button>
                    </div>
                    <div class="card-body p-0" style="cursor: default;">
                        ${cardClone.innerHTML}
                    </div>
                </div>
            `;
            
            // Add to document
            document.body.appendChild(popup);
            
            // Register the card in the manager
            pinnedCardsManager.cards.set(pinnedId, {
                element: popup,
                cardType: cardType,
                eventId: eventId
            });
            
            // Make the card draggable
            makeDraggable(popup);
            
            // Add click handler to bring to front
            popup.addEventListener('mousedown', () => {
                pinnedCardsManager.bringToFront(pinnedId);
            });
            
            // Add animation styles if not already present
            if (!document.getElementById('pinned-card-styles')) {
                const styles = document.createElement('style');
                styles.id = 'pinned-card-styles';
                styles.textContent = `
                    @keyframes slideInRight {
                        from { transform: translateX(100%); opacity: 0; }
                        to { transform: translateX(0); opacity: 1; }
                    }
                    @keyframes slideOutRight {
                        from { transform: translateX(0); opacity: 1; }
                        to { transform: translateX(100%); opacity: 0; }
                    }
                    .pinned-card-popup.closing {
                        animation: slideOutRight 0.3s ease-in forwards;
                    }
                    .pinned-card-popup:hover {
                        box-shadow: 0 8px 25px rgba(0,0,0,0.2) !important;
                    }
                    .pinned-card-popup.dragging {
                        transform: rotate(2deg);
                        transition: transform 0.1s ease;
                    }
                    .draggable-header:hover {
                        background-color: rgba(0,0,0,0.8) !important;
                    }
                `;
                document.head.appendChild(styles);
            }
            
            // Show success notification
            if (window.notifySuccess) {
                window.notifySuccess('Card Pinned', `${getPinnedCardTitle(cardType)} pinned successfully`);
            }
            
            console.log(`Pinned card created: ${cardType} for event ${eventId}`);
        }

        // Function to make an element draggable
        function makeDraggable(element) {
            let isDragging = false;
            let startX, startY, startLeft, startTop;
            
            const header = element.querySelector('.draggable-header');
            if (!header) return;
            
            header.addEventListener('mousedown', initDrag);
            
            function initDrag(e) {
                isDragging = true;
                element.classList.add('dragging');
                
                // Get initial positions
                startX = e.clientX;
                startY = e.clientY;
                
                const rect = element.getBoundingClientRect();
                startLeft = rect.left;
                startTop = rect.top;
                
                // Switch to left/top positioning for easier calculation
                element.style.right = 'auto';
                element.style.left = startLeft + 'px';
                element.style.top = startTop + 'px';
                
                // Add global event listeners
                document.addEventListener('mousemove', doDrag);
                document.addEventListener('mouseup', stopDrag);
                
                // Prevent text selection
                e.preventDefault();
            }
            
            function doDrag(e) {
                if (!isDragging) return;
                
                // Calculate new position
                const newLeft = startLeft + (e.clientX - startX);
                const newTop = startTop + (e.clientY - startY);
                
                // Constrain to viewport
                const maxLeft = window.innerWidth - element.offsetWidth;
                const maxTop = window.innerHeight - element.offsetHeight;
                
                const constrainedLeft = Math.max(0, Math.min(newLeft, maxLeft));
                const constrainedTop = Math.max(0, Math.min(newTop, maxTop));
                
                // Update position
                element.style.left = constrainedLeft + 'px';
                element.style.top = constrainedTop + 'px';
            }
            
            function stopDrag() {
                if (isDragging) {
                    isDragging = false;
                    element.classList.remove('dragging');
                    
                    // Remove global event listeners
                    document.removeEventListener('mousemove', doDrag);
                    document.removeEventListener('mouseup', stopDrag);
                }
            }
        }
        
        // Helper function to get pinned card title
        function getPinnedCardTitle(cardType) {
            switch(cardType) {
                case 'latest-score': return 'Latest Score';
                case 'next-on-start': return 'Next on Start';
                case 'performing-now': return 'Performing Now';
                default: return 'Dashboard Card';
            }
        }
        
        // Function to close pinned card
        function closePinnedCard(pinnedId) {
            const pinnedCard = document.getElementById(pinnedId);
            if (!pinnedCard) return;
            
            // Remove from manager
            pinnedCardsManager.cards.delete(pinnedId);
            
            // Add closing animation
            pinnedCard.classList.add('closing');
            
            // Remove after animation completes
            setTimeout(() => {
                pinnedCard.remove();
            }, 300);
            
            if (window.notifyInfo) {
                window.notifyInfo('Card Unpinned', 'Pinned card closed');
            }
        }function refreshLatestUpdates() {
    if (!autoRefresh) return;
    
    // Get all event IDs that have latest updates displayed
    const latestUpdateElements = document.querySelectorAll('[id^="latest-updates-"]');
    latestUpdateElements.forEach(element => {
        const eventId = element.id.replace('latest-updates-', '');
        refreshEventLatestUpdates(eventId);
    });
}

function refreshEventLatestUpdates(eventId) {
    fetch(`${DASH_API}?action=get_event_latest_updates&event_id=${encodeURIComponent(eventId)}`, { method: 'GET' })
        .then(r => r.json())
        .then(data => {
            if (data.success) {
                console.log('refreshEventLatestUpdates received data for event', eventId, ':', data);
                // Get latest scored participant from summary table for complete score data
                getLatestScoredParticipant(eventId)
                    .then(latestParticipant => {
                        console.log('getLatestScoredParticipant result for event', eventId, ':', latestParticipant);
                        // Only update if we actually got valid data
                        if (latestParticipant) {
                            updateLatestScoreDisplay(eventId, latestParticipant);
                        }
                        // If latestParticipant is null, keep existing content unchanged
                    })
                    .catch(error => {
                        console.log('Error getting latest scored participant for event ' + eventId + ':', error);
                        // Don't update display on error - keep existing content
                    });
                
                // Only update other displays if we have data
                if (data.next_bib) {
                    updateNextOnStartDisplay(eventId, data.next_bib);
                }
                if (data.performing_now) {
                    updatePerformingNowDisplay(eventId, data.performing_now);
                }
            } else {
                console.log('refreshEventLatestUpdates ' + eventId + ':', data);
            }
        })
        .catch(error => {
            console.log('Error refreshing latest updates for event ' + eventId + ':', error);
        });
}

// Get latest scored participant with all judge scores from summary table
async function getLatestScoredParticipant(eventId) {
    try {
        // Get the latest score from the proper API endpoint
        const latestResponse = await fetch(`${DASH_API}?action=get_event_latest_updates&event_id=${encodeURIComponent(eventId)}`);
        const latestData = await latestResponse.json();
        
        if (!latestData.success || !latestData.latest_score) {
            return null;
        }
        
        const latestScore = latestData.latest_score;
        const latestBib = latestScore.bib_number;
        
        // Get summary table JSON with judge scores and participant data
        const summaryResponse = await fetch(`api/summary_table_api.php?event_id=${encodeURIComponent(eventId)}&format=json&show_judges=true&show_rank=true`);
        const summaryData = await summaryResponse.json();
        
        if (!summaryData.success || !summaryData.participants) {
            console.log('Could not get participant data from summary table API');
            // Fall back to using basic API data only
            return {
                bib_number: latestBib,
                name: `${latestScore.first_name} ${latestScore.last_name}`.trim(),
                first_name: latestScore.first_name || '',
                last_name: latestScore.last_name || '',
                club: latestScore.club || '',
                country: latestScore.country || '',
                category: latestScore.category || '',
                photo: latestScore.photo || '',
                rank: latestScore.current_rank || 1,
                judge_scores: [{
                    judge_name: 'Judge 1',
                    score: parseFloat(latestScore.score_value) || 0,
                    score_status: 'normal',
                    is_dropped: false
                }],
                total_score: parseFloat(latestScore.score_value) || 0,
                created_at: latestScore.created_at,
                heat_name: latestScore.heat_name || '',
                heat_number: latestScore.heat_number || ''
            };
        }
        
        // Find the participant by BIB number in the JSON data
        const participant = summaryData.participants.find(p => 
            p.bib_number && p.bib_number.toString() === latestBib.toString()
        );
        
        if (!participant) {
            console.log('Could not find participant with BIB', latestBib, 'in summary table participants');
            // Fall back to using API data only
            return {
                bib_number: latestBib,
                name: `${latestScore.first_name} ${latestScore.last_name}`.trim(),
                first_name: latestScore.first_name || '',
                last_name: latestScore.last_name || '',
                club: latestScore.club || '',
                country: latestScore.country || '',
                category: latestScore.category || '',
                photo: latestScore.photo || '',
                rank: latestScore.current_rank || 1,
                judge_scores: [{
                    judge_name: 'Judge 1',
                    score: parseFloat(latestScore.score_value) || 0,
                    score_status: 'normal',
                    is_dropped: false
                }],
                total_score: parseFloat(latestScore.score_value) || 0,
                created_at: latestScore.created_at,
                heat_name: latestScore.heat_name || '',
                heat_number: latestScore.heat_number || ''
            };
        }
        
        // Extract all judge scores from the most recent run
        let allJudgeScores = [];
        let latestHeat = 0;
        let latestRun = 0;
        
        // Find the most recent run with judge scores
        if (participant.judge_breakdown) {
            for (const heat in participant.judge_breakdown) {
                for (const run in participant.judge_breakdown[heat]) {
                    const heatNum = parseInt(heat);
                    const runNum = parseInt(run);
                    if (heatNum > latestHeat || (heatNum === latestHeat && runNum > latestRun)) {
                        latestHeat = heatNum;
                        latestRun = runNum;
                    }
                }
            }
        }
        
        // Get judge scores from the latest run
        if (latestHeat > 0 && latestRun > 0 && 
            participant.judge_breakdown[latestHeat] && 
            participant.judge_breakdown[latestHeat][latestRun]) {
            
            allJudgeScores = participant.judge_breakdown[latestHeat][latestRun].map(judge => ({
                judge_name: judge.judge_name || 'Judge',
                score: judge.score || 0,
                control_point: judge.control_point || 'General',
                score_status: judge.score_status || 'normal',
                is_dropped: judge.is_dropped || false
            }));
        }
        
        // If no judge breakdown found, fall back to basic score
        if (allJudgeScores.length === 0) {
            allJudgeScores = [{
                judge_name: 'Judge 1',
                score: parseFloat(latestScore.score_value) || 0,
                control_point: 'General',
                score_status: 'normal',
                is_dropped: false
            }];
        }
        
        // Get total score from participant data
        const totalScore = participant.scores?.overall_average || 
                          participant.scores?.overall_best || 
                          parseFloat(latestScore.score_value) || 0;
        
        console.log('Extracted participant data for BIB', latestBib, ':', {
            rank: participant.rank || participant.rank_in_category,
            name: participant.participant_name,
            judgeScores: allJudgeScores,
            totalScore: totalScore,
            heat: latestHeat,
            run: latestRun
        });
        
        return {
            bib_number: latestBib,
            name: participant.participant_name || `${latestScore.first_name} ${latestScore.last_name}`.trim(),
            first_name: participant.first_name || latestScore.first_name || '',
            last_name: participant.last_name || latestScore.last_name || '',
            club: participant.club || latestScore.club || '',
            country: participant.country || latestScore.country || '',
            category: participant.category || latestScore.category || '',
            photo: participant.photo || latestScore.photo || '',
            rank: participant.rank || participant.rank_in_category || latestScore.current_rank || 1,
            judge_scores: allJudgeScores,
            total_score: totalScore,
            created_at: latestScore.created_at,
            heat_name: `Heat ${latestHeat}` || latestScore.heat_name || '',
            heat_number: latestHeat || latestScore.heat_number || '',
            run_number: latestRun || 1
        };
        
    } catch (error) {
        console.error('Error getting latest scored participant:', error);
        return null;
    }
}

function updateLatestScoreDisplay(eventId, latestParticipant) {
    const container = document.getElementById(`latest-score-${eventId}`);
    if (!container) return;
    
    // Debug logging
    console.log('updateLatestScoreDisplay called for event', eventId, 'with data:', latestParticipant);
    console.log('Participant photo field:', latestParticipant?.photo);
    
    // Helper function to validate if participant data is complete and valid
    function isValidParticipantData(data) {
        return data && 
               data.bib_number && 
               data.name && 
               (data.total_score > 0 || (data.judge_scores && data.judge_scores.length > 0));
    }
    
    // Only update if we have valid new data, otherwise hide the card
    if (!latestParticipant || !isValidParticipantData(latestParticipant)) {
        // Hide the card when no data is available
        container.style.display = 'none';
        return;
    }
    
    // We have valid data, make sure card is visible and update content
    container.style.display = 'block';
    
    // Create judge scores HTML in native order without grouping
    let judgeScoresHtml = '';
    
    if (latestParticipant.judge_scores && latestParticipant.judge_scores.length > 0) {
        judgeScoresHtml = latestParticipant.judge_scores.map((judge, index) => {
            const isDropped = judge.is_dropped || judge.score_status === 'dropped' || judge.isDropped;
            const scoreClass = isDropped ? 'bg-secondary text-decoration-line-through' : 'bg-primary';
            const scoreIcon = isDropped ? 'fas fa-times' : 'fas fa-check';
            const scoreTitle = isDropped ? 'Dropped Score' : 'Counted Score';
            
            return `<span class="badge ${scoreClass} me-1 mb-1" title="${scoreTitle}">
                                ${isDropped ? judge.score : `${judge.score}`}
            </span>`;
        }).join('');
    }
    
    const html = `<div class="d-flex align-items-center mb-2">
                   
                    <h6 class="mb-0 text-success fw-bold">Latest Score</h6>
                </div>
        <div class="border-0 shadow-none card border-0 bg-success bg-opacity-10">
            <div class="border-0 shadow-none card-body p-2">
                
                <div class="d-flex align-items-start mb-2 latest-participant-wrapper">
                    <div class="d-flex align-items-center p_media_info">
                        ${createParticipantPhoto(latestParticipant)}
                        <div class="participant-avatar bg-white text-black d-flex align-items-center justify-content-center fw-bold css-bib rounded-circle" style="width: 50px; height: 50px; border: 2px solid #198754;">
                            <div class="fs-6 fw-bold text-success">${latestParticipant.bib_number}</div>
                        </div>
                        ${createFactsIcon(eventId, latestParticipant.bib_number)}
                    </div>
                    <div class="flex-grow-1 ms-3">
                        <h5 class="mb-1 text-dark">${latestParticipant.name}</h5>
                        

                        <div class="d-flex"style="
                            justify-content: space-between;
                            align-items: flex-start;
                        ">
                        <div class="d-flex flex-wrap gap-1 mb-2">
                         ${latestParticipant.country ? `<span class="country-code">${latestParticipant.country}</span>` : ''}
                            ${latestParticipant.club ? `<span class="badge bg-secondary participant-status-badge">${latestParticipant.club}</span>` : ''}
                           
                            ${latestParticipant.rank ? `<span class="badge bg-success px-2 py-1 rounded-pill fs-4" style="
                                                        position: absolute;
                                                        right: 20px;
                                                        top: 20px;
                                                    ">${latestParticipant.rank}</span>` : ''}
                                                                            </div>


                                                                            <div class="align-items-lg-stretch align-right d-flex" style="
                                                        display: flex;
                                                        justify-content: flex-end;
                                                        align-items: stretch;
                                                    ">
                        <!-- Judge Scores -->
                        <div class="mb-2">
                            
                            ${judgeScoresHtml}
                        </div>
                        
                        <!-- Total Score -->
                        
                        ${latestParticipant.total_score ? `
                        <div class="d-flex align-items-center gap-2 mb-2 p-2 bg-secondary bg-opacity-20 rounded">
                            <div class="text-primary fw-bold fs-5">
                                ${latestParticipant.total_score.toFixed(2)}
                            </div>
                        </div>` : ''}
                        
                        
                    </div></div>
                    <div class="text-muted small mt-1">
                            <i class="fas fa-clock me-1" style="cursor: pointer;" onclick="createPinnedCard('latest-score', ${eventId}, this)" title="Pin this card"></i>
                            ${latestParticipant.created_at ? new Date(latestParticipant.created_at).toLocaleTimeString() : 'Recently scored'}
                            ${latestParticipant.heat_name ? ` • ${latestParticipant.heat_name}` : ''}
                        </div>
                </div>
            </div>
        </div>`;
    
    morphHtml(container, html);
    
    // Remove auto-refresh notifications to prevent spam
    // if (window.notifySuccess) {
    //     window.notifySuccess(`Latest Score`, `${latestParticipant.name} - ${latestParticipant.total_score ? latestParticipant.total_score.toFixed(2) : 'Scored'}`);
    // }
}

function updateNextOnStartDisplay(eventId, nextBib) {
    const container = document.getElementById(`next-on-start-${eventId}`);
    if (!container) return;
    
    console.log('updateNextOnStartDisplay called with:', nextBib);
    
    // Helper function to validate if next participant data is complete
    function isValidNextParticipantData(data) {
        return data && 
               data.bib_number && 
               data.first_name && 
               data.last_name;
    }
    
    // Only update if we have valid new data, otherwise hide the card
    if (!nextBib || !isValidNextParticipantData(nextBib)) {
        // Hide the card when no participants are waiting
        container.style.display = 'none';
        return;
    }
    
    // We have valid data, make sure card is visible and update content
    container.style.display = 'block';
    
    // We have valid new data, update the display
    const html = `<div class="d-flex align-items-center mb-2">                    
                    <h6 class="mb-0 text-primary fw-bold">Next on Start</h6>
                </div>
        <div class="border-0 shadow-none card border-0 bg-primary bg-opacity-10">
            <div class="border-0 shadow-none card-body p-2">
                
                <div class="d-flex align-items-start mb-2 next-on-start-wrapper">
                    <div class="d-flex align-items-center p_media_info">
                        ${createParticipantPhoto(nextBib)}
                        <div class="participant-avatar bg-white text-black d-flex align-items-center justify-content-center fw-bold css-bib rounded-circle" style="width: 50px; height: 50px; border: 2px solid #0d6efd;">
                            <div class="fs-6 fw-bold text-primary">${nextBib.bib_number}</div>
                        </div>
                        ${createFactsIcon(eventId, nextBib.bib_number)}
                    </div>
                    <div class="flex-grow-1 ms-3">
                        <h5 class="mb-1 text-dark">${nextBib.first_name} ${nextBib.last_name}</h5>
                        <div class="d-flex flex-wrap gap-1 mb-1">
                           
                            ${nextBib.country ? `<span class="country-code">${nextBib.country}</span>` : ''}
                            ${nextBib.club ? `<span class="badge bg-secondary participant-status-badge">${nextBib.club}</span>` : ''}
                        </div>
                       
                        <div class="d-flex align-items-center gap-2 mt-1">
                            <div class="text-primary fw-bold">
                                <i class="fas fa-stopwatch me-1"></i>Ready
                            </div>
                            <span class="badge bg-primary bg-opacity-75 px-2 py-1 rounded-pill" style="
                                                                                    position: absolute;
                                                                                    right: 20px;
                                                                                    top: 20px;
                                                                                ">
                                <i class="fas fa-arrow-right me-1"></i>Next
                            </span>
                        </div>
                        <div class="text-muted small mt-1">
                            <i class="fas fa-flag me-1" style="cursor: pointer;" onclick="createPinnedCard('next-on-start', ${eventId}, this)" title="Pin this card"></i>
                            Ready to compete
                            ${nextBib.heat_name ? ` • ${nextBib.heat_name}` : ''}
                        </div>
                    </div>
                </div>
            </div>
        </div>`;
    
    morphHtml(container, html);
    
    // Remove auto-refresh notifications to prevent spam
    // if (window.notifyInfo) {
    //     window.notifyInfo(`Next on Start`, `${nextBib.first_name} ${nextBib.last_name} (BIB ${nextBib.bib_number})`);
    // }
}

function updatePerformingNowDisplay(eventId, performingNow) {
    const container = document.getElementById(`performing-now-${eventId}`);
    if (!container) return;
    
    console.log('updatePerformingNowDisplay called with:', performingNow);
    
    // Only update if we have valid new data, otherwise hide the card
    if (!performingNow || !performingNow.bib_number || !performingNow.first_name || !performingNow.last_name) {
        // Hide the card when no one is performing
        container.style.display = 'none';
        return;
    }
    
    // We have valid data, make sure card is visible and update content
    container.style.display = 'block';
    const html = ` <div class="d-flex align-items-center mb-2">
                    
                    <h6 class="mb-0 text-warning fw-bold">PERFORMING NOW</h6>
                </div>
        <div class="border-0 shadow-none card border-0 bg-warning bg-opacity-10">
            <div class="border-0 shadow-none card-body p-2">
               
                <div class="d-flex align-items-start mb-2 performing-now-wrapper">
                    <div class="d-flex align-items-center p_media_info">
                        ${createParticipantPhoto(performingNow)}
                        <div class="participant-avatar bg-white text-black d-flex align-items-center justify-content-center fw-bold css-bib rounded-circle" style="width: 50px; height: 50px; border: 2px solid #ffc107;">
                            <div class="fs-6 fw-bold text-warning">${performingNow.bib_number}</div>
                        </div>
                        ${createFactsIcon(eventId, performingNow.bib_number)}
                    </div>
                    <div class="flex-grow-1 ms-3">
                        <h5 class="mb-1 text-dark">${performingNow.first_name} ${performingNow.last_name}</h5>
                        <div class="d-flex flex-wrap gap-1 mb-1">
                           
                            ${performingNow.country ? `<span class="country-code">${performingNow.country}</span>` : ''}
                            ${performingNow.club ? `<span class="badge bg-secondary participant-status-badge">${performingNow.club}</span>` : ''}
                        </div>
                        
                        <div class="d-flex align-items-center gap-2 mt-1">
                            <div class="text-warning fw-bold">
                               Performing
                            </div>
                            <span class="badge bg-danger px-2 py-1 rounded-pill" style="
                                                            position: absolute;
                                                            right: 20px;
                                                            top: 20px;
                                                        ">
                                <i class="fas fa-circle me-1"></i>LIVE
                            </span>
                        </div>
                        <div class="text-muted small mt-1">                            
                            <i class="fas fa-play me-1" style="cursor: pointer;" onclick="createPinnedCard('performing-now', ${eventId}, this)" title="Pin this card"></i>
                            ${performingNow.heat_name ? ` • ${performingNow.heat_name}` : ''}
                        </div>
                    </div>
                </div>
            </div>
        </div>`;
    
    morphHtml(container, html);
    
    // Remove auto-refresh notifications to prevent spam
    // if (window.notifyWarning) {
    //     window.notifyWarning(`Now Performing`, `${performingNow.first_name} ${performingNow.last_name} (BIB ${performingNow.bib_number})`);
    // }
}
    </script>

  
    <script>
    // Public dashboard specific configuration
    document.addEventListener('DOMContentLoaded', function() {
        // Update test notifications function to use the global one
    
        
        // Show welcome notification
        setTimeout(() => {
            if (window.notifySuccess) {
                window.notifySuccess('Dashboard Ready', 'Public event dashboard loaded successfully');
            }
        }, 2000);
        
        console.log('Public dashboard specific configuration completed');
    });
    </script>

        <?php include 'admin/footer.php'; ?>
        
</body>
</html>