<?php
/**
 * webview.php — IBO-style 3-pane sports guide (Sports | Leagues | Events)
 *
 * The Tivi app's Sports menu is a WebView. Point it at:
 *     {panel_url}webview.php?fetch=sport
 *
 * This renders the exact same interactive 3-pane sports guide as IBO Glass 4.3:
 *   - Auto-imports today's fixtures from ESPN's mobile endpoint (UK first)
 *   - 3 panes: Sports | Leagues | Events, with search, team logos, TV channels,
 *     LIVE/Final status, and D-pad navigation for a TV remote.
 *
 * Fully automatic: if the data is stale (>30 min) or empty, it re-imports
 * before rendering. No manual step needed.
 */

include('includes/functions.php');

// ---- No-cache headers (the guide must always be fresh) ----
if (!headers_sent()) {
    header_remove('Cache-Control');
    header('Cache-Control: no-store, no-cache, private, must-revalidate, max-age=0', true);
    header('CDN-Cache-Control: no-store', true);
    header('Pragma: no-cache', true);
    header('Expires: 0', true);
}

// =============================================================================
// ESPN league list — [sport, espn_path, display_name]. UK first.
// =============================================================================
$ESPN_LEAGUES = [
    // UK football
    ['soccer', 'soccer/eng.1', 'English Premier League'],
    ['soccer', 'soccer/eng.2', 'English Championship'],
    ['soccer', 'soccer/eng.3', 'English League One'],
    ['soccer', 'soccer/eng.4', 'English League Two'],
    ['soccer', 'soccer/eng.fa', 'FA Cup'],
    ['soccer', 'soccer/eng.league_cup', 'EFL Cup'],
    ['soccer', 'soccer/eng.trophy', 'EFL Trophy'],
    ['soccer', 'soccer/sco.1', 'Scottish Premiership'],
    ['soccer', 'soccer/sco.2', 'Scottish Championship'],
    ['soccer', 'soccer/sco.challenge', 'Scottish Challenge Cup'],
    ['soccer', 'soccer/irl.1', 'League of Ireland'],
    // European football
    ['soccer', 'soccer/ger.1', 'German Bundesliga'],
    ['soccer', 'soccer/ger.2', 'German 2. Bundesliga'],
    ['soccer', 'soccer/ita.1', 'Italian Serie A'],
    ['soccer', 'soccer/ita.2', 'Italian Serie B'],
    ['soccer', 'soccer/esp.1', 'Spanish La Liga'],
    ['soccer', 'soccer/esp.2', 'Spanish La Liga 2'],
    ['soccer', 'soccer/fra.1', 'French Ligue 1'],
    ['soccer', 'soccer/fra.2', 'French Ligue 2'],
    ['soccer', 'soccer/ned.1', 'Dutch Eredivisie'],
    ['soccer', 'soccer/por.1', 'Portuguese Primeira Liga'],
    ['soccer', 'soccer/bel.1', 'Belgian Pro League'],
    ['soccer', 'soccer/tur.1', 'Turkish Super Lig'],
    ['soccer', 'soccer/gre.1', 'Greek Super League'],
    ['soccer', 'soccer/den.1', 'Danish Superliga'],
    ['soccer', 'soccer/aut.1', 'Austrian Bundesliga'],
    ['soccer', 'soccer/sui.1', 'Swiss Super League'],
    ['soccer', 'soccer/nor.1', 'Norwegian Eliteserien'],
    ['soccer', 'soccer/swe.1', 'Swedish Allsvenskan'],
    ['soccer', 'soccer/rus.1', 'Russian Premier League'],
    ['soccer', 'soccer/uefa.champions', 'UEFA Champions League'],
    ['soccer', 'soccer/uefa.europa', 'UEFA Europa League'],
    ['soccer', 'soccer/uefa.europa.conf', 'UEFA Conference League'],
    ['soccer', 'soccer/uefa.nations', 'UEFA Nations League'],
    ['soccer', 'soccer/conmebol.libertadores', 'Copa Libertadores'],
    ['soccer', 'soccer/conmebol.sudamericana', 'Copa Sudamericana'],
    ['soccer', 'soccer/concacaf.league', 'CONCACAF League'],
    ['soccer', 'soccer/fifa.friendly', 'International Friendlies'],
    ['soccer', 'soccer/club.friendly', 'Club Friendlies'],
    // International football
    ['soccer', 'soccer/arg.1', 'Argentine Primera'],
    ['soccer', 'soccer/bra.1', 'Brazilian Serie A'],
    ['soccer', 'soccer/mex.1', 'Mexican Liga MX'],
    ['soccer', 'soccer/mex.2', 'Mexican Liga de Expansión'],
    ['soccer', 'soccer/usa.1', 'MLS'],
    ['soccer', 'soccer/usa.nwsl', 'NWSL'],
    ['soccer', 'soccer/chi.1', 'Chinese Super League'],
    ['soccer', 'soccer/col.1', 'Colombian Primera A'],
    ['soccer', 'soccer/uru.1', 'Uruguayan Primera'],
    ['soccer', 'soccer/jpn.1', 'J1 League'],
    ['soccer', 'soccer/aus.1', 'A-League'],
    ['soccer', 'soccer/ksa.1', 'Saudi Pro League'],
    // Motorsport
    ['motorsport', 'racing/f1', 'Formula 1'],
    ['motorsport', 'racing/nascar-premier', 'NASCAR Cup Series'],
    ['motorsport', 'racing/nascar-truck', 'NASCAR Truck'],
    ['motorsport', 'racing/irl', 'IndyCar Series'],
    ['motorsport', 'racing/nhra', 'NHRA Drag Racing'],
    // Tennis
    ['tennis', 'tennis/atp', 'ATP World Tour'],
    ['tennis', 'tennis/wta', 'WTA Tour'],
    // Golf
    ['golf', 'golf/pga', 'PGA Tour'],
    ['golf', 'golf/lpga', 'LPGA'],
    ['golf', 'golf/eur', 'DP World Tour'],
    // Fighting
    ['fighting', 'mma/ufc', 'UFC'],
    ['fighting', 'mma/pfl', 'PFL'],
    ['fighting', 'mma/bellator', 'Bellator'],
    // Baseball
    ['baseball', 'baseball/mlb', 'MLB'],
    // Basketball
    ['basketball', 'basketball/nba', 'NBA'],
    ['basketball', 'basketball/wnba', 'WNBA'],
    // American Football
    ['amfootball', 'football/nfl', 'NFL'],
    ['amfootball', 'football/cfl', 'CFL'],
    ['amfootball', 'football/college-football', 'NCAA Football'],
    // Ice Hockey
    ['icehockey', 'hockey/nhl', 'NHL'],
];

