<?php require_once __DIR__ . '/includes/bootstrap.php';
$pageTitle = 'Games | Underground FX Radio';
$currentPage = basename(__FILE__);
$games = ugfx_games_for_public();
$allStats = ugfx_game_stats();
$totalGames = count(ugfx_games_catalog());
$onlineGames = count($games);
$featuredGames = array_filter($games, fn($g) => !empty($g['settings']['featured'] ?? false));
$featuredGames = $featuredGames ?: $games;
$spotlight = reset($featuredGames) ?: reset($games);
$engineOrder = ['reaction','memory','pattern','runner','quiz','burst'];
$engineLabels = ['reaction'=>'Reaction','memory'=>'Memory','pattern'=>'Pattern','runner'=>'Runner','quiz'=>'Quiz','burst'=>'Burst'];
$engineIcons = ['reaction'=>'bi-lightning-charge','memory'=>'bi-grid-3x3-gap','pattern'=>'bi-soundwave','runner'=>'bi-signpost-split','quiz'=>'bi-patch-question','burst'=>'bi-bullseye'];
$engineCounts = [];
foreach ($engineOrder as $engine) {
    $engineCounts[$engine] = count(array_filter($games, fn($g) => ($g['type'] ?? '') === $engine));
}
include __DIR__ . '/includes/header.php';
?>
<section class="ugfx-page-hero ugfx-arcade-hero">
  <div class="container-xxl position-relative">
    <div class="row g-4 align-items-center">
      <div class="col-lg-7">
        <div class="ugfx-kicker"><i class="bi bi-controller"></i> Underground FX Arcade</div>
        <h1 class="page-title">Arcade mode is live</h1>
        <p class="page-copy">A full browser arcade with reaction games, pattern tests, memory boards, runner challenges, quiz sets, and leaderboard battles. Station staff can take any game on or offline without touching the rest of the site.</p>
        <div class="d-flex flex-wrap gap-2 mt-4">
          <span class="ugfx-chip ugfx-chip-blue"><?= $onlineGames ?> online games</span>
          <span class="ugfx-chip"><?= $totalGames ?> total games</span>
          <span class="ugfx-chip"><?= count($featuredGames) ?> spotlight picks</span>
        </div>
      </div>
      <div class="col-lg-5">
        <div class="ugfx-card p-4 p-lg-5 ugfx-arcade-spotlight">
          <div class="ugfx-micro-label">ARCADE SPOTLIGHT</div>
          <?php if ($spotlight): ?>
          <h2 class="mb-2"><?= htmlspecialchars($spotlight['name']) ?></h2>
          <p class="text-secondary mb-3"><?= htmlspecialchars($spotlight['description']) ?></p>
          <div class="d-flex gap-2 flex-wrap mb-4">
            <span class="ugfx-chip"><?= htmlspecialchars(ucfirst($spotlight['type'])) ?></span>
            <span class="ugfx-chip"><?= htmlspecialchars(ucfirst($spotlight['difficulty'])) ?></span>
            <span class="ugfx-chip ugfx-chip-blue">Top <?= (int)($allStats[$spotlight['id']]['top_score'] ?? 0) ?> <?= htmlspecialchars($spotlight['unit']) ?></span>
          </div>
          <button class="btn ugfx-btn-primary" type="button" data-quick-open="<?= htmlspecialchars($spotlight['id']) ?>">Play spotlight game</button>
          <?php else: ?>
          <h2 class="mb-2">Arcade standby</h2>
          <p class="text-secondary mb-0">The game page is live, but every game has been taken offline from the admin area.</p>
          <?php endif; ?>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section-pad pt-3">
  <div class="container-xxl">
    <?php if (!$games): ?>
      <div class="ugfx-card p-5 text-center">
        <div class="ugfx-micro-label">ARCADE OFFLINE</div>
        <h2 class="mb-3">No games are online right now</h2>
        <p class="text-secondary mb-0">The station team has temporarily taken the arcade offline. Check back later for the next competition drop.</p>
      </div>
    <?php else: ?>
    <div class="row g-4 mb-4">
      <div class="col-lg-8">
        <div class="ugfx-card p-4 p-lg-5">
          <div class="d-flex justify-content-between gap-3 flex-wrap align-items-start mb-4">
            <div>
              <div class="ugfx-micro-label">SELECT A GAME ENGINE</div>
              <h2 class="mb-2">Choose your challenge</h2>
              <div class="text-secondary">Start by choosing one of the six arcade engines, then pick from the games inside it. The page stays clean on first load instead of dumping the full arcade list at once.</div>
            </div>
            <div class="d-flex flex-wrap gap-2">
              <button class="btn ugfx-btn-outline" type="button" data-clear-engine>Show all engines</button>
            </div>
          </div>
          <div class="ugfx-engine-grid mb-4" id="engineGrid">
            <?php foreach ($engineOrder as $engine): ?>
            <button class="ugfx-engine-card" type="button" data-engine-card="<?= htmlspecialchars($engine) ?>">
              <div class="d-flex justify-content-between align-items-start gap-3 mb-3">
                <div>
                  <div class="ugfx-micro-label">ENGINE</div>
                  <h3 class="mb-1"><?= htmlspecialchars($engineLabels[$engine]) ?></h3>
                </div>
                <i class="bi <?= htmlspecialchars($engineIcons[$engine]) ?> ugfx-game-icon"></i>
              </div>
              <div class="text-secondary small mb-3"><?= (int)$engineCounts[$engine] ?> games live in this lane</div>
              <div class="d-flex flex-wrap gap-2">
                <span class="ugfx-chip"><?= htmlspecialchars($engineLabels[$engine]) ?></span>
                <span class="ugfx-chip ugfx-chip-blue"><?= (int)$engineCounts[$engine] ?> games</span>
              </div>
            </button>
            <?php endforeach; ?>
          </div>
          <div class="d-flex justify-content-between gap-3 flex-wrap align-items-start mb-3">
            <div>
              <div class="ugfx-micro-label">ENGINE GAMES</div>
              <h3 class="mb-1" id="engineTitle">Pick an engine above</h3>
              <div class="text-secondary small" id="engineCopy">Once you choose an engine, its games will load here.</div>
            </div>
          </div>
          <div class="ugfx-game-grid" id="gameGrid"></div>
          <div class="text-secondary small mt-3" id="gameGridEmpty">Choose one of the six engines above to load its games.</div>
        </div>
      </div>
      <div class="col-lg-4">
        <div class="ugfx-card p-4 h-100">
          <div class="ugfx-micro-label">ARCADE CONTROL ROOM</div>
          <h3 class="mb-3">What is live right now</h3>
          <div class="d-grid gap-3">
            <div class="ugfx-mini-stat"><strong><?= $onlineGames ?></strong><span>Games online</span></div>
            <div class="ugfx-mini-stat"><strong><?= count(array_filter($allStats, fn($s) => !empty($s['leaderboard_enabled']))) ?></strong><span>Leaderboards live</span></div>
            <div class="ugfx-mini-stat"><strong><?= array_sum(array_map(fn($s) => (int)($s['plays'] ?? 0), $allStats)) ?></strong><span>Total saved scores</span></div>
          </div>
          <div class="ugfx-divider my-4"></div>
          <div class="text-secondary small">Need a fresh competition round? The admin side can now reset one board, all boards, hide a game, or take the whole arcade offline without touching the page code.</div>
        </div>
      </div>
    </div>

    <div class="row g-4 align-items-start">
      <div class="col-xl-8">
        <div class="ugfx-card p-4 p-lg-5" id="arcadePlayShell">
          <div class="d-flex justify-content-between gap-3 flex-wrap align-items-start mb-3">
            <div>
              <div class="ugfx-micro-label" id="activeGameType">GAME ENGINE</div>
              <h2 id="activeGameTitle">Loading arcade…</h2>
              <p class="text-secondary mb-0" id="activeGameDesc"></p>
            </div>
            <div class="d-flex gap-2 flex-wrap" id="activeGameBadges"></div>
          </div>
          <div id="arcadeMount"></div>
        </div>
      </div>
      <div class="col-xl-4">
        <div class="ugfx-card p-4 mb-4">
          <div class="d-flex justify-content-between align-items-start gap-3 mb-3">
            <div>
              <div class="ugfx-micro-label">LEADERBOARD</div>
              <h3 class="mb-0" id="leaderboardTitle">Top players</h3>
            </div>
            <span class="ugfx-chip" id="leaderboardUnit">pts</span>
          </div>
          <div class="text-secondary small mb-3" id="leaderboardDesc">Loading scores…</div>
          <div id="leaderboardBox"><div class="text-secondary">Loading leaderboard…</div></div>
        </div>
        <div class="ugfx-card p-4">
          <div class="ugfx-micro-label">HOW SCORING WORKS</div>
          <h3 class="mb-2">One arcade, many modes</h3>
          <div class="text-secondary small">Every game stores its own leaderboard. Save as many runs as you want. The admin panel can instantly reset a single board, clear everything, or hide a game while you set up new station events.</div>
        </div>
      </div>
    </div>
    <?php endif; ?>
  </div>
</section>

<style>
.ugfx-arcade-hero{position:relative;overflow:hidden}
.ugfx-arcade-hero::after{content:"";position:absolute;inset:0;background:radial-gradient(circle at top right, rgba(255,123,0,.14), transparent 45%);pointer-events:none}
.ugfx-arcade-spotlight{min-height:100%}
.ugfx-engine-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.ugfx-game-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.ugfx-engine-card,.ugfx-arcade-card{padding:22px;border-radius:26px;border:1px solid rgba(255,123,0,.14);background:linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,123,0,.05));text-align:left;color:#fff;transition:transform .18s ease, border-color .18s ease, box-shadow .18s ease}
.ugfx-engine-card:hover,.ugfx-engine-card.is-active,.ugfx-arcade-card:hover,.ugfx-arcade-card.is-active{transform:translateY(-2px);border-color:rgba(255,145,80,.42);box-shadow:0 24px 60px rgba(0,0,0,.25),0 0 0 1px rgba(255,145,80,.18) inset}
.ugfx-game-icon{font-size:1.75rem;color:#ff9a55}
.ugfx-mini-stat{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border:1px solid rgba(255,123,0,.14);border-radius:18px;background:rgba(255,255,255,.02)}
.ugfx-mini-stat strong{font-size:1.2rem}
.ugfx-mini-stat span{color:var(--ugfx-muted);font-size:.92rem}
.ugfx-divider{height:1px;background:rgba(255,255,255,.06)}
.ugfx-arcade-stage{border-radius:30px;border:1px solid rgba(255,123,0,.16);background:radial-gradient(circle at top, rgba(255,123,0,.16), rgba(8,9,18,.96));padding:24px;position:relative;overflow:hidden}
.ugfx-stage-shell{position:relative;min-height:340px;border-radius:26px;border:1px solid rgba(255,123,0,.18);background:rgba(6,7,16,.72);overflow:hidden}
.ugfx-stage-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;padding:24px;color:#f8efe8;font-weight:700;letter-spacing:.04em;background:rgba(10,11,22,.12)}
.ugfx-target{position:absolute;width:72px;height:72px;border:none;border-radius:50%;background:radial-gradient(circle at 30% 30%, #ffd39d, #ff6a00 55%, #341300 100%);box-shadow:0 0 0 6px rgba(255,120,35,.14),0 0 36px rgba(255,120,35,.72);transform:translate(-50%,-50%)}
.ugfx-memory-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}
.ugfx-memory-card{aspect-ratio:1/1;border-radius:22px;border:1px solid rgba(255,123,0,.15);background:linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,123,0,.08));color:#fff;font-size:1.6rem;font-weight:800}
.ugfx-memory-card.is-open,.ugfx-memory-card.is-matched{background:linear-gradient(180deg, rgba(255,123,0,.28), rgba(255,123,0,.12));box-shadow:0 0 0 1px rgba(255,145,80,.2) inset}
.ugfx-memory-card.is-matched{opacity:.82}
.ugfx-beat-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
.ugfx-beat-pad{aspect-ratio:1/1;border-radius:26px;border:1px solid rgba(255,123,0,.15);background:linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,123,0,.08));box-shadow:inset 0 0 0 1px rgba(255,255,255,.03)}
.ugfx-beat-pad.active{transform:scale(.985);box-shadow:0 0 0 2px rgba(255,182,114,.62) inset,0 0 34px rgba(255,120,35,.4)}
.ugfx-runner-track{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;height:340px;padding:14px}
.ugfx-runner-lane{position:relative;border-radius:22px;background:linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,123,0,.05));overflow:hidden}
 .ugfx-runner-player,.ugfx-runner-block{position:absolute;left:50%;transform:translateX(-50%);width:56px;height:56px;border-radius:18px}