// =============================================================================
// HTTP helper (iPhone UA, SSL verify off, socket fallback) — same as IBO
// =============================================================================
function sports_http_json(string $url): ?array {
    $raw = false;
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_TIMEOUT        => 8,
            CURLOPT_CONNECTTIMEOUT => 6,
            CURLOPT_USERAGENT      => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
            CURLOPT_HTTPHEADER     => ['Accept: application/json'],
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => 0,
        ]);
        $raw = curl_exec($ch);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if ($raw === false || $raw === '' || $code < 200 || $code >= 400) { $raw = false; }
    }
    if ($raw === false && ini_get('allow_url_fopen')) {
        $ctx = stream_context_create([
            'http' => ['timeout' => 8, 'header' => "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1\r\nAccept: application/json\r\n", 'ignore_errors' => true],
            'ssl' => ['verify_peer' => false, 'verify_peer_name' => false],
        ]);
        $raw = @file_get_contents($url, false, $ctx);
        if ($raw === false || $raw === '') { $raw = false; }
    }
    if ($raw === false || $raw === '') { return null; }
    $j = json_decode($raw, true);
    return is_array($j) ? $j : null;
}

// =============================================================================
// Auto-import: re-import if stale (>6 hours) or empty. Same as IBO.
// =============================================================================
function sports_auto_import(array $leagues): void {
    global $db;
    $last = trim((string) ($db->selectScalar('sports_fixtures_cache', 'MAX(fetched_at) as m', "cache_key = 'sport:import'")['m'] ?? ''));
    $ts = $last !== '' ? (int) $last : 0;
    $fresh = $ts > 0 && (time() - $ts) < 21600; // 6 hours

    $count = 0;
    try {
        $count = (int) $db->count('sport_events', 'event_date >= :d', [':d' => gmdate('Y-m-d')]);
    } catch (Throwable $e) { $count = 0; }

    if ($fresh && $count > 0) { return; }

    @set_time_limit(120);
    ignore_user_abort(true);

    $beg = gmdate('Ymd');
    $end = gmdate('Ymd', strtotime('+6 day') ?: time());
    $rBeg = gmdate('Y-m-d');
    $rEnd = gmdate('Y-m-d', strtotime('+6 day') ?: time());

    $rows = [];
    $attempts = 0;
    $hits = 0;
    foreach ($leagues as [$sport, $path, $name]) {
        $attempts++;
        $j = sports_http_json("https://site.web.api.espn.com/apis/site/v2/sports/$path/scoreboard?dates=$beg-$end");
        if ($j === null) { continue; }
        $hits++;
        $lb = $j['leagues'][0]['logos'][0]['href'] ?? '';
        foreach (($j['events'] ?? []) ?: [] as $e) {
            $comp = $e['competitions'][0] ?? [];
            $home = null; $away = null;
            foreach (($comp['competitors'] ?? []) as $x) {
                if (($x['homeAway'] ?? '') === 'home') { $home = $x; }
                elseif (($x['homeAway'] ?? '') === 'away') { $away = $x; }
            }
            $iso  = (string) ($e['date'] ?? '');
            $date = substr($iso, 0, 10);
            $time = substr($iso, 11, 5);
            if ($date < $rBeg || $date > $rEnd) { continue; }

            $ch = [];
            foreach (($comp['broadcasts'] ?? []) as $b) {
                foreach (($b['names'] ?? []) as $nm) { $ch[] = $nm; }
            }
            if ($ch === []) {
                foreach (($comp['geoBroadcasts'] ?? []) as $b) {
                    $nm = $b['media']['shortName'] ?? '';
                    if ($nm !== '') { $ch[] = $nm; }
                }
            }
            $ch = array_values(array_unique(array_filter($ch)));

            $state  = $comp['status']['type']['state'] ?? '';
            $status = $state === 'in' ? 'live' : ($state === 'post' ? 'final' : '');

            if ($home !== null) {
                $score = '';
                if ($state === 'in' || $state === 'post') {
                    $hs = (string) ($home['score'] ?? '');
                    $as = (string) ($away['score'] ?? '');
                    if ($hs !== '' || $as !== '') { $score = $hs . '-' . $as; }
                }
                $rows[] = [
                    'category' => $sport, 'league' => $name,
                    'home' => trim((string) ($home['team']['displayName'] ?? '')),
                    'away' => $away ? trim((string) ($away['team']['displayName'] ?? '')) : '',
                    'date' => $date, 'time' => $time, 'channels' => implode(', ', $ch),
                    'ext_id' => (string) ($e['id'] ?? ''),
                    'home_badge' => (string) ($home['team']['logo'] ?? ''),
                    'away_badge' => $away ? (string) ($away['team']['logo'] ?? '') : '',
                    'league_badge' => (string) $lb, 'status' => $status, 'score' => $score,
                ];
            } else {
                $title = trim((string) ($e['name'] ?? $e['shortName'] ?? ''));
                if ($title === '') { continue; }
                $rows[] = [
                    'category' => $sport, 'league' => $name, 'home' => $title, 'away' => '',
                    'date' => $date, 'time' => $time, 'channels' => implode(', ', $ch),
                    'ext_id' => (string) ($e['id'] ?? ''),
                    'home_badge' => '', 'away_badge' => '', 'league_badge' => (string) $lb,
                    'status' => $status, 'score' => '',
                ];
            }
        }
    }

    if ($attempts > 0 && ($hits / $attempts) < 0.5) { return; }

    // Replace: delete past + current-window ESPN events, then insert fresh.
    $db->delete('sport_events', "event_date < :d", [':d' => $rBeg]);
    $db->delete('sport_events', "event_date >= :d1 AND event_date <= :d2", [':d1' => $rBeg, ':d2' => $rEnd]);
    $k = 0;
    foreach ($rows as $r) {
        $db->insert('sport_events', [
            'league' => $r['league'], 'home' => $r['home'], 'away' => $r['away'],
            'event_date' => $r['date'], 'event_time' => $r['time'], 'channels' => $r['channels'],
            'sort' => $k, 'created_at' => gmdate('c'), 'source' => 'espn', 'ext_id' => $r['ext_id'],
            'category' => $r['category'], 'home_badge' => $r['home_badge'], 'away_badge' => $r['away_badge'],
            'league_badge' => $r['league_badge'], 'status' => $r['status'], 'score' => $r['score'],
        ]);
        $k++;
    }
    $db->delete('sports_fixtures_cache', "cache_key = 'sport:import'");
    $db->insert('sports_fixtures_cache', ['cache_key' => 'sport:import', 'json' => (string) time(), 'fetched_at' => time()]);
}

// =============================================================================
// Load events from DB (next 7 days)
// =============================================================================
function sports_events_window(int $days): array {
    global $db;
    $today = gmdate('Y-m-d');
    $until = gmdate('Y-m-d', strtotime($today . ' +' . ($days - 1) . ' day') ?: time());
    return $db->select('sport_events', '*', 'event_date >= :d1 AND event_date <= :d2', 'event_date ASC, event_time ASC, sort ASC, id ASC', [':d1' => $today, ':d2' => $until]);
}

// =============================================================================
// Render the guide
// =============================================================================
sports_auto_import($ESPN_LEAGUES);

$days = 7;
$events = sports_events_window($days);

// Build sport -> league -> events tree (same as IBO).
$catName = static function (string $k): string {
    $map = ['soccer'=>'Football','basketball'=>'Basketball','icehockey'=>'Ice Hockey','baseball'=>'Baseball','amfootball'=>'Am. Football','motorsport'=>'Motorsport','fighting'=>'Boxing/MMA','tennis'=>'Tennis','golf'=>'Golf','rugby'=>'Rugby','cricket'=>'Cricket','volleyball'=>'Volleyball'];
    return $map[$k] ?? ($k === '' ? 'Football' : ucfirst($k));
};

$tree = [];
foreach ($events as $e) {
    $sk = $e['category'] !== '' ? $e['category'] : 'soccer';
    $lg = $e['league'] !== '' ? $e['league'] : $catName($sk);
    if (!isset($tree[$sk])) { $tree[$sk] = []; }
    if (!isset($tree[$sk][$lg])) { $tree[$sk][$lg] = ['badge' => '', 'events' => []]; }
    if ($tree[$sk][$lg]['badge'] === '' && $e['league_badge'] !== '') { $tree[$sk][$lg]['badge'] = $e['league_badge']; }
    $tree[$sk][$lg]['events'][] = [
        'home' => $e['home'], 'away' => $e['away'], 'date' => $e['event_date'], 'time' => $e['event_time'],
        'hb' => $e['home_badge'], 'ab' => $e['away_badge'],
        'ch' => $e['channels'], 'st' => $e['status'] ?? '', 'sc' => $e['score'] ?? '',
    ];
}
$sports = [];
foreach ($tree as $sk => $lgs) {
    $leagues = [];
    $cnt = 0;
    foreach ($lgs as $ln => $ld) {
        $leagues[] = ['name' => $ln, 'badge' => $ld['badge'], 'events' => $ld['events']];
        $cnt += count($ld['events']);
    }
    usort($leagues, static fn ($a, $b) => count($b['events']) <=> count($a['events']));
    $sports[] = ['key' => $sk, 'name' => $catName($sk), 'count' => $cnt, 'leagues' => $leagues];
}
usort($sports, static fn ($a, $b) => $b['count'] <=> $a['count']);