.ugfx-runner-player{bottom:14px;background:radial-gradient(circle at 30% 30%, #ffd39d, #ff6a00 60%, #3c1800 100%);box-shadow:0 0 30px rgba(255,123,0,.4)}
.ugfx-runner-block{top:-60px;background:linear-gradient(180deg, rgba(255,255,255,.85), rgba(255,255,255,.32))}
.ugfx-runner-controls{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
.ugfx-runner-controls button{min-width:110px}
.ugfx-quiz-answers{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.ugfx-quiz-answer{padding:16px;border-radius:18px;border:1px solid rgba(255,123,0,.15);background:rgba(255,255,255,.03);color:#fff;text-align:left}
.ugfx-burst-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.ugfx-burst-pad{aspect-ratio:1/1;border-radius:22px;border:1px solid rgba(255,123,0,.15);background:linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,123,0,.05));opacity:.45}
.ugfx-burst-pad.live{opacity:1;box-shadow:0 0 0 2px rgba(255,182,114,.62) inset,0 0 32px rgba(255,123,0,.4)}
@media (max-width: 1199px){.ugfx-game-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width: 767px){.ugfx-game-grid,.ugfx-quiz-answers,.ugfx-memory-grid,.ugfx-burst-grid,.ugfx-beat-grid{grid-template-columns:1fr 1fr}.ugfx-stage-shell{min-height:280px}.ugfx-runner-track{height:280px}.ugfx-runner-controls{gap:8px}}
@media (max-width: 575px){.ugfx-game-grid,.ugfx-quiz-answers,.ugfx-memory-grid,.ugfx-burst-grid{grid-template-columns:1fr}.ugfx-beat-grid{grid-template-columns:1fr 1fr}}
</style>

<script>
(() => {
  const games = <?= json_encode(array_values($games), JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE) ?>;
  const lookup = Object.fromEntries(games.map(game => [game.id, game]));
  const stats = <?= json_encode($allStats, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE) ?>;
  const endpoint = 'api/games.php';
  const questionsByDifficulty = {
    easy:[
      {q:'Which page shows who is on air next?', a:['Schedule','News','Friends','Chat'], correct:0},
      {q:'What does a DJ usually do live on Underground FX?', a:['Hosts a show','Repairs browsers','Edits ZIP headers','Deletes streams'], correct:0},
      {q:'Which of these fits a radio request page?', a:['Song shout-out','Car tyre size','Tax form','Wi-Fi password'], correct:0},
      {q:'What does “live now” usually mean?', a:['Broadcast is active','Site is offline','No one is listening','Charts are empty'], correct:0},
    ],
    medium:[
      {q:'A popup player is mainly useful for what?', a:['Listening while browsing','Making coffee','Uploading PHP','Editing DNS'], correct:0},
      {q:'What does a leaderboard sort by?', a:['Highest score','Longest title','Newest browser','Biggest image'], correct:0},
      {q:'What does AutoDJ usually mean?', a:['Automated playout','Muted microphone','Broken CSS','Closed chat'], correct:0},
      {q:'Which area would fans use to submit a song request?', a:['Requests','Admin backup','Charts reset','404 page'], correct:0},
    ],
    hard:[
      {q:'Which score should rank higher?', a:['Higher score, then newer time','Older name alphabetically','Shortest player name','Lowest browser memory'], correct:0},
      {q:'A cached API response can briefly show what?', a:['Old labels','More bass','Bigger logos','New DNS'], correct:0},
      {q:'What is the safest way to hide a game from players?', a:['Take it offline in admin','Delete the homepage','Rename CSS','Turn off images'], correct:0},
      {q:'What should a game API reject when a title is offline?', a:['New score submissions','Images','Schedule entries','Audio'], correct:0},
    ]
  };
  const memorySets = {
    easy:['🎙️','🔥','🎧','📻','🎚️','⭐'],
    medium:['🎙️','🔥','🎧','📻','🎚️','⭐','🚀','🎵'],
    hard:['🎙️','🔥','🎧','📻','🎚️','⭐','🚀','🎵','🎤','💿']
  };

  const mount = document.getElementById('arcadeMount');
  const boardBox = document.getElementById('leaderboardBox');
  const boardTitle = document.getElementById('leaderboardTitle');
  const boardDesc = document.getElementById('leaderboardDesc');
  const boardUnit = document.getElementById('leaderboardUnit');
  const activeTitle = document.getElementById('activeGameTitle');
  const activeDesc = document.getElementById('activeGameDesc');
  const activeType = document.getElementById('activeGameType');
  const activeBadges = document.getElementById('activeGameBadges');
  const gameGrid = document.getElementById('gameGrid');
  const gameGridEmpty = document.getElementById('gameGridEmpty');
  const engineTitle = document.getElementById('engineTitle');
  const engineCopy = document.getElementById('engineCopy');
  const engineButtons = Array.from(document.querySelectorAll('[data-engine-card]'));
  const leaderboards = {};
  let activeGame = games[0] || null;
  let activeEngine = null;
  let cleanup = null;

  const arcadeName = () => localStorage.getItem('ugfx_arcade_name') || '';
  function askName(){
    const raw = prompt('Name for the leaderboard:', arcadeName());
    if (raw === null) return null;
    const clean = (raw.trim() || 'Guest').slice(0, 32);
    localStorage.setItem('ugfx_arcade_name', clean);
    return clean;
  }
  function escapeHtml(str){return String(str).replace(/[&<>"']/g, s => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[s]));}
  function shuffle(list){return [...list].sort(() => Math.random() - 0.5);}
  function randomRange(min,max){return Math.floor(Math.random()*(max-min+1))+min;}
  function activeCards(gameId){Array.from(document.querySelectorAll('[data-game-card]')).forEach(card => card.classList.toggle('is-active', card.dataset.gameCard === gameId));}
  function activeEngines(type){engineButtons.forEach(card => card.classList.toggle('is-active', card.dataset.engineCard === type));}
  function renderGameCards(type){
    activeEngine = type;
    activeEngines(type);
    const filtered = games.filter(game => game.type === type);
    engineTitle.textContent = `${type.charAt(0).toUpperCase()+type.slice(1)} engine`;
    engineCopy.textContent = `${filtered.length} games live in this engine. Pick one to load it below.`;
    gameGrid.innerHTML = filtered.map(game => `
      <button class="ugfx-arcade-card ${activeGame?.id === game.id ? 'is-active' : ''}" type="button" data-game-card="${escapeHtml(game.id)}" data-type="${escapeHtml(game.type)}">
        <div class="d-flex justify-content-between align-items-start gap-3 mb-3">
          <div>
            <div class="ugfx-micro-label">${escapeHtml(game.difficulty.toUpperCase())}</div>
            <h3 class="mb-1">${escapeHtml(game.name)}</h3>
          </div>
          <i class="bi ${escapeHtml(game.icon)} ugfx-game-icon"></i>
        </div>
        <div class="text-secondary small mb-3">${escapeHtml(game.tagline)}</div>
        <div class="d-flex flex-wrap gap-2">
          <span class="ugfx-chip">${escapeHtml(game.type.charAt(0).toUpperCase()+game.type.slice(1))}</span>
          <span class="ugfx-chip ugfx-chip-blue">Top ${Number(stats[game.id]?.top_score || 0)}</span>
        </div>
      </button>`).join('');
    gameGridEmpty.style.display = filtered.length ? 'none' : '';
    gameGrid.querySelectorAll('[data-game-card]').forEach(card => card.addEventListener('click', () => activate(card.dataset.gameCard)));
  }
  function clearGameCards(){
    activeEngine = null;
    activeEngines(null);
    engineTitle.textContent = 'Pick an engine above';
    engineCopy.textContent = 'Once you choose an engine, its games will load here.';
    gameGrid.innerHTML = '';
    gameGridEmpty.style.display = '';
  }
  function setBadges(game){
    activeBadges.innerHTML = `
      <span class="ugfx-chip">${escapeHtml(game.type)}</span>
      <span class="ugfx-chip">${escapeHtml(game.difficulty)}</span>
      <span class="ugfx-chip ugfx-chip-blue">Top ${Number(stats[game.id]?.top_score || 0)} ${escapeHtml(game.unit)}</span>`;
  }
  async function loadBoards(){
    const res = await fetch(endpoint, {cache:'no-store'});
    const data = await res.json();
    Object.assign(leaderboards, data.leaderboards || {});
    renderBoard(activeGame?.id);
  }
  function renderBoard(gameId){
    const game = lookup[gameId];
    if (!game) return;
    boardTitle.textContent = game.name + ' leaderboard';
    boardUnit.textContent = game.unit;
    boardDesc.textContent = game.description;
    const rows = leaderboards[gameId] || [];
    if (!rows.length) {
      boardBox.innerHTML = '<div class="text-secondary">No scores saved yet. Jump in and claim the board.</div>';
      return;
    }
    boardBox.innerHTML = rows.slice(0,10).map((row, index) => `<div class="d-flex justify-content-between align-items-center border rounded-4 p-3 mb-2"><div><div class="fw-semibold">#${index+1} ${escapeHtml(row.name || 'Guest')}</div><div class="text-secondary small">${escapeHtml(row.submitted_at || '')}</div></div><span class="ugfx-chip ugfx-chip-blue">${Number(row.score || 0)}</span></div>`).join('');
  }
  async function submitScore(game, score, extra = {}){
    const name = askName();
    if (name === null) return;
    const res = await fetch(endpoint, {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({action:'submit', game: game.id, name, score, extra})});
    const data = await res.json();
    if (!data.ok) { alert(data.message || 'Could not save score.'); return; }
    leaderboards[game.id] = data.leaderboard || [];
    stats[game.id] = Object.assign({}, stats[game.id] || {}, {top_score: Math.max(Number(stats[game.id]?.top_score || 0), Number(score || 0)), plays: Number(stats[game.id]?.plays || 0) + 1});
    renderBoard(game.id);
    setBadges(game);
    const card = document.querySelector(`[data-game-card="${game.id}"] .ugfx-chip-blue`);
    if (card) card.textContent = `Top ${Number(stats[game.id]?.top_score || 0)}`;
    alert('Score saved.');
  }

  function mountReaction(game){
    const duration = game.difficulty === 'easy' ? 20 : game.difficulty === 'medium' ? 18 : 16;
    const pace = game.difficulty === 'easy' ? 1 : game.difficulty === 'medium' ? 2 : 3;
    mount.innerHTML = `<div class="ugfx-arcade-stage"><div class="d-flex justify-content-between flex-wrap gap-2 mb-3"><span class="ugfx-chip">Time: <strong id="rgTime">${duration}</strong>s</span><span class="ugfx-chip ugfx-chip-blue">Score: <strong id="rgScore">0</strong></span></div><div class="ugfx-stage-shell" id="reactionShell"><button class="ugfx-target d-none" id="reactionTarget" type="button"></button><div class="ugfx-stage-overlay" id="reactionOverlay">Press start to begin</div></div><div class="d-flex gap-2 flex-wrap mt-3"><button class="btn ugfx-btn-primary" id="reactionStart" type="button">Start round</button><button class="btn ugfx-btn-outline" id="reactionSave" type="button" disabled>Save score</button></div></div>`;
    const shell = document.getElementById('reactionShell'); const target = document.getElementById('reactionTarget'); const overlay = document.getElementById('reactionOverlay'); const timeEl = document.getElementById('rgTime'); const scoreEl = document.getElementById('rgScore'); const saveBtn = document.getElementById('reactionSave');
    let score = 0, time = duration, timer = null, running = false;
    function move(){ const rect = shell.getBoundingClientRect(); target.style.left = `${randomRange(44, Math.max(44, rect.width - 44))}px`; target.style.top = `${randomRange(44, Math.max(44, rect.height - 44))}px`; }
    document.getElementById('reactionStart').onclick = () => { clearInterval(timer); score = 0; time = duration; running = true; scoreEl.textContent='0'; timeEl.textContent=String(duration); target.classList.remove('d-none'); overlay.textContent=''; saveBtn.disabled = true; move(); timer = setInterval(() => { time--; timeEl.textContent=String(time); if (time <= 0) { clearInterval(timer); running = false; target.classList.add('d-none'); overlay.textContent = `Round over — ${score} points`; saveBtn.disabled = score <= 0; } }, 1000); };
    target.onclick = () => { if (!running) return; score += pace; scoreEl.textContent = String(score); move(); };
    saveBtn.onclick = () => submitScore(game, score, {duration});
    return () => clearInterval(timer);
  }

  function mountMemory(game){
    const difficultyMap = {easy:60, medium:55, hard:50};
    const icons = memorySets[game.difficulty] || memorySets.easy;
    mount.innerHTML = `<div class="ugfx-arcade-stage"><div class="d-flex justify-content-between flex-wrap gap-2 mb-3"><span class="ugfx-chip">Time: <strong id="mmTime">${difficultyMap[game.difficulty]}</strong>s</span><span class="ugfx-chip ugfx-chip-blue">Moves: <strong id="mmMoves">0</strong></span></div><div class="ugfx-memory-grid" id="memoryGrid"></div><div class="d-flex gap-2 flex-wrap mt-3"><button class="btn ugfx-btn-primary" id="memoryStart" type="button">New board</button><button class="btn ugfx-btn-outline" id="memorySave" type="button" disabled>Save score</button></div></div>`;
    const grid = document.getElementById('memoryGrid'); const timeEl = document.getElementById('mmTime'); const movesEl = document.getElementById('mmMoves'); const saveBtn = document.getElementById('memorySave');
    let cards = [], open = [], matched = 0, moves = 0, timer = null, time = difficultyMap[game.difficulty], score = 0;
    function build(){ clearInterval(timer); open=[]; matched=0; moves=0; time=difficultyMap[game.difficulty]; score=0; timeEl.textContent=String(time); movesEl.textContent='0'; saveBtn.disabled=true; cards = shuffle([...icons, ...icons]).map((icon, index) => ({icon, index, open:false, matched:false})); render(); timer = setInterval(() => { time--; timeEl.textContent=String(time); if (time <= 0) { clearInterval(timer); score = Math.max(0, matched * 20 - moves); saveBtn.disabled = matched !== cards.length / 2; } }, 1000); }
    function render(){ grid.innerHTML = cards.map(card => `<button class="ugfx-memory-card ${card.open?'is-open':''} ${card.matched?'is-matched':''}" data-index="${card.index}" type="button">${card.open || card.matched ? escapeHtml(card.icon) : '?'}</button>`).join(''); grid.querySelectorAll('[data-index]').forEach(btn => btn.addEventListener('click', onFlip)); }
    function onFlip(e){ const idx = Number(e.currentTarget.dataset.index); const card = cards.find(c => c.index === idx); if (!card || card.open || card.matched || open.length >= 2 || time <= 0) return; card.open = true; open.push(card); render(); if (open.length === 2) { moves++; movesEl.textContent = String(moves); const [a,b] = open; if (a.icon === b.icon) { a.matched = b.matched = true; matched++; open=[]; render(); if (matched === cards.length/2) { clearInterval(timer); score = Math.max(50, time * 10 - moves * 2 + matched * 15); saveBtn.disabled = false; } } else { setTimeout(() => { a.open = false; b.open = false; open=[]; render(); }, 700); } } }
    document.getElementById('memoryStart').onclick = build; saveBtn.onclick = () => submitScore(game, score, {moves, time_left: time}); build();
    return () => clearInterval(timer);
  }

  function mountPattern(game){
    const speed = game.difficulty === 'easy' ? 650 : game.difficulty === 'medium' ? 520 : 420;
    mount.innerHTML = `<div class="ugfx-arcade-stage"><div class="d-flex justify-content-between flex-wrap gap-2 mb-3"><span class="ugfx-chip">Round: <strong id="pmRound">0</strong></span><span class="ugfx-chip ugfx-chip-blue">Best run: <strong id="pmBest">0</strong></span></div><div class="ugfx-beat-grid" id="patternGrid">${[0,1,2,3].map(i=>`<button class="ugfx-beat-pad" data-pad="${i}" type="button"></button>`).join('')}</div><div class="d-flex gap-2 flex-wrap mt-3"><button class="btn ugfx-btn-primary" id="patternStart" type="button">Start set</button><button class="btn ugfx-btn-outline" id="patternSave" type="button" disabled>Save score</button></div></div>`;
    const pads = Array.from(document.querySelectorAll('.ugfx-beat-pad')); const roundEl = document.getElementById('pmRound'); const bestEl = document.getElementById('pmBest'); const saveBtn = document.getElementById('patternSave');
    let seq = [], input = [], round = 0, best = 0, playingBack = false, playbackTimer = null;
    function light(index){ pads[index]?.classList.add('active'); setTimeout(() => pads[index]?.classList.remove('active'), Math.min(260, speed-120)); }
    function nextRound(){ input=[]; round++; best=Math.max(best, round-1); roundEl.textContent=String(round); bestEl.textContent=String(best); seq.push(randomRange(0,3)); playingBack=true; let i=0; clearInterval(playbackTimer); playbackTimer=setInterval(() => { light(seq[i]); i++; if (i >= seq.length) { clearInterval(playbackTimer); setTimeout(() => { playingBack=false; }, speed); } }, speed); }
    function fail(){ playingBack=true; saveBtn.disabled = best <= 0; }
    pads.forEach(pad => pad.onclick = () => { if (playingBack) return; const idx = Number(pad.dataset.pad); input.push(idx); light(idx); const pos = input.length - 1; if (seq[pos] !== idx) { fail(); return; } if (input.length === seq.length) { setTimeout(nextRound, 500); } });
    document.getElementById('patternStart').onclick = () => { seq=[]; input=[]; round=0; best=0; roundEl.textContent='0'; bestEl.textContent='0'; saveBtn.disabled=true; nextRound(); };
    saveBtn.onclick = () => submitScore(game, best, {round: best});
    return () => clearInterval(playbackTimer);
  }

  function mountRunner(game){
    const spawnRate = game.difficulty === 'easy' ? 900 : game.difficulty === 'medium' ? 700 : 550;
    const fallStep = game.difficulty === 'easy' ? 7 : game.difficulty === 'medium' ? 8.5 : 10;
    mount.innerHTML = `<div class="ugfx-arcade-stage"><div class="d-flex justify-content-between flex-wrap gap-2 mb-3"><span class="ugfx-chip">Survival: <strong id="rnTime">0</strong>s</span><span class="ugfx-chip ugfx-chip-blue">Lane: <strong id="rnLane">2</strong></span></div><div class="ugfx-stage-shell"><div class="ugfx-runner-track" id="runnerTrack">${[0,1,2].map(i=>`<div class="ugfx-runner-lane" data-lane="${i}"></div>`).join('')}</div></div><div class="ugfx-runner-controls mt-3"><button class="btn ugfx-btn-outline" id="runnerLeft" type="button">Move left</button><button class="btn ugfx-btn-primary" id="runnerStart" type="button">Start run</button><button class="btn ugfx-btn-outline" id="runnerRight" type="button">Move right</button><button class="btn ugfx-btn-outline" id="runnerSave" type="button" disabled>Save score</button></div></div>`;
    const track = document.getElementById('runnerTrack'); const lanes = Array.from(track.querySelectorAll('.ugfx-runner-lane')); const timeEl = document.getElementById('rnTime'); const laneEl = document.getElementById('rnLane'); const saveBtn = document.getElementById('runnerSave');
    let lane = 1, blocks = [], running = false, score = 0, interval = null, spawnTimer = null, player = document.createElement('div'); player.className='ugfx-runner-player';
    function renderPlayer(){ laneEl.textContent=String(lane+1); lanes.forEach((laneEl, idx) => { if (idx === lane && !laneEl.contains(player)) laneEl.appendChild(player); }); }
    function spawnBlock(){ const laneIdx = randomRange(0,2); const block = document.createElement('div'); block.className='ugfx-runner-block'; block.dataset.y='-60'; lanes[laneIdx].appendChild(block); blocks.push({lane: laneIdx, el: block, y: -60}); }
    function endRun(){ running=false; clearInterval(interval); clearInterval(spawnTimer); saveBtn.disabled = score <= 0; }
    function tick(){ if (!running) return; score += 0.1; timeEl.textContent = String(Math.floor(score)); blocks.forEach(block => { block.y += fallStep; block.el.style.top = `${block.y}px`; if (block.y > 250 && block.lane === lane) endRun(); }); blocks = blocks.filter(block => { if (block.y > 360) { block.el.remove(); return false; } return true; }); }
    document.getElementById('runnerStart').onclick = () => { blocks.forEach(b => b.el.remove()); blocks=[]; score=0; lane=1; renderPlayer(); saveBtn.disabled=true; timeEl.textContent='0'; running=true; clearInterval(interval); clearInterval(spawnTimer); interval=setInterval(tick, 50); spawnTimer=setInterval(spawnBlock, spawnRate); };
    document.getElementById('runnerLeft').onclick = () => { if (!running) return; lane = Math.max(0, lane-1); renderPlayer(); };
    document.getElementById('runnerRight').onclick = () => { if (!running) return; lane = Math.min(2, lane+1); renderPlayer(); };
    saveBtn.onclick = () => submitScore(game, Math.floor(score), {duration: Math.floor(score)});
    window.addEventListener('keydown', keyHandler = (e) => { if (e.key === 'ArrowLeft') document.getElementById('runnerLeft').click(); if (e.key === 'ArrowRight') document.getElementById('runnerRight').click(); });
    renderPlayer();
    return () => { clearInterval(interval); clearInterval(spawnTimer); window.removeEventListener('keydown', keyHandler); };
  }

  function mountQuiz(game){
    const pool = shuffle([...(questionsByDifficulty[game.difficulty] || questionsByDifficulty.easy)]).slice(0, 4);
    const duration = game.difficulty === 'easy' ? 45 : game.difficulty === 'medium' ? 35 : 28;
    mount.innerHTML = `<div class="ugfx-arcade-stage"><div class="d-flex justify-content-between flex-wrap gap-2 mb-3"><span class="ugfx-chip">Time: <strong id="qzTime">${duration}</strong>s</span><span class="ugfx-chip ugfx-chip-blue">Score: <strong id="qzScore">0</strong></span></div><div class="ugfx-stage-shell p-4 d-flex flex-column justify-content-between"><div><div class="ugfx-micro-label">QUESTION</div><h3 class="mb-3" id="quizQuestion"></h3><div class="ugfx-quiz-answers" id="quizAnswers"></div></div><div class="d-flex gap-2 flex-wrap mt-4"><button class="btn ugfx-btn-primary" type="button" id="quizStart">Start quiz</button><button class="btn ugfx-btn-outline" type="button" id="quizSave" disabled>Save score</button></div></div></div>`;
    const timeEl = document.getElementById('qzTime'); const scoreEl = document.getElementById('qzScore'); const qEl = document.getElementById('quizQuestion'); const answersEl = document.getElementById('quizAnswers'); const saveBtn = document.getElementById('quizSave');
    let index = 0, score = 0, timer = null, time = duration, running = false;
    function end(){ running=false; clearInterval(timer); saveBtn.disabled = score <= 0; }
    function render(){ const current = pool[index]; if (!current) { qEl.textContent='Round complete'; answersEl.innerHTML=''; end(); return; } qEl.textContent = current.q; answersEl.innerHTML = current.a.map((ans, idx) => `<button class="ugfx-quiz-answer" data-answer="${idx}" type="button">${escapeHtml(ans)}</button>`).join(''); answersEl.querySelectorAll('[data-answer]').forEach(btn => btn.onclick = () => { if (!running) return; if (Number(btn.dataset.answer) === current.correct) score += Math.max(10, time); scoreEl.textContent = String(score); index++; render(); }); }
    document.getElementById('quizStart').onclick = () => { index=0; score=0; time=duration; running=true; scoreEl.textContent='0'; timeEl.textContent=String(time); saveBtn.disabled=true; render(); clearInterval(timer); timer=setInterval(() => { time--; timeEl.textContent=String(time); if (time <= 0) end(); }, 1000); };
    saveBtn.onclick = () => submitScore(game, score, {correct: index});
    return () => clearInterval(timer);
  }

  function mountBurst(game){
    const liveCount = game.difficulty === 'easy' ? 2 : game.difficulty === 'medium' ? 3 : 4;
    const duration = game.difficulty === 'easy' ? 25 : game.difficulty === 'medium' ? 22 : 18;
    mount.innerHTML = `<div class="ugfx-arcade-stage"><div class="d-flex justify-content-between flex-wrap gap-2 mb-3"><span class="ugfx-chip">Time: <strong id="btTime">${duration}</strong>s</span><span class="ugfx-chip ugfx-chip-blue">Score: <strong id="btScore">0</strong></span></div><div class="ugfx-burst-grid" id="burstGrid">${Array.from({length:9}, (_,i) => `<button class="ugfx-burst-pad" data-pad="${i}" type="button"></button>`).join('')}</div><div class="d-flex gap-2 flex-wrap mt-3"><button class="btn ugfx-btn-primary" type="button" id="burstStart">Start wave</button><button class="btn ugfx-btn-outline" type="button" id="burstSave" disabled>Save score</button></div></div>`;
    const pads = Array.from(document.querySelectorAll('.ugfx-burst-pad')); const timeEl = document.getElementById('btTime'); const scoreEl = document.getElementById('btScore'); const saveBtn = document.getElementById('burstSave');
    let timer = null, waveTimer = null, running = false, time = duration, score = 0, combo = 0, live = new Set();
    function setLive(){ live.clear(); shuffle(pads).slice(0, liveCount).forEach((pad, idx) => { live.add(Number(pad.dataset.pad)); pad.classList.add('live'); }); pads.forEach(p => { if (!live.has(Number(p.dataset.pad))) p.classList.remove('live'); }); }
    document.getElementById('burstStart').onclick = () => { clearInterval(timer); clearInterval(waveTimer); running=true; time=duration; score=0; combo=0; scoreEl.textContent='0'; timeEl.textContent=String(time); saveBtn.disabled=true; setLive(); timer=setInterval(() => { time--; timeEl.textContent=String(time); if (time <= 0) { clearInterval(timer); clearInterval(waveTimer); running=false; pads.forEach(p => p.classList.remove('live')); saveBtn.disabled = score <= 0; } }, 1000); waveTimer=setInterval(setLive, game.difficulty === 'hard' ? 650 : 850); };
    pads.forEach(pad => pad.onclick = () => { if (!running) return; const id = Number(pad.dataset.pad); if (!live.has(id)) { combo = 0; return; } combo += 1; score += 5 * combo; scoreEl.textContent = String(score); pad.classList.remove('live'); live.delete(id); if (!live.size) setLive(); });
    saveBtn.onclick = () => submitScore(game, score, {combo});
    return () => { clearInterval(timer); clearInterval(waveTimer); };
  }

  function activate(gameId){
    const game = lookup[gameId]; if (!game) return;
    activeGame = game; activeCards(gameId); activeType.textContent = `${game.type.toUpperCase()} ENGINE`; activeTitle.textContent = game.name; activeDesc.textContent = game.description; setBadges(game); renderBoard(game.id); if (cleanup) cleanup();
    cleanup = ({reaction:mountReaction,memory:mountMemory,pattern:mountPattern,runner:mountRunner,quiz:mountQuiz,burst:mountBurst}[game.type] || mountReaction)(game);
  }

  engineButtons.forEach(btn => btn.addEventListener('click', () => renderGameCards(btn.dataset.engineCard)));
  document.querySelector('[data-clear-engine]')?.addEventListener('click', clearGameCards);
  document.querySelectorAll('[data-quick-open]').forEach(btn => btn.addEventListener('click', () => { const game = lookup[btn.dataset.quickOpen]; if (game) { renderGameCards(game.type); activate(game.id); } }));
  loadBoards().then(() => { clearGameCards(); if (activeGame) activate(activeGame.id); });
})();
</script>
<?php include __DIR__ . '/includes/footer.php'; ?>