$T = [
    'ss'=>'Search Sports','sl'=>'Search League','se'=>'Search Events','allsports'=>'All Sports',
    'season'=>'Season','vs'=>'vs','live'=>'LIVE','final'=>'Final','empty'=>'No events scheduled',
    'wd'=>['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
    'mon'=>['','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
    'cat'=>['soccer'=>'Football','basketball'=>'Basketball','icehockey'=>'Ice Hockey','baseball'=>'Baseball','amfootball'=>'Am. Football','motorsport'=>'Motorsport','fighting'=>'Boxing/MMA','tennis'=>'Tennis','golf'=>'Golf','rugby'=>'Rugby','cricket'=>'Cricket','volleyball'=>'Volleyball'],
];

$jflags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT;
$json = json_encode(['sports' => $sports], $jflags);
$tj   = json_encode($T, $jflags);
$esc  = static fn ($s) => htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');

header('Content-Type: text/html; charset=utf-8');

$css = <<<'CSS'
:root{--bg:#0b0716;--fg:#ece9f8;--accent:#b98cff;--accent2:#7c3aed;--muted:rgba(236,233,248,.56);
--glass:linear-gradient(160deg,rgba(255,255,255,.075),rgba(255,255,255,.022));
--stroke:rgba(255,255,255,.10);--stroke2:rgba(185,140,255,.34)}
*{box-sizing:border-box;margin:0;padding:0}
html{font-size:clamp(13px,0.42vw + 0.35vh,17px);-webkit-text-size-adjust:100%}
body{color:var(--fg);font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;line-height:1.25;
background:radial-gradient(125% 75% at 50% -12%,rgba(124,58,237,.16),transparent 55%),#0b0716;
background-attachment:fixed;height:100dvh;overflow:hidden}
.app{display:grid;grid-template-columns:minmax(0,.82fr) minmax(0,1fr) minmax(0,1.75fr);
gap:clamp(.4rem,1vw,.85rem);height:100dvh;padding:clamp(.4rem,1.4vw,1rem)}
.pane{background:var(--glass);backdrop-filter:blur(16px) saturate(1.3);-webkit-backdrop-filter:blur(16px) saturate(1.3);
border:1px solid var(--stroke);border-radius:1rem;display:flex;flex-direction:column;min-height:0;overflow:hidden}
.search{margin:.55rem;padding:.6em .9em;font:inherit;font-size:clamp(.8rem,1.15vw,1rem);color:var(--fg);
background:rgba(255,255,255,.05);border:1px solid var(--stroke);border-radius:.7rem;outline:none}
.search:focus{border-color:var(--accent);box-shadow:0 0 0 2px rgba(185,140,255,.4)}
.search::placeholder{color:var(--muted)}
.list{overflow-y:auto;flex:1;padding:.3rem .5rem .6rem;display:flex;flex-direction:column;gap:.25rem}
.row{display:flex;align-items:center;gap:.65rem;padding:.58rem .7rem;border-radius:.7rem;cursor:pointer;outline:none;
border:1px solid transparent;scroll-margin:.7rem}
.row:focus,.row:hover{background:rgba(255,255,255,.07);border-color:var(--stroke2)}
.row.sel{background:linear-gradient(135deg,rgba(124,58,237,.55),rgba(185,140,255,.26));border-color:transparent}
.row.empty{opacity:.5}.row.empty.sel,.row.empty:focus{opacity:1}
.row .ic{width:1.6rem;height:1.6rem;flex-shrink:0;display:flex;align-items:center;justify-content:center;color:var(--accent)}
.row .ic svg{width:100%;height:100%}.row .ic img{width:100%;height:100%;object-fit:contain}
.row .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:700;font-size:clamp(.85rem,1.15vw,1.05rem)}
.row .cnt{color:var(--muted);font-size:.82em;font-weight:700;font-variant-numeric:tabular-nums}
.row.sel .cnt{color:rgba(255,255,255,.85)}
.detail{padding:clamp(.9rem,2vw,1.5rem) 1rem;text-align:center;border-bottom:1px solid var(--stroke)}
.detail img{height:clamp(3.4rem,8vw,5.6rem);width:auto;object-fit:contain;margin:.4rem auto;display:block;filter:drop-shadow(0 3px 8px rgba(0,0,0,.5))}
.detail h2{font-size:clamp(1.05rem,1.8vw,1.5rem);font-weight:800;text-wrap:balance}
.detail .sub{color:var(--muted);font-size:clamp(.76rem,1.05vw,.92rem);margin-top:.12rem}
.detail .season{color:var(--accent);font-weight:700}
.ev{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.7rem;padding:.62rem .8rem;border-radius:.8rem;
border:1px solid transparent;outline:none;cursor:pointer;scroll-margin:.7rem}
.ev:focus,.ev:hover{background:rgba(255,255,255,.07);border-color:var(--stroke2)}
.ev .eb{width:clamp(1.8rem,3.2vw,2.5rem);height:clamp(1.8rem,3.2vw,2.5rem);flex-shrink:0;display:flex;align-items:center;justify-content:center}
.ev .eb img{width:100%;height:100%;object-fit:contain}
.ev .mid{text-align:center;min-width:0}
.ev .mt{font-weight:800;font-size:clamp(.9rem,1.3vw,1.15rem);overflow-wrap:break-word}
.ev .dt{color:var(--muted);font-size:.8em;margin-top:.15rem}
.stx{font-weight:800;font-size:.92em;padding:.08em .5em;border-radius:.4rem;white-space:nowrap}
.stx.live{color:#fff;background:linear-gradient(135deg,var(--accent2),var(--accent));box-shadow:0 0 .6rem rgba(185,140,255,.5)}
.stx.fin{color:var(--muted);border:1px solid var(--stroke)}
.ev .ch{display:flex;flex-wrap:wrap;gap:.3rem;justify-content:center;margin-top:.35rem}
.ev .ch span{font-size:.72em;font-weight:600;padding:.16em .55em;border-radius:.4rem;background:rgba(255,255,255,.06);border:1px solid var(--stroke);color:rgba(236,233,248,.82)}
.empty{padding:2.5rem 1rem;text-align:center;color:var(--muted)}
@media(max-width:640px){.app{gap:.3rem;padding:.3rem}.search{margin:.35rem;padding:.5em .6em}
.list{padding:.2rem .25rem .4rem}.row{padding:.45rem .5rem;gap:.4rem}.row .ic{width:1.3rem;height:1.3rem}
.ev{padding:.5rem .5rem;gap:.4rem}.detail{padding:.7rem .5rem}.detail img{height:2.6rem}}
@media(prefers-reduced-motion:reduce){*{transition:none!important}}
CSS;

$js = <<<'JS'
(function(){
var D=window.__SPORTS__||{sports:[]},T=window.__T__||{};
var sports=D.sports||[];
var $=function(i){return document.getElementById(i)};
var c1=$("c1"),c2=$("c2"),c3=$("c3"),c3h=$("c3h"),s1=$("s1"),s2=$("s2"),s3=$("s3");
s1.placeholder=T.ss||"";s2.placeholder=T.sl||"";s3.placeholder=T.se||"";
var BALL='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9"/><path d="M12 7.2l4.3 3.1-1.6 5h-5.4l-1.6-5z"/></svg>';
var ICON={all:'<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="3" width="7.5" height="7.5" rx="1.6"/><rect x="13.5" y="3" width="7.5" height="7.5" rx="1.6"/><rect x="3" y="13.5" width="7.5" height="7.5" rx="1.6"/><rect x="13.5" y="13.5" width="7.5" height="7.5" rx="1.6"/></svg>',
soccer:BALL,
basketball:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3v18M5.6 5.6c3.4 3.4 3.4 9.4 0 12.8M18.4 5.6c-3.4 3.4-3.4 9.4 0 12.8"/></svg>',
baseball:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9"/><path d="M6.8 5c2.2 3.2 2.2 10.8 0 14M17.2 5c-2.2 3.2-2.2 10.8 0 14"/></svg>',
amfootball:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><ellipse cx="12" cy="12" rx="9" ry="5.6"/><path d="M8.5 12h7M12 9.7v4.6"/></svg>',
tennis:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9"/><path d="M5.2 6.4c4 2.4 4 8.8 0 11.2M18.8 6.4c-4 2.4-4 8.8 0 11.2"/></svg>',
motorsport:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M5 21V4h13l-2.4 4L18 12H5"/></svg>',
icehockey:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M4 4l7 13"/><ellipse cx="14.5" cy="18.5" rx="5" ry="1.8"/></svg>',
fighting:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M7 8a3 3 0 0 1 3-3h4a4 4 0 0 1 4 4v3a4 4 0 0 1-4 4H9a3 3 0 0 1-3-3zM7 10H5a2 2 0 0 0 0 4h2"/></svg>',
golf:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M9 21V3l8 3.2L9 9.4"/><ellipse cx="11" cy="21" rx="6" ry="1.6"/></svg>',
rugby:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><ellipse cx="12" cy="12" rx="9" ry="5.6" transform="rotate(-40 12 12)"/><path d="M10 14l4-4M11 11.5l1.6 1.6M12.4 10.1l1.6 1.6"/></svg>'};
function icon(k){return ICON[k]||BALL}
function esc(s){var d=document.createElement("div");d.textContent=s==null?"":String(s);return d.innerHTML}
function el(t,c){var e=document.createElement(t);if(c)e.className=c;return e}
var curSport=null,curLeague=null;
function sportByKey(k){for(var i=0;i<sports.length;i++)if(sports[i].key===k)return sports[i];return null}
function allLeagues(){var a=[];sports.forEach(function(s){s.leagues.forEach(function(l){a.push(l)})});a.sort(function(x,y){return y.events.length-x.events.length});return a}
function currentLeagues(){if(curSport==="all")return allLeagues();var s=sportByKey(curSport);return s?s.leagues:[]}
function curLeagueObj(){var ls=currentLeagues();for(var i=0;i<ls.length;i++)if(ls[i].name===curLeague)return ls[i];return null}
function sportNameOfLeague(l){for(var i=0;i<sports.length;i++){var s=sports[i];for(var j=0;j<s.leagues.length;j++)if(s.leagues[j].name===l.name)return s.name}return ""}
function season(evs){if(!evs.length)return "";var y=parseInt(evs[0].date.slice(0,4),10),m=parseInt(evs[0].date.slice(5,7),10);if(!y)return "";var a=m>=7?y:y-1;return (T.season||"")+" "+a+"-"+(a+1)}
function dt(e){var d=new Date((e.date||"")+"T"+(e.time||"00:00")+":00Z");if(isNaN(d.getTime()))return (e.date||"")+(e.time?" "+e.time:"");
var wd=(T.wd&&T.wd[d.getDay()])||"",mn=(T.mon&&T.mon[d.getMonth()+1])||"",hh=("0"+d.getHours()).slice(-2),mm=("0"+d.getMinutes()).slice(-2);
return wd+" "+d.getDate()+" "+mn+"  ·  "+hh+":"+mm}
var SPORT_ORDER=["soccer","basketball","baseball","amfootball","icehockey","motorsport","fighting","tennis","golf","rugby","cricket","volleyball"];
function renderSports(){
 c1.innerHTML="";var total=0,byk={};sports.forEach(function(s){total+=s.count;byk[s.key]=s});
 var order=SPORT_ORDER.slice();sports.forEach(function(s){if(order.indexOf(s.key)<0)order.push(s.key)});
 var rows=[{key:"all",name:T.allsports||"All",count:total}];
 order.forEach(function(k){var s=byk[k];rows.push({key:k,name:(T.cat&&T.cat[k])||k,count:s?s.count:0})});
 rows.forEach(function(s){
  var r=el("div","row"+(curSport===s.key?" sel":"")+(s.count?"":" empty"));r.tabIndex=0;r.setAttribute("data-k",s.key);
  r.innerHTML='<span class="ic">'+icon(s.key)+'</span><span class="nm">'+esc(s.name)+'</span><span class="cnt">'+s.count+'</span>';
  r.addEventListener("focus",function(){selectSport(s.key)});
  r.addEventListener("click",function(){selectSport(s.key)});
  c1.appendChild(r);
 });
}
function selectSport(key){
 curSport=key;
 [].slice.call(c1.children).forEach(function(r){r.classList.toggle("sel",r.getAttribute("data-k")===key)});
 renderLeagues("");
}
function renderLeagues(filter){
 c2.innerHTML="";var ls=currentLeagues(),f=(filter||"").toLowerCase(),first=null;
 ls.forEach(function(l){
  if(f&&l.name.toLowerCase().indexOf(f)<0)return;
  var r=el("div","row");r.tabIndex=0;r.setAttribute("data-l",l.name);r._l=l;
  var ic=l.badge?'<img src="'+esc(l.badge)+'" alt="" onerror="this.remove()">':icon("soccer");
  r.innerHTML='<span class="ic">'+ic+'</span><span class="nm">'+esc(l.name)+'</span><span class="cnt">'+l.events.length+'</span>';
  r.addEventListener("focus",function(){selectLeague(l)});
  r.addEventListener("click",function(){selectLeague(l)});
  c2.appendChild(r);if(!first)first=r;
 });
 if(first){selectLeague(first._l)}else{c3h.innerHTML="";c3.innerHTML='<div class="empty">'+esc(T.empty||"")+'</div>'}
}
function markLeague(n){[].slice.call(c2.children).forEach(function(r){r.classList.toggle("sel",r.getAttribute("data-l")===n)})}
function selectLeague(l){
 if(!l)return;curLeague=l.name;markLeague(l.name);
 var head=(l.badge?'<img src="'+esc(l.badge)+'" alt="" onerror="this.remove()">':'')
  +'<h2>'+esc(l.name)+'</h2><div class="sub">'+esc(sportNameOfLeague(l))+'</div>'
  +'<div class="sub season">'+esc(season(l.events))+'</div>';
 c3h.innerHTML=head;renderEvents("");
}
function renderEvents(filter){
 c3.innerHTML="";var l=curLeagueObj();if(!l)return;var f=(filter||"").toLowerCase();
 l.events.forEach(function(e){
  var name=e.away?(e.home+" "+(T.vs||"vs")+" "+e.away):e.home;
  if(f&&name.toLowerCase().indexOf(f)<0)return;
  var r=el("div","ev");r.tabIndex=0;
  var hb='<span class="eb">'+(e.hb?'<img src="'+esc(e.hb)+'" alt="" onerror="this.remove()">':'')+'</span>';
  var ab='<span class="eb">'+(e.ab?'<img src="'+esc(e.ab)+'" alt="" onerror="this.remove()">':'')+'</span>';
  var st="";
  if(e.st==="live")st=' <span class="stx live">'+esc(T.live||"LIVE")+(e.sc?" "+esc(e.sc):"")+'</span>';
  else if(e.st==="final")st=' <span class="stx fin">'+esc(T.final||"Final")+(e.sc?" "+esc(e.sc):"")+'</span>';
  var chips="";
  if(e.ch&&e.ch.length){chips='<div class="ch">';e.ch.forEach(function(c){chips+='<span>'+esc(c)+'</span>'});chips+='</div>';}
  var mid='<div class="mid"><div class="mt">'+esc(name)+'</div><div class="dt">'+esc(dt(e))+st+'</div>'+chips+'</div>';
  r.innerHTML=e.away?(hb+mid+ab):('<span class="eb"></span>'+mid+'<span class="eb"></span>');
  c3.appendChild(r);
 });
}
s1.addEventListener("input",function(){var v=(this.value||"").toLowerCase();[].slice.call(c1.children).forEach(function(r){var n=r.querySelector(".nm");r.classList.toggle("hide",!!v&&n&&n.textContent.toLowerCase().indexOf(v)<0)})});
s2.addEventListener("input",function(){renderLeagues(this.value)});
s3.addEventListener("input",function(){renderEvents(this.value)});
function foc(){return [].slice.call(document.querySelectorAll(".row:not(.hide),.ev:not(.hide)"))}
function move(dir){var cur=document.activeElement,list=foc();if(!cur||list.indexOf(cur)<0){if(list[0])list[0].focus();return}
 var cr=cur.getBoundingClientRect(),cx=cr.left+cr.width/2,cy=cr.top+cr.height/2,best=null,bs=1e9;
 list.forEach(function(e){if(e===cur)return;var r=e.getBoundingClientRect(),x=r.left+r.width/2,y=r.top+r.height/2,dx=x-cx,dy=y-cy;
  var ok=(dir=="left"&&dx<-4)||(dir=="right"&&dx>4)||(dir=="up"&&dy<-4)||(dir=="down"&&dy>4);if(!ok)return;
  var ax=(dir=="left"||dir=="right")?Math.abs(dx):Math.abs(dy),cs=(dir=="left"||dir=="right")?Math.abs(dy):Math.abs(dx),s=ax+cs*2.2;
  if(s<bs){bs=s;best=e}});
 if(best){best.focus();if(best.scrollIntoView)best.scrollIntoView({block:"nearest",inline:"nearest"})}}
document.addEventListener("keydown",function(e){var a=document.activeElement;if(a&&a.tagName=="INPUT")return;var k=e.key,c=e.keyCode;
 if(k=="ArrowLeft"||c==37){e.preventDefault();move("left")}
 else if(k=="ArrowRight"||c==39){e.preventDefault();move("right")}
 else if(k=="ArrowUp"||c==38){e.preventDefault();move("up")}
 else if(k=="ArrowDown"||c==40){e.preventDefault();move("down")}});
renderSports();
selectSport(sports.length?sports[0].key:"all");
var f0=c1.querySelector(".row");if(f0){try{f0.focus({preventScroll:true})}catch(e){f0.focus()}}
})();
JS;

echo '<!doctype html><html lang="en"><head><meta charset="utf-8">'
   . '<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">'
   . '<title>Sports</title><style>' . $css . '</style></head><body>'
   . '<div class="app">'
   . '<section class="pane" id="p1"><input class="search" id="s1" type="search"><div class="list" id="c1"></div></section>'
   . '<section class="pane" id="p2"><input class="search" id="s2" type="search"><div class="list" id="c2"></div></section>'
   . '<section class="pane" id="p3"><div class="detail" id="c3h"></div><input class="search" id="s3" type="search"><div class="list" id="c3"></div></section>'
   . '</div>'
   . '<script>window.__SPORTS__=' . $json . ';window.__T__=' . $tj . ';</script>'
   . '<script>' . $js . '</script></body></html>';
