<?php
ob_start();
require_once __DIR__ . '/../../includes/auth.php';
// Redirect to admin login if not logged in or not admin
if (!isLoggedIn() || empty($_SESSION['is_admin'])) {
    ob_end_clean();
    header('Location: /admin/login.php'); exit;
}
ob_end_clean();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
  <link rel="icon" type="image/svg+xml" href="/favicon.svg">
  <link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet">
<meta name="googlebot" content="noindex, nofollow">
<title>TomTomGames Admin</title>
<link href="https://fonts.googleapis.com/css2?family=Exo+2:wght@400;600;700;900&family=Rajdhani:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
  /* ── Typography Scale ── */
  --fs-xs:12px;--fs-sm:14px;--fs-base:16px;--fs-md:17px;
  --fs-lg:19px;--fs-xl:21px;--fs-2xl:25px;--lh:1.6;--bg:#0a0a12;--bg2:#10101e;--bg3:#181828;--card:#1a1a2e;--border:rgba(255,255,255,0.08);--gold:#f0c040;--gold2:#ffdc73;--cyan:#00e5ff;--purple:#9b5de5;--green:#00e676;--red:#ff4444;--yellow:#ffd60a;--text:#e8e8f0;--text2:#8888aa;--r:12px;--rs:8px}
body{background:var(--bg);color:var(--text);font-family:'Rajdhani',sans-serif;font-size:17px;line-height:1.6;min-height:100vh;display:flex}
aside{width:210px;min-height:100vh;background:var(--bg2);border-right:1px solid var(--border);padding:0;display:flex;flex-direction:column;position:fixed;left:0;top:0;bottom:0}
.sidebar-head{padding:20px 18px 16px;border-bottom:1px solid var(--border)}
.sidebar-logo{font-family:'Exo 2',sans-serif;font-weight:900;font-size:15px;display:flex;align-items:center;gap:8px}.sidebar-logo span{background:linear-gradient(135deg,var(--gold),var(--cyan));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.sidebar-sub{font-size:12px;color:var(--text2);letter-spacing:1px;margin-top:2px;font-weight:700}
.nav-section{padding:12px 12px 4px;font-size:12px;font-weight:700;color:var(--text2);letter-spacing:1.5px;text-transform:uppercase}
.nav-item{display:flex;align-items:center;gap:9px;padding:10px 16px;color:var(--text2);cursor:pointer;transition:all .15s;font-weight:600;font-size:15px;border:none;background:none;width:100%;text-align:left;border-left:3px solid transparent}
.nav-item:hover{color:var(--text);background:rgba(255,255,255,.03)}
.nav-item.active{color:var(--gold);border-left-color:var(--gold);background:rgba(240,192,64,.05)}
.nav-item .badge-count{margin-left:auto;background:var(--red);color:#fff;font-size:12px;font-weight:700;padding:1px 6px;border-radius:10px;min-width:18px;text-align:center}
.sidebar-footer{margin-top:auto;padding:12px}
.logout-btn{width:100%;padding:10px;border:1px solid rgba(255,68,68,.3);border-radius:var(--rs);background:rgba(255,68,68,.06);color:var(--red);cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;letter-spacing:.5px}

main{margin-left:210px;flex:1;padding:28px 32px;min-height:100vh}
.page-title{font-family:'Exo 2',sans-serif;font-weight:900;font-size:26px;margin-bottom:20px;background:linear-gradient(135deg,var(--gold),var(--cyan));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.section{display:none}
.section.active{display:block}

/* STATS */
.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:14px;margin-bottom:28px}
.stat-card{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:18px 16px}
.stat-label{font-size:12px;font-weight:700;color:var(--text2);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:6px}
.stat-value{font-family:'Exo 2',sans-serif;font-weight:900;font-size:30px;color:var(--gold);line-height:1}
.stat-sub{font-size:13px;color:var(--text2);margin-top:4px}

/* CARD */
.card{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:18px;margin-bottom:18px}
.card-title{font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;margin-bottom:14px;color:var(--text);display:flex;align-items:center;gap:8px}

/* TABLE */
.tbl-wrap{overflow-x:auto}
table{width:100%;border-collapse:collapse}
th{text-align:left;font-size:12px;font-weight:700;color:var(--text2);letter-spacing:1px;text-transform:uppercase;padding:0 10px 10px;border-bottom:1px solid var(--border);white-space:nowrap}
td{padding:10px;border-bottom:1px solid rgba(255,255,255,.03);font-size:15px;vertical-align:middle}
tr:last-child td{border-bottom:none}
tr:hover td{background:rgba(255,255,255,.015)}

/* BADGES */
.badge{display:inline-block;font-size:12px;font-weight:700;padding:2px 8px;border-radius:20px;letter-spacing:.3px;white-space:nowrap}
.b-pending  {background:rgba(255,214,10,.15);color:var(--yellow)}
.b-approved,.b-completed{background:rgba(0,230,118,.15);color:var(--green)}
.b-rejected,.b-failed   {background:rgba(255,68,68,.15);color:var(--red)}
.b-active   {background:rgba(0,230,118,.15);color:var(--green)}
.b-suspended{background:rgba(255,68,68,.15);color:var(--red)}
.b-card     {background:rgba(0,229,255,.12);color:var(--cyan)}
.b-venmo    {background:rgba(59,89,200,.2);color:#7b9fff}
.b-chime    {background:rgba(0,200,100,.12);color:#00e676}
.b-cashapp  {background:rgba(0,180,50,.12);color:#4caf50}
.b-zelle    {background:rgba(160,32,240,.15);color:#c77dff}

/* BUTTONS */
.btn{padding:7px 13px;border:none;border-radius:var(--rs);font-family:'Exo 2',sans-serif;font-weight:700;font-size:13px;letter-spacing:.5px;cursor:pointer;transition:all .15s;text-transform:uppercase;white-space:nowrap}
.btn:active{transform:scale(.97)}
.btn-green{background:rgba(0,230,118,.12);color:var(--green);border:1px solid rgba(0,230,118,.3)}
.btn-green:hover{background:rgba(0,230,118,.22)}
.btn-red{background:rgba(255,68,68,.12);color:var(--red);border:1px solid rgba(255,68,68,.3)}
.btn-red:hover{background:rgba(255,68,68,.22)}
.btn-gold{background:rgba(240,192,64,.12);color:var(--gold);border:1px solid rgba(240,192,64,.3)}
.btn-gold:hover{background:rgba(240,192,64,.22)}
.btn-cyan{background:rgba(0,229,255,.1);color:var(--cyan);border:1px solid rgba(0,229,255,.3)}

/* FILTER TABS */
.filter-bar{display:flex;gap:8px;margin-bottom:14px;flex-wrap:wrap}
.ftab{padding:6px 14px;border:1px solid var(--border);border-radius:20px;background:none;color:var(--text2);cursor:pointer;font-size:14px;font-weight:600;transition:all .15s}
.ftab.active{border-color:var(--gold);color:var(--gold);background:rgba(240,192,64,.06)}

/* FORM inline */
.fi-sm{background:var(--bg3);border:1px solid var(--border);border-radius:var(--rs);padding:7px 10px;color:var(--text);font-family:'Rajdhani',sans-serif;font-size:17px;line-height:1.6;outline:none}
.fi-sm:focus{border-color:var(--cyan)}

/* SEARCH */
.search-row{margin-bottom:14px;display:flex;gap:10px;align-items:center}
.search-row input{background:var(--bg3);border:1px solid var(--border);border-radius:var(--rs);padding:9px 13px;color:var(--text);font-family:'Rajdhani',sans-serif;font-size:17px;line-height:1.6;outline:none;width:260px}
.search-row input:focus{border-color:var(--cyan)}

/* PURCHASE CARD (milkyswipe style) */
.purchase-row{background:var(--bg3);border:1px solid var(--border);border-radius:var(--r);padding:14px;margin-bottom:10px}
.purchase-row.urgent{border-color:rgba(255,214,10,.3);background:rgba(255,214,10,.03)}
.pr-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:10px}
.pr-info{}
.pr-user{font-weight:700;font-size:15px;color:var(--text)}
.pr-ref{font-size:13px;color:var(--text2);margin-top:1px}
.pr-amount{text-align:right}
.pr-tokens{font-family:'Exo 2',sans-serif;font-weight:900;font-size:22px;color:var(--gold);line-height:1}
.pr-dollars{font-size:14px;color:var(--green);font-weight:700}
.pr-meta{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:10px;align-items:center}
.pr-actions{display:flex;gap:8px;align-items:center}
.pr-note{flex:1}
.pr-note input{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:var(--rs);padding:7px 10px;color:var(--text);font-family:'Rajdhani',sans-serif;font-size:17px;line-height:1.6;outline:none}
.pr-note input:focus{border-color:var(--cyan)}

/* TOAST */
#toast{position:fixed;top:18px;right:18px;padding:11px 18px;border-radius:var(--rs);font-weight:700;font-size:15px;z-index:999;display:none;box-shadow:0 4px 20px rgba(0,0,0,.4)}
#toast.show{display:block}
#toast.ok{background:#00e676;color:#000}
#toast.err{background:#ff4444;color:#fff}
#toast.info{background:var(--card);color:var(--cyan);border:1px solid rgba(0,229,255,.3)}

.empty{text-align:center;padding:36px;color:var(--text2);font-size:15px}

/* ─── ADMIN SAVED CARD ──────────────────────────────── */
.admin-saved-card{background:linear-gradient(135deg,#1c1c3a,#2d1b69);border-radius:14px;padding:18px;position:relative;overflow:hidden;border:1px solid rgba(255,255,255,.1)}
.admin-saved-card::before{content:'';position:absolute;top:-30px;right:-30px;width:110px;height:110px;border-radius:50%;background:rgba(255,255,255,.04)}

/* ─── GAME MANAGEMENT ────────────────────────────────── */
.game-row{display:flex;align-items:center;gap:14px;padding:14px 18px;border-bottom:1px solid var(--border);transition:background .15s}
.game-row:last-child{border-bottom:none}
.game-row:hover{background:rgba(255,255,255,.02)}
.game-color-dot{width:14px;height:14px;border-radius:50%;flex-shrink:0;box-shadow:0 0 8px currentColor}
.game-info{flex:1;min-width:0}
.game-name{font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text)}
.game-slug{font-size:13px;color:var(--text2);font-family:monospace;margin-top:1px}
.game-urls{font-size:13px;color:var(--text2);margin-top:3px;display:flex;flex-direction:column;gap:1px}
.game-url-row{display:flex;align-items:center;gap:5px;overflow:hidden}
.game-url-label{font-weight:700;color:var(--cyan);flex-shrink:0;font-size:12px;letter-spacing:.5px}
.game-url-val{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text2)}
.game-url-link{color:var(--cyan);text-decoration:none;font-size:12px;flex-shrink:0}
.game-url-link:hover{text-decoration:underline}
.game-actions{display:flex;gap:6px;flex-shrink:0}
.game-edit-btn{padding:6px 12px;border-radius:6px;border:none;cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;font-size:13px;transition:all .15s}
.inactive-overlay{opacity:.5}

/* ─── ADMIN CHAT ─────────────────────────────────── */
.chat-inbox-row{display:flex;align-items:center;gap:14px;padding:14px 18px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s}
.chat-inbox-row:last-child{border-bottom:none}
.chat-inbox-row:hover{background:rgba(255,255,255,.03)}
.chat-inbox-row.unread{background:rgba(240,192,64,.04)}
.ci-avatar{width:44px;height:44px;border-radius:50%;background:linear-gradient(135deg,var(--purple),var(--cyan));display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:900;font-size:18px;color:#fff;flex-shrink:0}
.ci-body{flex:1;min-width:0}
.ci-top{display:flex;justify-content:space-between;align-items:baseline;gap:8px}
.ci-name{font-weight:700;font-size:15px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ci-time{font-size:13px;color:var(--text2);white-space:nowrap;flex-shrink:0}
.ci-preview{font-size:14px;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
.ci-preview.unread-preview{color:var(--text);font-weight:600}
.ci-badge{background:var(--red);color:#fff;font-size:12px;font-weight:700;min-width:18px;height:18px;border-radius:9px;display:flex;align-items:center;justify-content:center;padding:0 4px;flex-shrink:0}
.admin-chat-wrap{background:var(--card);border:1px solid var(--border);border-radius:var(--r);overflow:hidden;display:flex;flex-direction:column;height:calc(100vh - 180px)}
.admin-chat-header{display:flex;align-items:center;gap:12px;padding:14px 18px;background:var(--bg2);border-bottom:1px solid var(--border);flex-shrink:0}
.admin-chat-avatar{width:40px;height:40px;border-radius:50%;background:linear-gradient(135deg,var(--purple),var(--cyan));display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:900;font-size:17px;color:#fff;flex-shrink:0}
.admin-chat-name{font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text)}
.admin-chat-meta{font-size:14px;color:var(--text2);margin-top:2px}
.admin-chat-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:8px}
.admin-bubble-wrap{display:flex;flex-direction:column;max-width:75%}
.admin-bubble-wrap.from-user{align-self:flex-start;align-items:flex-start}
.admin-bubble-wrap.from-admin{align-self:flex-end;align-items:flex-end}
.admin-bubble{padding:9px 14px;border-radius:18px;font-size:15px;line-height:1.45;word-break:break-word}
.admin-bubble.from-user{background:var(--bg3);color:var(--text);border:1px solid var(--border);border-bottom-left-radius:4px}
.admin-bubble.from-admin{background:linear-gradient(135deg,var(--gold),#d4a017);color:#000;font-weight:500;border-bottom-right-radius:4px}
.admin-bubble-time{font-size:12px;color:var(--text2);margin-top:3px;padding:0 4px}
.admin-chat-input-bar{display:flex;gap:8px;padding:12px 14px;border-top:1px solid var(--border);background:var(--bg2);flex-shrink:0}
.admin-chat-input{flex:1;background:var(--bg3);border:1.5px solid var(--border);border-radius:24px;padding:9px 16px;color:var(--text);font-family:'Rajdhani',sans-serif;font-size:17px;line-height:1.6;outline:none;transition:border-color .15s}
.admin-chat-input:focus{border-color:var(--cyan)}
.admin-send-btn{width:38px;height:38px;border-radius:50%;background:linear-gradient(135deg,var(--gold),#d4a017);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#000}
.admin-send-btn svg{stroke:#000}
.admin-date-div{text-align:center;font-size:13px;color:var(--text2);font-weight:700;margin:8px 0;display:flex;align-items:center;gap:8px}
.admin-date-div::before,.admin-date-div::after{content:'';flex:1;height:1px;background:var(--border)}

/* ─── GAMER MANAGEMENT ───────────────────────────────── */
.gm-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:20px;flex-wrap:wrap}
.gm-search-wrap{position:relative;flex:1;min-width:200px}
.gm-search-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--text2)}
.gm-search{width:100%;background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:10px 14px 10px 36px;color:var(--text);font-family:'Rajdhani',sans-serif;font-size:17px;line-height:1.6;outline:none}
.gm-search:focus{border-color:var(--cyan)}
.gm-filters{display:flex;gap:6px;flex-shrink:0}
.gm-filter{padding:7px 14px;border:1px solid var(--border);border-radius:20px;background:none;color:var(--text2);cursor:pointer;font-size:14px;font-weight:600;transition:all .15s;white-space:nowrap}
.gm-filter.active{border-color:var(--gold);color:var(--gold);background:rgba(240,192,64,.07)}
.gm-stats-mini{font-size:14px;color:var(--text2);white-space:nowrap}

.gm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px}
.gm-card{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:18px;cursor:pointer;transition:all .18s;position:relative;overflow:hidden}
.gm-card:hover{border-color:rgba(240,192,64,.3);transform:translateY(-2px);box-shadow:0 6px 24px rgba(0,0,0,.3)}
.gm-card.suspended{border-color:rgba(255,68,68,.2);background:rgba(255,30,30,.03)}
.gm-card.unverified{border-color:rgba(255,214,10,.15);background:rgba(255,214,10,.02)}
.gm-card-top{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.gm-card-avatar{width:46px;height:46px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:900;font-size:20px;color:#fff;flex-shrink:0}
.gm-card-info{flex:1;min-width:0}
.gm-card-name{font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gm-card-alias{font-size:14px;color:var(--cyan);margin-top:2px}
.gm-card-badges{display:flex;gap:5px;flex-wrap:wrap;margin-top:2px}
.gm-card-stats{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:14px}
.gm-stat{background:var(--bg3);border-radius:8px;padding:8px 10px;text-align:center}
.gm-stat-val{font-family:'Exo 2',sans-serif;font-weight:700;font-size:17px;color:var(--gold)}
.gm-stat-lbl{font-size:12px;color:var(--text2);font-weight:600;letter-spacing:.5px;margin-top:1px}
.gm-card-email{font-size:13px;color:var(--text2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gm-card-joined{font-size:12px;color:var(--text2);margin-top:3px}
.gm-card-hover-cta{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(to top,rgba(240,192,64,.12),transparent);padding:8px 16px;font-size:13px;font-weight:700;color:var(--gold);letter-spacing:.5px;opacity:0;transition:opacity .2s;text-align:center}
.gm-card:hover .gm-card-hover-cta{opacity:1}

.gm-back-btn{display:flex;align-items:center;gap:7px;background:none;border:1px solid var(--border);border-radius:8px;color:var(--text2);cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;padding:8px 14px;margin-bottom:18px;transition:all .15s}
.gm-back-btn:hover{color:var(--cyan);border-color:var(--cyan)}

.gm-profile-card{background:linear-gradient(135deg,#1a1228,#0d1a2e);border:1px solid rgba(240,192,64,.2);border-radius:var(--r);padding:22px;margin-bottom:18px;display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.gm-profile-avatar{width:72px;height:72px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:900;font-size:30px;color:#fff;flex-shrink:0;border:3px solid var(--gold);box-shadow:0 0 20px rgba(240,192,64,.3)}
.gm-profile-info{flex:1;min-width:0}
.gm-profile-name{font-family:'Exo 2',sans-serif;font-weight:900;font-size:22px;color:var(--text)}
.gm-profile-alias{font-size:15px;color:var(--cyan);margin-top:2px}
.gm-profile-email{font-size:15px;color:var(--text2);margin-top:4px}
.gm-profile-right{text-align:right;flex-shrink:0}
.gm-profile-tokens{font-family:'Exo 2',sans-serif;font-weight:900;font-size:32px;color:var(--gold);line-height:1}
.gm-profile-tok-lbl{font-size:13px;color:var(--text2);margin-top:2px;letter-spacing:1px;text-transform:uppercase}
.gm-profile-badges{display:flex;gap:6px;margin-top:8px;justify-content:flex-end}

.gm-tabs{display:flex;gap:0;background:var(--bg3);border-radius:var(--r);padding:4px;margin-bottom:16px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.gm-tabs::-webkit-scrollbar{display:none}
.gm-tab{flex:1;padding:9px 12px;border:none;background:none;color:var(--text2);font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;letter-spacing:.3px;border-radius:8px;cursor:pointer;transition:all .15s;white-space:nowrap}
.gm-tab.active{background:linear-gradient(135deg,rgba(240,192,64,.15),rgba(0,229,255,.08));color:var(--gold)}

.gm-tab-panel{display:none}
.gm-tab-panel.active{display:block;animation:fadeUp .2s ease}

.gm-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:16px}
.gm-info-item{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:14px}
.gm-info-label{font-size:12px;font-weight:700;color:var(--text2);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:5px}
.gm-info-val{font-size:15px;font-weight:600;color:var(--text)}

.gm-actions-panel{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:16px}
.gm-actions-title{font-size:13px;font-weight:700;color:var(--text2);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:12px}
.gm-action-btns{display:flex;gap:8px;flex-wrap:wrap}

.gm-token-display{font-family:'Exo 2',sans-serif;font-weight:900;font-size:48px;color:var(--gold);text-align:center;padding:16px 0}
.gm-edit-label{display:block;font-size:13px;font-weight:700;color:var(--text2);letter-spacing:1px;text-transform:uppercase;margin-bottom:6px}
.gm-empty{text-align:center;padding:28px;color:var(--text2);font-size:15px}

/* ─── PAYMENT LEDGER ─────────────────────────────────── */
.pm-summary{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:16px}
.pm-sum-item{background:var(--bg3);border:1px solid var(--border);border-radius:var(--rs);padding:10px;text-align:center}
.pm-sum-val{font-family:'Exo 2',sans-serif;font-weight:900;font-size:18px;line-height:1}
.pm-sum-lbl{font-size:12px;color:var(--text2);font-weight:700;letter-spacing:.5px;text-transform:uppercase;margin-top:3px}

.pm-card{background:var(--bg3);border:1px solid var(--border);border-radius:var(--r);padding:14px;margin-bottom:10px;transition:border-color .15s}
.pm-card.pm-completed{border-left:3px solid var(--green)}
.pm-card.pm-pending{border-left:3px solid var(--yellow)}
.pm-card.pm-failed{border-left:3px solid var(--red);opacity:.85}
.pm-card-top{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px}
.pm-order-id{font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text)}
.pm-custom-badge{background:rgba(155,93,229,.2);color:#c77dff;font-size:12px;font-weight:700;padding:1px 7px;border-radius:10px;margin-left:6px;letter-spacing:.3px}
.pm-date{font-size:13px;color:var(--text2);margin-top:2px}
.pm-card-right{text-align:right}
.pm-amount{font-family:'Exo 2',sans-serif;font-weight:900;font-size:22px;color:var(--green);line-height:1}
.pm-tokens{font-size:14px;color:var(--gold);font-weight:700;margin-top:2px}
.pm-card-mid{}
.pm-detail-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:14px}
.pm-lbl{color:var(--text2);font-weight:700}
.pm-val{color:var(--text)}
.pm-card-info{font-size:13px;color:var(--text2);background:var(--bg);border-radius:6px;padding:2px 8px}
.pm-failure{background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);border-radius:6px;padding:7px 10px;margin-top:8px;font-size:14px;color:var(--red)}
.pm-admin-note{background:rgba(240,192,64,.05);border:1px solid rgba(240,192,64,.15);border-radius:6px;padding:7px 10px;margin-top:6px;font-size:14px;color:var(--gold2)}
.pm-receipt-link{font-size:14px;color:var(--cyan);text-decoration:none;font-weight:600}
.pm-receipt-link:hover{text-decoration:underline}
.pm-actions{display:flex;gap:8px;align-items:center;margin-top:12px;padding-top:12px;border-top:1px solid var(--border)}
.btn-sm{padding:6px 12px;font-size:13px}

/* ── Responsive Typography ─────────────────────────────── */
@media (min-width: 768px) {
  body { font-size: 17px; }
  .card { font-size: 16px !important; padding: 20px !important; }
  .page-title { font-size: 26px !important; }
  .nav-item { font-size: 15px !important; }
}
@media (min-width: 1200px) {
  body { font-size: 18px; }
  .card { font-size: 17px !important; }
  .page-title { font-size: 28px !important; }
}
</style>
</head>
<body>

<div id="toast"></div>

<aside>
  <div class="sidebar-head">
    <div class="sidebar-logo" style="display:flex;align-items:center;gap:8px"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="28" height="28" style="display:inline-block;vertical-align:middle;flex-shrink:0"><defs><linearGradient id="li1" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#f0c040"/><stop offset="100%" stop-color="#ff6b35"/></linearGradient><linearGradient id="li2" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#00e5ff"/><stop offset="100%" stop-color="#7b2fbe"/></linearGradient></defs><rect x="6" y="16" width="36" height="22" rx="11" fill="url(#li1)"/><rect x="12" y="23" width="8" height="3" rx="1.5" fill="rgba(0,0,0,0.45)"/><rect x="15" y="20" width="3" height="8" rx="1.5" fill="rgba(0,0,0,0.45)"/><circle cx="32" cy="22" r="2.2" fill="#e63946" opacity=".9"/><circle cx="36" cy="25" r="2.2" fill="#2ec4b6" opacity=".9"/><circle cx="32" cy="28" r="2.2" fill="#7b2fbe" opacity=".9"/><circle cx="28" cy="25" r="2.2" fill="#f4a261" opacity=".9"/><rect x="21" y="24" width="6" height="3" rx="1.5" fill="rgba(0,0,0,0.3)"/><rect x="8" y="30" width="8" height="7" rx="4" fill="url(#li2)" opacity=".7"/><rect x="32" y="30" width="8" height="7" rx="4" fill="url(#li2)" opacity=".7"/><rect x="14" y="13" width="8" height="5" rx="2.5" fill="url(#li1)" opacity=".8"/><rect x="26" y="13" width="8" height="5" rx="2.5" fill="url(#li1)" opacity=".8"/></svg><span>TomTomGames</span></div>
    <div class="sidebar-sub" style="-webkit-text-fill-color:var(--text2)">ADMIN PANEL</div>
  </div>
  <div class="nav-section">Main</div>
  <button class="nav-item active" onclick="showSec('dashboard')">📊 Dashboard</button>
  <button class="nav-item" onclick="showSec('users')">🎮 Players</button>
  <button class="nav-item" onclick="showSec('pending')">⏳ Pending Signups <span class="badge-count" id="badge-pending">0</span></button>
  <button class="nav-item" onclick="showSec('purchases')">🧾 Purchases <span class="badge-count" id="badge-purchases">0</span></button>
  <button class="nav-item" onclick="showSec('cashouts')">💸 Cashouts <span class="badge-count" id="badge-cashouts">0</span></button>
  <button class="nav-item" onclick="showSec('chat')">💬 Live Chat <span class="badge-count" id="badge-chat">0</span></button>
  <button class="nav-item" onclick="showSec('broadcasts')">📢 Broadcasts</button>
  <div class="nav-section">Manage</div>
  <button class="nav-item" onclick="showSec('games')">🕹️ Game Management</button>
  <button class="nav-item" onclick="showSec('referrals')">🎁 Referrals</button>
  <button class="nav-item" onclick="showSec('platform-accounts')">🔑 Platform Accounts</button>
  <button class="nav-item" onclick="showSec('payments')">💳 Payment Settings</button>
  <button class="nav-item" onclick="showSec('cashout-methods')">💸 Cashout Methods</button>
  <button class="nav-item" onclick="showSec('payout-settings')">💰 Payout Settings</button>
  <button class="nav-item" onclick="showSec('history')">📋 All History</button>
  <div class="nav-section">System</div>
  <button class="nav-item" onclick="showSec('backups')">💾 Backups</button>
  <div class="sidebar-footer">
    <button class="logout-btn" onclick="fetch('/api/logout.php').then(()=>location='/admin/login.php')">🚪 LOGOUT</button>
  </div>
</aside>

<main>

  <!-- DASHBOARD -->
  <div class="section active" id="section-dashboard">
    <div class="page-title">📊 Dashboard</div>
    <!-- Unread messages alert -->
    <div id="unread-chat-alert" style="display:none;background:linear-gradient(135deg,rgba(240,192,64,.12),rgba(0,229,255,.06));border:1px solid rgba(240,192,64,.3);border-radius:12px;padding:14px 18px;margin-bottom:16px;display:none;align-items:center;gap:14px;cursor:pointer" onclick="showSec('chat')">
      <div style="font-size:28px">💬</div>
      <div style="flex:1">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;color:var(--gold)">New Messages from Players</div>
        <div id="unread-chat-alert-text" style="font-size:14px;color:var(--text2);margin-top:2px">Click to view and respond</div>
      </div>
      <div style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:24px;color:var(--gold)" id="unread-chat-alert-count">0</div>
    </div>
    <div class="stats-grid">
      <div class="stat-card"><div class="stat-label">Total Users</div><div class="stat-value" id="s-users">—</div></div>
      <div class="stat-card"><div class="stat-label">Total Revenue</div><div class="stat-value" id="s-rev" style="color:var(--green)">—</div></div>
      <div class="stat-card"><div class="stat-label">Tokens Sold</div><div class="stat-value" id="s-toks">—</div></div>
      <div class="stat-card"><div class="stat-label">Pending Purchases</div><div class="stat-value" id="s-ppurch" style="color:var(--yellow)">—</div></div>
      <div class="stat-card"><div class="stat-label">Pending Cashouts</div><div class="stat-value" id="s-pcash" style="color:var(--yellow)">—</div></div>
    </div>
    <div class="card">
      <div class="card-title">⚡ Pending Purchase Approvals</div>
      <div id="dash-purchases"></div>
    </div>
    <div class="card">
      <div class="card-title">⚡ Pending Cashout Requests</div>
      <div id="dash-cashouts"></div>
    </div>

    <!-- PLATFORM CREDIT OVERVIEW -->
    <div style="margin-top:8px">
      <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:16px;color:var(--text);margin-bottom:14px;display:flex;align-items:center;gap:8px">
        🕹️ Platform Credit Overview
        <button onclick="loadPlatformStats()" style="background:none;border:none;color:var(--text2);font-size:13px;cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;padding:0;margin-left:4px">↻</button>
      </div>
      <div id="dash-platform-grid" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px"></div>
    </div>
  </div>

  <!-- PURCHASES -->
  <div class="section" id="section-purchases">
    <div class="page-title">🧾 Token Purchases</div>
    <div class="filter-bar">
      <button class="ftab active" onclick="loadPurchases('pending',this)">⏳ Pending Approval</button>
      <button class="ftab" onclick="loadPurchases('completed',this)">✅ Completed</button>
      <button class="ftab" onclick="loadPurchases('failed',this)">❌ Failed</button>
      <button class="ftab" onclick="loadPurchases('all',this)">📋 All</button>
    </div>
    <div id="purchases-list"></div>
  </div>

  <!-- CASHOUTS -->
  <div class="section" id="section-cashouts">
    <div class="page-title">💸 Cashout Requests</div>
    <div class="filter-bar">
      <button class="ftab active" onclick="loadCashouts('pending',this)">⏳ Pending</button>
      <button class="ftab" onclick="loadCashouts('sent',this)">✅ Sent</button>
      <button class="ftab" onclick="loadCashouts('rejected',this)">❌ Denied</button>
      <button class="ftab" onclick="loadCashouts('deleted',this)">🗑 Deleted</button>
    </div>
    <div id="cashouts-table"></div>
  </div>

  <!-- USERS -->
  <!-- GAMER MANAGEMENT -->
  <div class="section" id="section-users">
    <!-- LIST VIEW -->
    <div id="gm-list-view">
      <div class="page-title">🎮 Gamer Management</div>
      <div class="gm-toolbar">
        <div class="gm-search-wrap">
          <svg class="gm-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
          <input class="gm-search" id="gm-search" type="text" placeholder="Search username, alias, email..." oninput="filterGamers(this.value)">
        </div>
        <div class="gm-filters">
          <button class="gm-filter active" onclick="setGamerFilter('all',this)">All</button>
          <button class="gm-filter" onclick="setGamerFilter('active',this)">Active</button>
          <button class="gm-filter" onclick="setGamerFilter('suspended',this)">Suspended</button>
          <button class="gm-filter" onclick="setGamerFilter('unverified',this)">Unverified</button>
        </div>
        <div class="gm-stats-mini" id="gm-stats-mini"></div>
      </div>
      <div class="gm-grid" id="gm-grid"></div>
    </div>

    <!-- PLAYER DETAIL VIEW -->
    <div id="gm-detail-view" style="display:none">
      <button class="gm-back-btn" onclick="showGamerList()">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="16" height="16"><polyline points="15 18 9 12 15 6"/></svg>
        Back to Players
      </button>
      <div class="gm-profile-card" id="gm-profile-card"></div>
      <div class="gm-tabs">
        <button class="gm-tab active" onclick="switchGamerTab('overview',this)">Overview</button>
        <button class="gm-tab" onclick="switchGamerTab('aliases',this)">🎮 Aliases</button>
        <button class="gm-tab" onclick="switchGamerTab('payout',this)">💸 Payout</button>
        <button class="gm-tab" onclick="switchGamerTab('platforms',this)">🔑 Accounts</button>
        <button class="gm-tab" onclick="switchGamerTab('tokens',this)">Tokens</button>
        <button class="gm-tab" onclick="switchGamerTab('purchases',this)">Purchases</button>
        <button class="gm-tab" onclick="switchGamerTab('cashouts',this)">Cashouts</button>
        <button class="gm-tab" onclick="switchGamerTab('billing',this)">Billing</button>
        <button class="gm-tab" onclick="switchGamerTab('chat',this)">Chat</button>
        <button class="gm-tab" onclick="switchGamerTab('edit',this)">Edit</button>
      </div>
      <!-- TAB: OVERVIEW -->
      <div class="gm-tab-panel active" id="gtab-overview">
        <div class="gm-info-grid" id="gm-info-grid"></div>
        <div class="gm-actions-panel">
          <div class="gm-actions-title">Quick Actions</div>
          <div class="gm-action-btns" id="gm-action-btns"></div>
        </div>
      </div>
      <!-- TAB: PLATFORM ACCOUNTS -->
      <div class="gm-tab-panel" id="gtab-platforms">
        <div class="card" style="margin-bottom:12px">
          <div class="card-title">🔑 Platform Accounts</div>
          <div style="font-size:14px;color:var(--text2);margin-bottom:12px">Manage game platform logins for this player. When you approve a request and set a username/password, it will automatically update their alias.</div>
          <div id="gm-platform-accounts-list"><div style="color:var(--text2);text-align:center;padding:16px">Loading...</div></div>
        </div>
      </div>

      <!-- TAB: PAYOUT METHODS -->
      <div class="gm-tab-panel" id="gtab-payout">
        <div class="card">
          <div class="card-title">💸 Payout Methods</div>
          <div style="font-size:14px;color:var(--text2);margin-bottom:12px">Where this player receives their cashout payments.</div>
          <div id="gm-payout-list"><div style="color:var(--text2);text-align:center;padding:16px">Loading...</div></div>
        </div>
      </div>

      <!-- TAB: PLATFORM ACCOUNTS -->
      <div class="gm-tab-panel" id="gtab-platforms">
        <div class="card">
          <div class="card-title">🔑 Platform Accounts</div>
          <div style="font-size:14px;color:var(--text2);margin-bottom:12px">Game platform logins created for this player.</div>
          <div id="gm-platforms-list"><div style="color:var(--text2);text-align:center;padding:16px">Loading...</div></div>
        </div>
      </div>

      <!-- TAB: ALIASES -->
      <div class="gm-tab-panel" id="gtab-aliases">
        <div class="card" style="margin-bottom:12px">
          <div class="card-title">🎮 Game Aliases</div>
          <div style="font-size:14px;color:var(--text2);margin-bottom:14px">Player's in-game usernames per platform. Edit and save below.</div>
          <div id="gm-aliases-list"><div style="color:var(--text2);text-align:center;padding:16px;font-size:15px">Loading...</div></div>
          <div id="gm-aliases-alert" class="alert" style="margin-top:10px"></div>
          <button class="btn btn-gold" onclick="gmSaveAllAliases()" style="margin-top:12px">💾 SAVE ALL ALIASES</button>
        </div>
      </div>

      <!-- TAB: TOKENS -->
      <div class="gm-tab-panel" id="gtab-tokens">
        <div class="card" style="margin-bottom:14px">
          <div class="card-title">💰 Token Balance</div>
          <div class="gm-token-display" id="gm-token-display">—</div>
        </div>
        <div class="card" style="margin-bottom:14px">
          <div class="card-title">Adjust Tokens</div>
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px">
            <div><label class="gm-edit-label">Amount</label><input class="fi-sm" type="number" id="gm-tok-amount" placeholder="e.g. 50" style="width:100%;padding:10px 12px;font-size:15px"></div>
            <div><label class="gm-edit-label">Reason</label><input class="fi-sm" type="text" id="gm-tok-reason" placeholder="e.g. Bonus" style="width:100%;padding:10px 12px;font-size:15px"></div>
          </div>
          <div style="display:flex;gap:8px">
            <button class="btn btn-green" style="flex:1" onclick="gmAdjustTokens(1)">➕ ADD</button>
            <button class="btn btn-red" style="flex:1" onclick="gmAdjustTokens(-1)">➖ REMOVE</button>
          </div>
          <div id="gm-tok-msg" class="alert" style="margin-top:12px"></div>
        </div>
        <div class="card">
          <div class="card-title">Set Exact Balance</div>
          <div style="display:flex;gap:8px">
            <input class="fi-sm" type="number" id="gm-tok-set" placeholder="New balance" style="flex:1;padding:10px 12px;font-size:15px">
            <button class="btn btn-gold" style="width:100px" onclick="gmSetTokens()">SET</button>
          </div>
        </div>
      </div>
      <!-- TAB: PURCHASES -->
      <div class="gm-tab-panel" id="gtab-purchases">
        <div id="gm-purchases-table"></div>
      </div>
      <!-- TAB: CASHOUTS -->
      <div class="gm-tab-panel" id="gtab-cashouts">
        <div class="card"><div class="tbl-wrap"><div id="gm-cashouts-table"></div></div></div>
      </div>
      <!-- TAB: BILLING -->
      <div class="gm-tab-panel" id="gtab-billing">
        <div class="card" style="margin-bottom:14px">
          <div class="card-title">💳 Saved Payment Info</div>
          <div id="gm-billing-card-display" style="display:none;margin-bottom:16px">
            <div class="admin-saved-card" id="gm-billing-card"></div>
            <div style="display:flex;gap:8px;margin-top:10px">
              <button class="btn btn-red" style="flex:1" onclick="gmClearCard()">🗑 Remove Card</button>
            </div>
          </div>
          <div id="gm-billing-no-card" style="display:none;padding:12px;background:var(--bg3);border-radius:var(--rs);font-size:15px;color:var(--text2);text-align:center;margin-bottom:12px">No card on file</div>
          <div id="gm-billing-alert" class="alert" style="margin-bottom:12px"></div>
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px">
            <div><label class="gm-edit-label">First Name</label><input class="fi-sm" id="gm-b-first" type="text" style="width:100%;padding:10px 12px"></div>
            <div><label class="gm-edit-label">Last Name</label><input class="fi-sm" id="gm-b-last" type="text" style="width:100%;padding:10px 12px"></div>
            <div><label class="gm-edit-label">Email</label><input class="fi-sm" id="gm-b-email" type="email" style="width:100%;padding:10px 12px"></div>
            <div><label class="gm-edit-label">ZIP Code</label><input class="fi-sm" id="gm-b-zip" type="text" style="width:100%;padding:10px 12px"></div>
          </div>
          <div style="margin-bottom:10px"><label class="gm-edit-label">Street Address</label><input class="fi-sm" id="gm-b-address" type="text" style="width:100%;padding:10px 12px"></div>
          <div style="display:grid;grid-template-columns:1fr 70px;gap:8px;margin-bottom:14px">
            <div><label class="gm-edit-label">City</label><input class="fi-sm" id="gm-b-city" type="text" style="width:100%;padding:10px 12px"></div>
            <div><label class="gm-edit-label">State</label><input class="fi-sm" id="gm-b-state" type="text" maxlength="2" style="width:100%;padding:10px 12px;text-transform:uppercase"></div>
          </div>
          <div style="display:flex;gap:8px">
            <button class="btn btn-gold" style="flex:1" onclick="gmSaveBilling()">💾 SAVE BILLING INFO</button>
            <button class="btn btn-red" style="width:120px" onclick="gmClearAllBilling()">🗑 Clear All</button>
          </div>
        </div>
      </div>

      <!-- TAB: CHAT -->
      <div class="gm-tab-panel" id="gtab-chat">
        <div class="admin-chat-wrap" style="height:400px">
          <div class="admin-chat-messages" id="gm-chat-messages"></div>
          <div class="admin-chat-input-bar">
            <input class="admin-chat-input" id="gm-chat-input" type="text" placeholder="Message this player..." onkeydown="if(event.key==='Enter')gmSendMsg()">
            <button class="admin-send-btn" onclick="gmSendMsg()">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
            </button>
          </div>
        </div>
        <button onclick="gmClearThread()" style="margin-top:10px;width:100%;background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:8px;padding:10px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;cursor:pointer">
          🗑 Clear This Conversation
        </button>
      </div>
      <!-- TAB: EDIT -->
      <div class="gm-tab-panel" id="gtab-edit">
        <div class="card" style="margin-bottom:14px">
          <div class="card-title">✏️ Edit Player Info</div>
          <div id="gm-edit-alert" class="alert" style="margin-bottom:12px"></div>
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:14px">
            <div><label class="gm-edit-label">Username</label><input class="fi-sm" id="gm-edit-username" type="text" style="width:100%;padding:10px 12px"></div>
            <div><label class="gm-edit-label">Alias / Nickname</label><input class="fi-sm" id="gm-edit-alias" type="text" style="width:100%;padding:10px 12px"></div>
            <div><label class="gm-edit-label">Email Address</label><input class="fi-sm" id="gm-edit-email" type="email" style="width:100%;padding:10px 12px"></div>
            <div><label class="gm-edit-label">New Password <span style="color:var(--text2);font-weight:400">(blank = keep)</span></label><input class="fi-sm" id="gm-edit-password" type="password" placeholder="Leave blank to keep" style="width:100%;padding:10px 12px"></div>
          </div>
          <button class="btn btn-gold" onclick="gmSaveEdit()">💾 SAVE CHANGES</button>
        </div>
        <div class="card" style="border-color:rgba(255,68,68,.25)">
          <div class="card-title" style="color:var(--red)">⚠️ Danger Zone</div>
          <div style="display:flex;flex-direction:column;gap:8px">
            <button class="btn btn-red" id="gm-suspend-btn" onclick="gmToggleSuspend()">Loading...</button>
            <button class="btn" onclick="gmSendPasswordReset()" style="background:rgba(155,93,229,.12);color:#c77dff;border:1px solid rgba(155,93,229,.3)">🔑 Send Password Reset Email</button>
            <button class="btn" id="gm-admin-toggle-btn" onclick="gmToggleAdmin()">Admin Toggle</button>
            <button class="btn" onclick="gmDeleteAccount()" style="background:rgba(255,30,30,.18);color:#ff6666;border:1px solid rgba(255,30,30,.35)">🗑️ DELETE ACCOUNT PERMANENTLY</button>
          </div>
          <p style="font-size:15px;color:var(--text2);margin-top:12px;line-height:1.6">Deleting is permanent and removes all purchases, cashouts, and chat history.</p>
        </div>
      </div>
    </div><!-- /gm-detail-view -->
  </div><!-- /section-users -->

  <!-- ── PAYMENT SETTINGS ─────────────────────────────────── -->
  <div class="section" id="section-payments">
    <div class="page-title">💳 Payment Settings</div>
    <div style="background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:10px;padding:12px 16px;margin-bottom:16px;font-size:15px;color:var(--text2);line-height:1.6">
      Enable or disable each payment method. Disabled methods are hidden from players instantly. Card payments run through Square — your Square account must be active for card to work.
    </div>
    <div id="payment-methods-list"></div>
  </div>

  <!-- ── PLATFORM ACCOUNTS ─────────────────────────────── -->
  <!-- ── REFERRALS ──────────────────────────────────────── -->
  <div class="section" id="section-referrals">
    <div class="page-title">🎁 Referral Management</div>
    <div style="display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap">
      <button class="ftab active" onclick="loadAdminReferrals('pending',this)">⏳ Pending</button>
      <button class="ftab" onclick="loadAdminReferrals('verified',this)">✅ Verified</button>
      <button class="ftab" onclick="loadAdminReferrals('denied',this)">❌ Denied</button>
      <button class="ftab" onclick="showRefSection('tiers')">⚙️ Manage Tiers</button>
      <button class="ftab" onclick="showRefSection('shares')">📱 Social Shares</button>
    </div>
    <div id="ref-admin-list"></div>
    <div id="ref-tiers-section" style="display:none">
      <div class="card" style="margin-bottom:14px;border-color:rgba(240,192,64,.2)">
        <div class="card-title" id="ref-tier-form-title">Add Referral Tier</div>
        <div id="ref-tier-alert" class="alert" style="margin-bottom:8px"></div>
        <input type="hidden" id="rt-id">
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px">
          <div><label class="gm-edit-label">Tier Name</label><input class="fi-sm" id="rt-name" type="text" placeholder="e.g. Gold Referrer" style="width:100%;padding:8px 10px"></div>
          <div><label class="gm-edit-label">Min Referrals</label><input class="fi-sm" id="rt-min" type="number" min="1" value="1" style="width:100%;padding:8px 10px"></div>
        </div>
        <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:8px">
          <div><label class="gm-edit-label">Tokens per Referral</label><input class="fi-sm" id="rt-per" type="number" min="0" step="0.5" value="5" style="width:100%;padding:8px 10px"></div>
          <div><label class="gm-edit-label">Milestone Bonus</label><input class="fi-sm" id="rt-bonus" type="number" min="0" value="0" style="width:100%;padding:8px 10px"></div>
          <div><label class="gm-edit-label">Sort Order</label><input class="fi-sm" id="rt-sort" type="number" value="0" style="width:100%;padding:8px 10px"></div>
        </div>
        <div style="margin-bottom:10px"><label class="gm-edit-label">Description</label><input class="fi-sm" id="rt-desc" type="text" placeholder="Shown to players" style="width:100%;padding:8px 10px"></div>
        <div style="display:flex;gap:8px;margin-bottom:12px">
          <div style="flex:1"><label class="gm-edit-label">Status</label>
          <select class="fi-sm" id="rt-active" style="width:100%;padding:8px 10px;background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:var(--rs)">
            <option value="1">Active</option><option value="0">Inactive</option>
          </select></div>
        </div>
        <div style="display:flex;gap:8px">
          <button class="btn btn-gold" onclick="saveRefTier()" style="flex:1">Save Tier</button>
          <button class="btn btn-outline" onclick="resetRefTierForm()" style="width:100px">Clear</button>
        </div>
      </div>
      <div class="card" style="padding:0;overflow:hidden">
        <div style="padding:14px 18px;border-bottom:1px solid var(--border);font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px">All Tiers</div>
        <div id="ref-tiers-admin-list"></div>
      </div>
    </div>
    <div id="ref-shares-section" style="display:none">
      <div style="display:flex;gap:8px;margin-bottom:12px">
        <button class="ftab active" onclick="loadAdminShares('pending',this)">Pending</button>
        <button class="ftab" onclick="loadAdminShares('approved',this)">Approved</button>
        <button class="ftab" onclick="loadAdminShares('denied',this)">Denied</button>
      </div>
      <div id="ref-shares-admin-list"></div>
    </div>
  </div>

  <div class="section" id="section-platform-accounts">
    <div class="page-title">🔑 Platform Account Requests</div>
    <div style="display:flex;gap:8px;margin-bottom:14px">
      <button class="ftab active" onclick="loadPlatformAccountRequests('pending',this)">⏳ Pending</button>
      <button class="ftab" onclick="loadPlatformAccountRequests('approved',this)">✅ Approved</button>
      <button class="ftab" onclick="loadPlatformAccountRequests('denied',this)">❌ Denied</button>
    </div>
    <div id="pa-requests-list"></div>
  </div>

  <!-- ── BROADCASTS ──────────────────────────────────────── -->
  <div class="section" id="section-broadcasts">
    <div class="page-title">📢 Broadcast Messages</div>

    <!-- Compose panel -->
    <div class="card" style="margin-bottom:16px;border-color:rgba(240,192,64,.2)">
      <div class="card-title" style="color:var(--gold)">✉️ Send Broadcast</div>
      <div id="bc-alert" class="alert" style="margin-bottom:10px"></div>
      <div class="fg" style="margin-bottom:10px">
        <label class="gm-edit-label">Subject *</label>
        <input class="fi-sm" id="bc-subject" type="text" placeholder="e.g. Important Update" style="width:100%;padding:10px 12px">
      </div>
      <div class="fg" style="margin-bottom:10px">
        <label class="gm-edit-label">Message *</label>
        <textarea id="bc-message" rows="4" placeholder="Write your message..." style="width:100%;box-sizing:border-box;background:var(--bg3);border:1px solid var(--border);border-radius:var(--rs);padding:10px 12px;color:var(--text);font-family:'Rajdhani',sans-serif;font-size:14px;resize:vertical;outline:none"></textarea>
      </div>
      <div style="display:grid;grid-template-columns:1fr auto;gap:10px;align-items:end">
        <div>
          <label class="gm-edit-label">Send To</label>
          <select class="fi-sm" id="bc-target" style="width:100%;padding:10px 12px;background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:var(--rs)">
            <option value="all">👥 All Active Players</option>
            <option value="verified">✅ Verified Players Only</option>
            <option value="unverified">⏳ Unverified Players Only</option>
            <option value="admins">🔑 Admins Only</option>
          </select>
        </div>
        <button class="btn btn-gold" style="padding:11px 20px;white-space:nowrap" onclick="sendBroadcast()">📢 SEND BROADCAST</button>
      </div>
    </div>

    <!-- Sent broadcasts list -->
    <div class="card" style="padding:0;overflow:hidden">
      <div style="padding:14px 18px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px">Sent Broadcasts</div>
        <button onclick="loadBroadcasts()" style="background:none;border:none;color:var(--cyan);cursor:pointer;font-size:14px;font-weight:700">↻ Refresh</button>
      </div>
      <div id="bc-list"></div>
    </div>

    <!-- Replies / Reads drawer -->
    <div id="bc-drawer" style="display:none;margin-top:12px">
      <div class="card" style="border-color:rgba(0,229,255,.2)">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">
          <div class="card-title" id="bc-drawer-title" style="margin-bottom:0">Details</div>
          <button onclick="closeBcDrawer()" style="background:none;border:none;color:var(--text2);cursor:pointer;font-size:18px">✕</button>
        </div>
        <div style="display:flex;gap:8px;margin-bottom:14px">
          <button class="ftab active" onclick="switchBcTab('replies',this)" id="bc-tab-replies">💬 Replies</button>
          <button class="ftab" onclick="switchBcTab('reads',this)" id="bc-tab-reads">👁 Read By</button>
        </div>
        <div id="bc-drawer-content"></div>
        <!-- Admin reply -->
        <div style="margin-top:14px;display:flex;gap:8px">
          <input class="fi-sm" id="bc-reply-input" type="text" placeholder="Reply to this broadcast..." style="flex:1;padding:10px 12px" onkeydown="if(event.key==='Enter')adminBroadcastReply()">
          <button class="btn btn-gold" onclick="adminBroadcastReply()" style="padding:10px 16px">Send</button>
        </div>
      </div>
    </div>
  </div>

  <!-- ── PAYOUT SETTINGS ─────────────────────────────── -->
  <div class="section" id="section-payout-settings">
    <div class="page-title">💰 Payout Settings</div>
    <div style="background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:10px;padding:12px 16px;margin-bottom:16px;font-size:15px;color:var(--text2);line-height:1.7">
      Configure how you send cashout payments to players. <strong style="color:var(--cyan)">Square Gift Card</strong> sends instantly. <strong style="color:var(--gold)">Manual methods</strong> show the player handle so you send from the app and mark done.
    </div>
    <div id="payout-settings-list"></div>
  </div>

  <!-- ── CASHOUT METHOD TYPES ──────────────────────────────── -->
  <div class="section" id="section-cashout-methods">
    <div class="page-title">💸 Cashout Methods</div>
    <div style="background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:10px;padding:12px 16px;margin-bottom:16px;font-size:15px;color:var(--text2);line-height:1.6">
      💸 Manage the payout method types available to players when they cash out. Active methods appear in the player's payout method dropdown.
    </div>

    <!-- Add / Edit form -->
    <div class="card" id="cmt-form-card" style="margin-bottom:16px">
      <div class="card-title" id="cmt-form-title">➕ Add Cashout Method</div>
      <div id="cmt-form-alert" class="alert" style="margin-bottom:10px"></div>
      <input type="hidden" id="cmt-id" value="">
      <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px">
        <div>
          <label class="gm-edit-label">Label *</label>
          <input class="fi-sm" id="cmt-label" type="text" placeholder="e.g. Venmo" style="width:100%;padding:10px 12px">
        </div>
        <div>
          <label class="gm-edit-label">Slug * <span style="font-weight:400;color:var(--text2)">lowercase, no spaces</span></label>
          <input class="fi-sm" id="cmt-slug" type="text" placeholder="e.g. venmo" style="width:100%;padding:10px 12px" oninput="this.value=this.value.toLowerCase().replace(/[^a-z0-9_]/g,'')">
        </div>
      </div>
      <div style="display:grid;grid-template-columns:80px 1fr;gap:10px;margin-bottom:10px">
        <div>
          <label class="gm-edit-label">Icon</label>
          <input class="fi-sm" id="cmt-icon" type="text" value="💰" maxlength="4" style="width:100%;padding:10px 12px;font-size:20px;text-align:center">
        </div>
        <div>
          <label class="gm-edit-label">Description <span style="font-weight:400;color:var(--text2)">shown to players</span></label>
          <input class="fi-sm" id="cmt-desc" type="text" placeholder="e.g. Send via Venmo username" style="width:100%;padding:10px 12px">
        </div>
      </div>
      <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px">
        <div>
          <label class="gm-edit-label">Sort Order</label>
          <input class="fi-sm" id="cmt-sort" type="number" value="99" min="0" style="width:100%;padding:10px 12px">
        </div>
        <div>
          <label class="gm-edit-label">Status</label>
          <select class="fi-sm" id="cmt-active" style="width:100%;padding:10px 12px;background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:var(--rs)">
            <option value="1">✅ Active</option>
            <option value="0">⏸ Inactive</option>
          </select>
        </div>
      </div>
      <div style="display:flex;gap:8px">
        <button class="btn btn-gold" style="flex:1" onclick="saveCashoutMethod()">💾 SAVE</button>
        <button class="btn btn-outline" onclick="resetCmtForm()" style="width:100px">CLEAR</button>
      </div>
    </div>

    <!-- Methods list -->
    <div class="card" style="padding:0;overflow:hidden">
      <div style="padding:14px 18px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px">Active &amp; Inactive Methods</div>
        <div style="font-size:14px;color:var(--text2)" id="cmt-count">Loading...</div>
      </div>
      <div id="cmt-list"></div>
    </div>
  </div>

  <!-- ── GAME MANAGEMENT ─────────────────────────────────── -->
  <div class="section" id="section-games">
    <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px;flex-wrap:wrap;gap:10px">
      <div class="page-title" style="margin-bottom:0">🕹️ Game Management</div>
      <?php if ((int)$_SESSION['user_id'] === MASTER_ADMIN_ID): ?>
      <button class="btn btn-gold" onclick="resetGameForm();document.getElementById('game-form-card').scrollIntoView({behavior:'smooth'})" style="padding:10px 20px;font-size:15px">
        ➕ Add New Game
      </button>
      <?php endif; ?>
    </div>

    <!-- Add / Edit form — master admin always sees this; others see it only when editing -->
    <div class="card" id="game-form-card" style="margin-bottom:16px;<?= (int)$_SESSION['user_id'] !== MASTER_ADMIN_ID ? 'display:none' : '' ?>">
      <div class="card-title" id="game-form-title">➕ Add New Game</div>
      <div id="game-form-alert" class="alert" style="margin-bottom:10px"></div>
      <input type="hidden" id="gf-id" value="">
      <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px">
        <div>
          <label class="gm-edit-label">Game Name *</label>
          <input class="fi-sm" id="gf-name" type="text" placeholder="e.g. VBlink 777" style="width:100%;padding:10px 12px">
        </div>
        <div>
          <label class="gm-edit-label">Slug (ID) * <span style="font-weight:400;color:var(--text2)">lowercase, no spaces</span></label>
          <input class="fi-sm" id="gf-slug" type="text" placeholder="e.g. vblink777" style="width:100%;padding:10px 12px" oninput="this.value=this.value.toLowerCase().replace(/[^a-z0-9_]/g,'')">
        </div>
      </div>
      <div style="margin-bottom:10px">
        <label class="gm-edit-label">Player URL * <span style="font-weight:400;color:var(--text2)">shown to players — opens the game</span></label>
        <input class="fi-sm" id="gf-player-url" type="url" placeholder="https://game.example.com/play" style="width:100%;padding:10px 12px">
      </div>
      <div style="margin-bottom:10px">
        <label class="gm-edit-label">Username URL Param <span style="font-weight:400;color:var(--text2)">— optional: query param name the platform uses to pre-fill login (e.g. <code style="background:rgba(255,255,255,.07);padding:1px 5px;border-radius:3px">username</code>)</span></label>
        <input class="fi-sm" id="gf-alias-param" type="text" placeholder="e.g. username, user, login" maxlength="50" style="width:100%;padding:10px 12px">
      </div>
      <!-- Agent Fields — EDIT mode (master admin only) -->
      <div id="gf-agent-edit" style="background:rgba(155,93,229,0.06);border:1px solid rgba(155,93,229,0.2);border-radius:8px;padding:12px 14px;margin-bottom:10px;display:none">
        <div style="font-size:12px;font-weight:700;color:var(--purple);letter-spacing:1px;text-transform:uppercase;margin-bottom:10px">🔐 Agent Info — Admin Only</div>
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px">
          <div>
            <label class="gm-edit-label">Agent Login</label>
            <input class="fi-sm" id="gf-agent-login" type="text" placeholder="Username or email" style="width:100%;padding:10px 12px">
          </div>
          <div>
            <label class="gm-edit-label">Agent Password</label>
            <input class="fi-sm" id="gf-agent-password" type="text" placeholder="Password" style="width:100%;padding:10px 12px">
          </div>
        </div>
        <div style="margin-bottom:10px">
          <label class="gm-edit-label">Agent Link <span style="font-weight:400;color:var(--text2)">admin/console URL</span></label>
          <div style="display:flex;gap:6px;align-items:center">
            <input class="fi-sm" id="gf-agent-link" type="url" placeholder="https://admin.game.example.com" style="flex:1;padding:10px 12px">
            <a id="gf-agent-link-open" href="#" target="_blank" rel="noopener" onclick="return openFieldUrl('gf-agent-link')"
              style="background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.25);color:var(--cyan);border-radius:6px;padding:9px 12px;font-size:13px;font-weight:700;text-decoration:none;white-space:nowrap">↗</a>
          </div>
        </div>
        <div style="margin-bottom:10px">
          <label class="gm-edit-label">Games Link <span style="font-weight:400;color:var(--text2)">game listing or lobby URL</span></label>
          <div style="display:flex;gap:6px;align-items:center">
            <input class="fi-sm" id="gf-games-link" type="url" placeholder="https://game.example.com/lobby" style="flex:1;padding:10px 12px">
            <a id="gf-games-link-open" href="#" target="_blank" rel="noopener" onclick="return openFieldUrl('gf-games-link')"
              style="background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.25);color:var(--cyan);border-radius:6px;padding:9px 12px;font-size:13px;font-weight:700;text-decoration:none;white-space:nowrap">↗</a>
          </div>
        </div>
        <div>
          <label class="gm-edit-label">Agent Guide <span style="font-weight:400;color:var(--text2)">notes, instructions, tips</span></label>
          <textarea class="fi-sm" id="gf-agent-guide" rows="3" placeholder="Step-by-step agent instructions, notes, or tips..." style="width:100%;padding:10px 12px;resize:vertical;font-family:inherit;font-size:14px"></textarea>
        </div>
        <div style="border-top:1px solid rgba(155,93,229,0.2);margin-top:12px;padding-top:12px">
          <div style="font-size:11px;font-weight:700;color:var(--purple);letter-spacing:1px;text-transform:uppercase;margin-bottom:8px">Sub-Account</div>
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
            <div>
              <label class="gm-edit-label">Sub-Account Agent Login</label>
              <input class="fi-sm" id="gf-sub-agent-login" type="text" placeholder="Username or email" style="width:100%;padding:10px 12px">
            </div>
            <div>
              <label class="gm-edit-label">Sub-Account Agent Password</label>
              <input class="fi-sm" id="gf-sub-agent-password" type="text" placeholder="Password" style="width:100%;padding:10px 12px">
            </div>
          </div>
        </div>
        <div style="border-top:1px solid rgba(155,93,229,0.2);margin-top:12px;padding-top:12px">
          <div style="font-size:11px;font-weight:700;color:var(--purple);letter-spacing:1px;text-transform:uppercase;margin-bottom:8px">Cashier</div>
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
            <div>
              <label class="gm-edit-label">Cashier Login</label>
              <input class="fi-sm" id="gf-cashier-login" type="text" placeholder="Username or email" style="width:100%;padding:10px 12px">
            </div>
            <div>
              <label class="gm-edit-label">Cashier Password</label>
              <input class="fi-sm" id="gf-cashier-password" type="text" placeholder="Password" style="width:100%;padding:10px 12px">
            </div>
          </div>
        </div>
      </div>

      <!-- Agent Fields — VIEW mode (non-master admins) -->
      <div id="gf-agent-view" style="background:rgba(155,93,229,0.06);border:1px solid rgba(155,93,229,0.2);border-radius:8px;padding:12px 14px;margin-bottom:10px;display:none">
        <div style="font-size:12px;font-weight:700;color:var(--purple);letter-spacing:1px;text-transform:uppercase;margin-bottom:10px">🔐 Agent Info — View Only</div>
        <div id="gf-agent-view-content" style="display:flex;flex-direction:column;gap:6px"></div>
      </div>

      <!-- Credit Accounting — admin only -->
      <div style="background:rgba(0,229,255,0.04);border:1px solid rgba(0,229,255,0.2);border-radius:8px;padding:12px 14px;margin-bottom:10px">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
          <div style="font-size:12px;font-weight:700;color:var(--cyan);letter-spacing:1px;text-transform:uppercase">💳 Credit Accounting — Admin Only</div>
        </div>
        <div style="display:flex;align-items:center;gap:12px;margin-top:8px">
          <div style="flex:1">
            <div style="font-size:12px;color:var(--text2);margin-bottom:3px;font-weight:600;text-transform:uppercase;letter-spacing:.5px">Available Credits</div>
            <div id="gf-credit-total" style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:26px;color:var(--cyan)">—</div>
          </div>
          <button type="button" onclick="openCreditModal()" id="gf-credit-btn"
            style="background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.3);color:var(--cyan);border-radius:8px;padding:10px 18px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;cursor:pointer;white-space:nowrap"
            disabled>📋 Manage Credits</button>
        </div>
      </div>

      <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:14px">
        <div>
          <label class="gm-edit-label">Brand Color</label>
          <div style="display:flex;align-items:center;gap:8px">
            <input type="color" id="gf-color" value="#f0c040" style="width:44px;height:38px;padding:2px;border:1px solid var(--border);border-radius:6px;background:var(--bg3);cursor:pointer">
            <input class="fi-sm" id="gf-color-hex" type="text" value="#f0c040" maxlength="7" style="flex:1;padding:10px 10px" oninput="syncColorPicker(this.value)">
          </div>
        </div>
        <div>
          <label class="gm-edit-label">Sort Order</label>
          <input class="fi-sm" id="gf-sort" type="number" value="99" min="0" style="width:100%;padding:10px 12px">
        </div>
        <div>
          <label class="gm-edit-label">Status</label>
          <select class="fi-sm" id="gf-active" style="width:100%;padding:10px 12px;background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:var(--rs)">
            <option value="1">✅ Active</option>
            <option value="0">⏸ Inactive</option>
          </select>
        </div>
      </div>
      <div style="display:flex;gap:8px">
        <button class="btn btn-gold" style="flex:1" onclick="saveGame()">💾 SAVE GAME</button>
        <button class="btn btn-outline" onclick="resetGameForm()" style="width:100px">CLEAR</button>
      </div>
    </div>

    <!-- Games list -->
    <div class="card" style="padding:0;overflow:hidden">
      <div style="padding:14px 18px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px">Active & Inactive Games</div>
        <div style="font-size:14px;color:var(--text2)" id="games-count">Loading...</div>
      </div>
      <div id="games-list"></div>
    </div>

    <?php if ((int)$_SESSION['user_id'] === MASTER_ADMIN_ID): ?>
    <!-- Archived Games — master admin only -->
    <div class="card" style="padding:0;overflow:hidden;margin-top:16px">
      <div style="padding:14px 18px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;color:var(--text2)">🗄️ Archived Games</div>
        <button onclick="loadArchivedGames()" style="background:none;border:none;color:var(--cyan);font-size:13px;font-weight:700;cursor:pointer">↻ Refresh</button>
      </div>
      <div id="archived-games-list"><div style="padding:16px 18px;color:var(--text2);font-size:14px">Loading...</div></div>
    </div>
    <?php endif; ?>
  </div>

  <!-- ── HISTORY ─────────────────────────────────── -->
  <div class="section" id="section-history">
    <div class="page-title">📋 Full Audit Log <span style="font-size:15px;font-weight:400;color:var(--text2);margin-left:8px">90-day rolling · 20 per page</span></div>

    <!-- Filters row -->
    <div style="display:flex;gap:8px;margin-bottom:14px;flex-wrap:wrap;align-items:center">
      <select id="hist-category" onchange="loadHistory(1)" style="background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;cursor:pointer">
        <option value="">📂 All Categories</option>
        <option value="auth">🔐 Auth (Login/Register)</option>
        <option value="player">👤 Player Actions</option>
        <option value="admin">🛡️ Admin Actions</option>
        <option value="security">⚠️ Security Events</option>
        <option value="general">📋 General</option>
      </select>
      <select id="hist-severity" onchange="loadHistory(1)" style="background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;cursor:pointer">
        <option value="">🔍 All Severity</option>
        <option value="critical">🔴 Critical</option>
        <option value="warning">🟡 Warning</option>
        <option value="info">🟢 Info</option>
      </select>
      <input type="text" id="hist-search" placeholder="Search user, action, detail..." onkeydown="if(event.key==='Enter')loadHistory(1)"
        style="background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-size:14px;width:200px">
      <input type="date" id="hist-date" onchange="loadHistory(1)"
        style="background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-size:14px">
      <button onclick="loadHistory(1)" style="background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.2);color:var(--cyan);border-radius:8px;padding:8px 14px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;cursor:pointer">↻ Refresh</button>
      <button onclick="exportHistory()" style="background:rgba(240,192,64,.08);border:1px solid rgba(240,192,64,.2);color:var(--gold);border-radius:8px;padding:8px 14px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;cursor:pointer">⬇ Export CSV</button>
      <span id="hist-count" style="font-size:14px;color:var(--text2);margin-left:4px"></span>
    </div>

    <!-- Summary stats bar -->
    <div id="hist-stats" style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:14px"></div>

    <!-- Log table -->
    <div id="history-table"></div>

    <!-- Pagination -->
    <div id="hist-pagination" style="display:flex;gap:8px;justify-content:center;margin-top:16px;flex-wrap:wrap"></div>
  </div>

  <!-- ── BACKUPS ──────────────────────────────────────────── -->
  <div class="section" id="section-backups">
    <div class="page-title">💾 Backup System</div>

    <div style="background:rgba(0,229,255,.05);border:1px solid rgba(0,229,255,.15);border-radius:10px;padding:12px 18px;margin-bottom:18px;display:flex;align-items:center;gap:14px;flex-wrap:wrap">
      <div style="flex:1;min-width:200px">
        <div style="font-size:14px;font-weight:700;color:var(--cyan);margin-bottom:2px">🕐 Automated Schedule</div>
        <div style="font-size:14px;color:var(--text2)">Daily at 2:00 AM · 7 rolling backups · Files + full database export</div>
      </div>
      <div style="display:flex;gap:8px">
        <button class="btn btn-gold" id="backup-create-btn" onclick="createBackup()" style="padding:10px 20px;font-size:15px">📦 Create Backup Now</button>
        <button onclick="loadBackups()" style="background:none;border:1px solid var(--border);color:var(--text2);border-radius:var(--rs);padding:10px 14px;cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px">↻</button>
      </div>
    </div>

    <div id="backup-alert" class="alert" style="margin-bottom:12px"></div>

    <div class="card" style="padding:0;overflow:hidden">
      <div style="padding:14px 18px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px">Available Backups <span style="color:var(--text2);font-weight:400;font-size:13px">(last 7 days)</span></div>
        <div id="backup-count" style="font-size:13px;color:var(--text2)"></div>
      </div>
      <div id="backup-list"><div style="padding:24px;text-align:center;color:var(--text2);font-size:15px">Loading...</div></div>
    </div>
  </div>

  <!-- PENDING SIGNUPS -->
  <div class="section" id="section-pending">
    <div class="page-title">⏳ Pending Signups</div>
    <div style="background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:10px;padding:12px 16px;margin-bottom:14px;font-size:15px;color:var(--text2);line-height:1.6">
      ⏳ Players who registered but haven't verified their email yet. <strong style="color:var(--gold)">Approve</strong> to create their account immediately, or <strong style="color:var(--red)">Delete</strong> to remove the request.
    </div>
    <div id="pending-list"></div>
  </div>

  <!-- CHAT INBOX -->
  <div class="section" id="section-chat">
    <div class="page-title">Live Chat
      <span style="font-size:15px;font-weight:400;color:var(--green);margin-left:10px;letter-spacing:.5px">
        ● Auto-refreshing every 5s
      </span>
    </div>

    <!-- INBOX VIEW -->
    <div id="chat-inbox-view">

      <!-- NEW MESSAGE COMPOSE PANEL -->
      <div class="card" style="margin-bottom:14px;border-color:rgba(240,192,64,.2);background:linear-gradient(135deg,#1a1228,#0d1820)">
        <div class="card-title" style="color:var(--gold);margin-bottom:12px">✉️ Send Message to Player</div>
        <!-- Player search -->
        <div style="position:relative;margin-bottom:10px">
          <input class="fi-sm" id="compose-search" type="text" placeholder="Search by name, alias or email..."
            style="width:100%;padding:10px 12px;font-size:14px"
            oninput="searchComposePlayers(this.value)" autocomplete="off">
          <div id="compose-dropdown" style="display:none;position:absolute;top:100%;left:0;right:0;background:var(--bg3);border:1px solid var(--border);border-radius:8px;z-index:50;max-height:200px;overflow-y:auto;margin-top:4px;box-shadow:0 8px 24px rgba(0,0,0,.4)"></div>
        </div>
        <!-- Selected player chip -->
        <div id="compose-selected" style="display:none;background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.2);border-radius:8px;padding:8px 12px;margin-bottom:10px;display:none;align-items:center;gap:10px">
          <div id="compose-player-avatar" style="width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;color:#fff;flex-shrink:0;background:#7b2fbe">?</div>
          <div style="flex:1;min-width:0">
            <div id="compose-player-name" style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text)">—</div>
            <div id="compose-player-info" style="font-size:15px;color:var(--text2)">—</div>
          </div>
          <button onclick="clearComposePicker()" style="background:none;border:none;color:var(--text2);cursor:pointer;font-size:18px;line-height:1;padding:0 4px">×</button>
        </div>
        <!-- Message box -->
        <textarea id="compose-msg" rows="3" placeholder="Type your message..."
          style="width:100%;box-sizing:border-box;background:var(--bg3);border:1px solid var(--border);border-radius:8px;padding:10px 12px;color:var(--text);font-family:'Rajdhani',sans-serif;font-size:14px;resize:vertical;outline:none;margin-bottom:10px"
          onkeydown="if(event.key==='Enter'&&event.ctrlKey)adminComposeSend()"></textarea>
        <div style="display:flex;justify-content:space-between;align-items:center">
          <div style="font-size:15px;color:var(--text2)">Ctrl+Enter to send · Player will see it in their Support chat</div>
          <button class="btn btn-gold" style="width:120px" onclick="adminComposeSend()">
            📨 SEND
          </button>
        </div>
        <div id="compose-alert" class="alert" style="margin-top:10px"></div>
      </div>

      <!-- Inbox list -->
      <div style="background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:10px;padding:12px 16px;margin-bottom:14px;font-size:15px;color:var(--text2);line-height:1.6;display:flex;align-items:center;gap:10px">
        <span style="flex:1">📨 Messages from players appear below. Click any conversation to open it and reply.</span>
        <button onclick="adminClearAllChats()" style="background:rgba(255,68,68,.1);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:8px;padding:7px 12px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;cursor:pointer;white-space:nowrap;flex-shrink:0">
          🗑 Clear All
        </button>
      </div>
      <div class="card" style="padding:0;overflow:hidden">
        <div id="chat-inbox-list"></div>
      </div>
    </div>

    <!-- THREAD VIEW -->
    <div id="chat-thread-view" style="display:none">
      <div style="display:flex;align-items:center;gap:10px;margin-bottom:14px">
        <button onclick="showChatInbox()" style="background:none;border:none;color:var(--cyan);cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;display:flex;align-items:center;gap:6px;padding:0;flex:1">
          ← Back to Inbox
        </button>
        <button onclick="adminClearThread()" style="background:rgba(255,68,68,.1);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:8px;padding:6px 12px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;cursor:pointer">
          🗑 Clear Thread
        </button>
      </div>
      <div class="admin-chat-wrap">
        <div class="admin-chat-header" id="admin-chat-header">
          <div class="admin-chat-avatar" id="admin-chat-avatar">?</div>
          <div>
            <div class="admin-chat-name" id="admin-chat-name">—</div>
            <div class="admin-chat-meta" id="admin-chat-meta">—</div>
          </div>
        </div>
        <div class="admin-chat-messages" id="admin-chat-messages"></div>
        <div class="admin-chat-input-bar">
          <input class="admin-chat-input" id="admin-chat-input" type="text" placeholder="Reply to player..."
            onkeydown="if(event.key==='Enter')adminSendMsg()">
          <button class="admin-send-btn" onclick="adminSendMsg()">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
          </button>
        </div>
      </div>
    </div>
  </div>

  <!-- PROCESS PAYOUT MODAL -->
  <!-- ── CREDIT ACCOUNTING MODAL ───────────────────────── -->
  <div id="credit-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.88);z-index:950;align-items:flex-start;justify-content:center;padding:20px;overflow-y:auto">
    <div style="background:var(--bg3);border:1px solid rgba(0,229,255,.25);border-radius:16px;padding:0;max-width:640px;width:100%;margin:auto">

      <!-- Header -->
      <div style="padding:20px 24px 16px;border-bottom:1px solid var(--border)">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
          <div style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:18px;color:var(--cyan)">💳 Credit Accounting</div>
          <button onclick="closeCreditModal()" style="background:none;border:none;color:var(--text2);font-size:20px;cursor:pointer;line-height:1">✕</button>
        </div>
        <div id="cm-platform-name" style="font-size:13px;color:var(--text2);margin-bottom:10px"></div>
        <div style="background:rgba(0,229,255,0.07);border:1px solid rgba(0,229,255,0.2);border-radius:10px;padding:14px 18px;display:flex;align-items:center;gap:16px">
          <div>
            <div style="font-size:11px;font-weight:700;color:var(--cyan);letter-spacing:1px;text-transform:uppercase;margin-bottom:2px">Total Credits This Platform</div>
            <div id="cm-total" style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:32px;color:var(--cyan)">0</div>
          </div>
        </div>
      </div>

      <!-- Add / Edit form -->
      <div style="padding:16px 24px;border-bottom:1px solid var(--border)">
        <div id="cm-form-title" style="font-size:13px;font-weight:700;color:var(--text2);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">➕ Add Credit Entry</div>
        <input type="hidden" id="cm-entry-id" value="">
        <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:10px">
          <div>
            <label class="gm-edit-label">Credits Purchased *</label>
            <input class="fi-sm" id="cm-credits" type="number" min="0" step="0.01" placeholder="0.00" style="width:100%;padding:9px 11px">
          </div>
          <div>
            <label class="gm-edit-label">Date *</label>
            <input class="fi-sm" id="cm-date" type="date" style="width:100%;padding:9px 11px">
          </div>
          <div>
            <label class="gm-edit-label">Payment Method</label>
            <input class="fi-sm" id="cm-method" type="text" placeholder="e.g. Venmo, Cash" style="width:100%;padding:9px 11px">
          </div>
        </div>
        <div style="margin-bottom:10px">
          <label class="gm-edit-label">Notes <span style="font-weight:400;color:var(--text2)">(optional)</span></label>
          <input class="fi-sm" id="cm-notes" type="text" placeholder="Any additional notes..." style="width:100%;padding:9px 11px">
        </div>
        <div id="cm-form-alert" class="alert" style="margin-bottom:8px"></div>
        <div style="display:flex;gap:8px">
          <button class="btn btn-gold" style="flex:1" onclick="saveCreditEntry()">💾 SAVE ENTRY</button>
          <button class="btn btn-outline" onclick="resetCreditForm()" style="width:80px">CLEAR</button>
        </div>
      </div>

      <!-- Entries list -->
      <div style="padding:16px 24px">
        <div style="font-size:13px;font-weight:700;color:var(--text2);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">Credit History</div>
        <div id="cm-list"><div style="color:var(--text2);text-align:center;padding:20px">Loading...</div></div>
      </div>

    </div>
  </div>

  <div id="process-payout-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:900;align-items:center;justify-content:center;padding:20px">
    <div style="background:var(--bg3);border:1px solid rgba(240,192,64,.3);border-radius:16px;padding:28px 24px;max-width:480px;width:100%;max-height:90vh;overflow-y:auto">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
        <div style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:20px;color:var(--gold)">Process Payout</div>
        <button onclick="closePayoutModal()" style="background:none;border:none;color:var(--text2);font-size:20px;cursor:pointer">X</button>
      </div>
      <div id="ppm-player-info" style="background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px;margin-bottom:16px"></div>
      <div id="ppm-saved-method" style="margin-bottom:16px"></div>
      <div class="fg" style="margin-bottom:12px">
        <label style="font-size:15px;font-weight:700;color:var(--text2);text-transform:uppercase;letter-spacing:1px;display:block;margin-bottom:6px">Send Payment Via</label>
        <select id="ppm-method-select" class="fi fi-select" style="width:100%" onchange="onPayoutMethodChange()">
          <option value="">-- Select payout method --</option>
        </select>
      </div>
      <div id="ppm-method-detail" style="margin-bottom:12px"></div>
      <div class="fg" style="margin-bottom:16px">
        <label style="font-size:15px;font-weight:700;color:var(--text2);text-transform:uppercase;letter-spacing:1px;display:block;margin-bottom:6px">Note (optional)</label>
        <input class="fi-sm" type="text" id="ppm-note" placeholder="e.g. Sent via Venmo 3pm" style="width:100%;padding:10px 12px">
      </div>
      <div id="ppm-alert" class="alert" style="margin-bottom:10px"></div>
      <button id="ppm-submit-btn" class="btn btn-gold" onclick="submitPayout()" style="width:100%;font-size:15px;padding:14px">Process Payout</button>
      <div style="font-size:15px;color:var(--text2);text-align:center;margin-top:10px">This marks the cashout as Sent</div>
    </div>
  </div>

</main>

<script>
const PLATS = <?= PLATFORMS ?>; // fallback static list
let _dynamicPlats = null;
const pname = id => {
  const src = _dynamicPlats || PLATS;
  const p = src.find(p=>(p.id||p.slug)===id);
  return p ? p.name : (id || '—');
};
// Load dynamic platforms list from DB
fetch('/api/platforms.php?action=admin_list').then(r=>r.json()).then(d=>{
  if (d.success) _dynamicPlats = d.platforms.map(p=>({id:p.slug,name:p.name}));
}).catch(()=>{});
const CURRENT_ADMIN_ID = <?= (int)$_SESSION['user_id'] ?>;
const MASTER_ADMIN_ID  = <?= MASTER_ADMIN_ID ?>;
const IS_MASTER_ADMIN  = CURRENT_ADMIN_ID === MASTER_ADMIN_ID;
const methodLabel = m => ({ card:'💳 Card', venmo:'💙 Venmo', chime:'🟢 Chime', cashapp:'💚 Cash App', zelle:'💜 Zelle' }[m] || m);
const methodClass = m => ({ card:'b-card', venmo:'b-venmo', chime:'b-chime', cashapp:'b-cashapp', zelle:'b-zelle' }[m] || '');
let allUsers = [];

async function apiFetch(action, method='GET', body=null) {
  const opts={method,headers:{'Content-Type':'application/json'}};
  if(body)opts.body=JSON.stringify(body);
  const r = await fetch(`/api/admin.php?action=${action}`,opts);
  return r.json();
}

// ─── INIT ──────────────────────────────────────────────────
loadStats();
loadPurchases('pending');
loadCashouts('pending');
loadUsers();
// Initialize game form once DOM is ready
document.addEventListener('DOMContentLoaded', () => resetGameForm());

async function loadStats() {
  const d = await apiFetch('stats');
  if (!d.success) return;
  const s = d.stats;
  document.getElementById('s-users').textContent = s.total_users;
  document.getElementById('s-rev').textContent   = '$'+parseFloat(s.total_revenue).toFixed(2);
  document.getElementById('s-toks').textContent  = s.total_tokens_sold;
  document.getElementById('s-ppurch').textContent= s.pending_purchases;
  document.getElementById('s-pcash').textContent = s.pending_cashouts;
  document.getElementById('badge-purchases').textContent = s.pending_purchases;
  document.getElementById('badge-cashouts').textContent  = s.pending_cashouts;
  const ps = s.pending_signups || 0;
  document.getElementById('badge-pending').textContent  = ps;
  document.getElementById('badge-pending').style.display = ps > 0 ? 'inline-block' : 'none';
  // Dashboard quick lists
  loadDashPurchases();
  loadDashCashouts();
  loadPendingSignups();
  loadPlatformStats();
}

async function loadPlatformStats() {
  const grid = document.getElementById('dash-platform-grid');
  if (!grid) return;
  grid.innerHTML = '<div style="color:var(--text2);font-size:14px;padding:8px 0">Loading...</div>';
  const d = await apiFetch('platform_stats');
  if (!d.success || !d.platforms.length) {
    grid.innerHTML = '<div style="color:var(--text2);font-size:14px;padding:8px 0">No platforms found.</div>';
    return;
  }
  grid.innerHTML = d.platforms.map(p => {
    const bal     = parseFloat(p.credits_balance);
    const balFmt  = bal % 1 === 0 ? bal.toLocaleString() : bal.toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2});
    const color   = p.color || '#00e5ff';
    const balColor = bal <= 0 ? 'var(--red)' : bal < 100 ? 'var(--yellow)' : 'var(--cyan)';
    const lowBadge = bal <= 0
      ? '<div style="font-size:11px;font-weight:700;color:var(--red);letter-spacing:.5px;margin-top:4px">⚠ LOW</div>'
      : (bal < 100 ? '<div style="font-size:11px;font-weight:700;color:var(--yellow);letter-spacing:.5px;margin-top:4px">⚠ LOW</div>' : '');
    return `<div onclick="openGameCredits('${escHtmlA(p.slug)}')" style="background:var(--card);border:1px solid var(--border);border-radius:12px;padding:16px 14px;cursor:pointer;transition:all .18s;position:relative;overflow:hidden"
      onmouseover="this.style.borderColor='${color}44';this.style.transform='translateY(-2px)'" onmouseout="this.style.borderColor='';this.style.transform=''">
      <div style="position:absolute;top:0;left:0;right:0;height:3px;background:${color};opacity:.7;border-radius:12px 12px 0 0"></div>
      <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:13px;color:var(--text);margin-bottom:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${escHtmlA(p.name)}</div>
      <div style="font-size:11px;font-weight:700;color:var(--text2);letter-spacing:1px;text-transform:uppercase;margin-bottom:3px">Credits</div>
      <div style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:22px;color:${balColor};line-height:1">${balFmt}</div>
      ${lowBadge}
      <div style="display:flex;gap:10px;margin-top:12px;padding-top:10px;border-top:1px solid var(--border)">
        <div style="flex:1;text-align:center">
          <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--gold)">$${parseFloat(p.purchases_total).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2})}</div>
          <div style="font-size:11px;color:var(--text2);font-weight:700;letter-spacing:.5px">PURCH</div>
        </div>
        <div style="flex:1;text-align:center;border-left:1px solid var(--border)">
          <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--green)">${parseInt(p.cashouts_total).toLocaleString()} 🪙</div>
          <div style="font-size:11px;color:var(--text2);font-weight:700;letter-spacing:.5px">CASH</div>
        </div>
      </div>
    </div>`;
  }).join('');
}

function openGameCredits(slug) {
  // Switch to Games section and open the credit modal for this platform
  showSec('games');
  // Wait for games to load then find and click the matching game's edit button
  const tryOpen = () => {
    const games = window._gamesData || [];
    const g = games.find(x => x.slug === slug);
    if (g) { editGame(g.id); setTimeout(() => openCreditModal(), 150); }
  };
  if ((window._gamesData||[]).length) { tryOpen(); }
  else { loadGames().then(() => tryOpen()); }
}

// ─── SECTION NAV ───────────────────────────────────────────

// ─── PURCHASE CARD RENDERER ──────────────────────────────
function purchaseCard(p, showActions=true) {
  const isPending = p.status === 'pending';
  const isManual  = p.payment_method !== 'card';
  const amt       = (p.amount_cents/100).toFixed(2);
  const date      = (p.created_at||'').substring(0,16);
  const statusColors = { pending:'var(--gold)', completed:'var(--green)', failed:'var(--red)', refunded:'var(--cyan)' };
  const statusLabels = { pending:'⏳ Pending Approval', completed:'✅ Completed', failed:'❌ Failed', refunded:'↩ Refunded' };
  const statusColor  = statusColors[p.status] || 'var(--text2)';
  const statusLabel  = statusLabels[p.status]  || p.status;
  const mIcons  = { card:'💳', venmo:'💙', cashapp:'💚', zelle:'💜', chime:'🟢', manual:'💵' };
  const mLabels = { card:'Square Card', venmo:'Venmo', cashapp:'Cash App', zelle:'Zelle', chime:'Chime', manual:'Manual' };
  const mIcon  = mIcons[p.payment_method]  || '💰';
  const mLabel = mLabels[p.payment_method] || p.payment_method;
  const platformRow = p.platform_id
    ? '<div style="font-size:14px;color:var(--text2);margin-top:4px">Platform: <strong style="color:var(--cyan)">'+pname(p.platform_id)+'</strong> · Alias: <strong style="color:var(--gold2)">'+escHtmlA(p.game_alias||'—')+'</strong></div>'
    : '';
  const canRefund = showActions && p.status === 'completed' && p.payment_method === 'card' && p.square_payment_id;
  const actions = showActions && isPending
    ? '<div style="display:flex;flex-direction:column;gap:8px;flex-shrink:0;min-width:160px">'+
      '<input class="fi-sm" type="text" id="pnote-'+p.id+'" placeholder="Note to player (optional)" style="width:100%;font-size:14px;padding:8px 10px">'+
      '<button class="btn btn-green" data-pid="'+p.id+'" onclick="resolvePurchase(this.dataset.pid,&quot;completed&quot;)" style="width:100%;font-size:15px;padding:10px;font-weight:700">✓ Approve &amp; Credit</button>'+
      '<button class="btn btn-red" data-pid="'+p.id+'" onclick="resolvePurchase(this.dataset.pid,&quot;failed&quot;)" style="width:100%;font-size:15px;padding:10px">✗ Reject</button></div>'
    : (canRefund
        ? '<div style="display:flex;flex-direction:column;gap:8px;flex-shrink:0;min-width:160px">'+
          '<input class="fi-sm" type="text" id="rnote-'+p.id+'" placeholder="Refund reason (optional)" style="width:100%;font-size:14px;padding:8px 10px">'+
          '<button class="btn btn-red" data-pid="'+p.id+'" data-amt="'+amt+'" onclick="refundPurchase(this.dataset.pid,this.dataset.amt)" style="width:100%;font-size:14px;padding:9px">↩ Refund $'+amt+'</button></div>'
        : (p.admin_note ? '<div style="font-size:14px;color:var(--gold);padding:6px 8px;background:rgba(240,192,64,.07);border-radius:6px;margin-top:4px">📝 '+escHtmlA(p.admin_note)+'</div>' : ''));

  return '<div class="card" id="pr-'+p.id+'" style="margin-bottom:10px;'+(isPending?'border-color:rgba(240,192,64,.25);background:rgba(240,192,64,.02)':'')+'">'+
    '<div style="display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap">'+
    '<div style="flex:1;min-width:180px">'+
    '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:4px">'+
    '<span style="font-family:\'Exo 2\',sans-serif;font-weight:700;font-size:15px">'+escHtmlA(p.username)+'</span>'+
    '<span style="font-size:15px;color:var(--text2)">#'+p.id+'</span>'+
    '<span style="font-size:15px;font-weight:700;color:'+statusColor+';background:rgba(0,0,0,.25);border:1px solid '+statusColor+';border-radius:6px;padding:2px 8px">'+statusLabel+'</span></div>'+
    '<div style="font-size:14px;color:var(--text2)">'+escHtmlA(p.alias||'')+' · '+mIcon+' '+mLabel+' · '+date+'</div>'+
    platformRow+
    '<div style="font-family:\'Exo 2\',sans-serif;font-weight:900;font-size:24px;color:var(--gold);margin-top:6px">'+p.tokens+' 🪙</div>'+
    '<div style="font-size:14px;font-weight:700;color:var(--green)">$'+amt+'</div>'+
    (isManual?'<div style="margin-top:8px;background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:6px;padding:6px 10px;font-size:14px"><span style="color:var(--cyan);font-weight:700">Manual Payment</span> — verify before approving</div>':'')+
    '</div>'+actions+'</div></div>';
}


async function loadPurchases(status, btn=null) {
  if (btn) { document.querySelectorAll('#section-purchases .ftab').forEach(b=>b.classList.remove('active')); btn.classList.add('active'); }
  const d = await apiFetch('purchases&status='+status);
  const el = document.getElementById('purchases-list');
  if (!d.success || !d.purchases.length) { el.innerHTML='<div class="empty">No purchases found.</div>'; return; }
  el.innerHTML = d.purchases.map(p => purchaseCard(p, true)).join('');
}

async function loadDashPurchases() {
  const d = await apiFetch('purchases&status=pending');
  const el = document.getElementById('dash-purchases');
  if (!d.success || !d.purchases.length) { el.innerHTML='<div class="empty">No pending purchases 🎉</div>'; return; }
  el.innerHTML = d.purchases.map(p => purchaseCard(p, true)).join('');
}

async function resolvePurchase(id, status) {
  const note = (document.getElementById('pnote-'+id)?.value||'').trim();
  const d = await apiFetch('resolve_purchase','POST',{id,status,note});
  if (d.success) {
    toast(status==='completed' ? '✓ Tokens credited!' : '✗ Purchase rejected', status==='completed'?'ok':'err');
    document.getElementById('pr-'+id)?.remove();
    loadStats();
  } else toast(d.error||'Error','err');
}

async function refundPurchase(id, maxAmount) {
  if (!confirm('Refund $'+maxAmount+' to this customer via Square? This also claws back the tokens credited for this purchase. This cannot be undone.')) return;
  const reason = (document.getElementById('rnote-'+id)?.value||'').trim();
  const d = await apiFetch('refund_purchase','POST',{id,amount:maxAmount,reason});
  if (d.success) {
    let msg = '✓ Refunded! ' + d.tokens_clawed_back + ' tokens clawed back.';
    if (d.token_shortfall > 0) msg += ' (' + d.token_shortfall + ' tokens already spent, could not claw back)';
    toast(msg, 'ok');
    loadPurchases('all');
    loadStats();
  } else toast(d.error||'Error','err');
}

// ─── CASHOUTS ──────────────────────────────────────────────
const PAYOUT_ICONS_A = { venmo:'💙', cashapp:'💚', zelle:'💜', chime:'🟢', bank:'🏦', other:'💰' };
const PAYOUT_LABELS_A = { venmo:'Venmo', cashapp:'Cash App', zelle:'Zelle', chime:'Chime', bank:'Bank Transfer', other:'Other' };

function cashoutRow(c, showActions=true) {
  const payoutInfo = c.payout_handle
    ? `<div style="margin-top:6px;background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:6px;padding:6px 10px;font-size:14px">
        <span style="font-weight:700;color:var(--cyan)">${PAYOUT_ICONS_A[c.payout_method_type]||'💰'} ${PAYOUT_LABELS_A[c.payout_method_type]||c.payout_method_type}:</span>
        <span style="color:var(--text);margin-left:4px">${escHtmlA(c.payout_handle)}</span>
       </div>`
    : '<div style="font-size:15px;color:var(--red);margin-top:4px">⚠️ No payout method on file</div>';

  const statusColors = { pending:'var(--text2)', locked:'var(--cyan)', approved:'var(--green)', sent:'var(--green)', rejected:'var(--red)', deleted:'var(--text2)' };
  const statusLabels = { pending:'⏳ Draft', locked:'🔒 Ready to Process', sent:'✅ Sent', approved:'✅ Sent', rejected:'❌ Denied', deleted:'🗑 Deleted' };
  const statusColor  = statusColors[c.status] || 'var(--text2)';
  const canAct       = showActions && (c.status === 'pending' || c.status === 'locked');
  const isLocked     = c.status === 'locked';
  const playerAlias  = c.user_alias || c.alias || c.username || '';

  return `<div class="card" style="margin-bottom:10px;${isLocked?'border-color:rgba(0,229,255,.25);background:rgba(0,229,255,.02)':''}">
    <div style="display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap">
      <div style="flex:1;min-width:180px">
        <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:4px">
          <span style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px">${escHtmlA(c.username)}</span>
          <span style="font-size:15px;color:var(--text2)">#${c.id}</span>
          <span style="font-size:15px;font-weight:700;color:${statusColor};background:rgba(0,0,0,.25);border:1px solid ${statusColor};border-radius:6px;padding:2px 8px">${statusLabels[c.status]||c.status}</span>
        </div>
        <div style="font-size:14px;color:var(--text2)">${pname(c.platform_id)} · <span style="color:var(--cyan)">${escHtmlA(c.alias||'')}</span> · <span style="color:var(--text2)">${escHtmlA(playerAlias)}</span></div>
        <div style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:24px;color:var(--gold);margin-top:4px">${c.tokens} 🪙</div>
        <div style="font-size:15px;color:var(--text2);margin-top:2px">${(c.created_at||'').substring(0,16)}</div>
        ${payoutInfo}
        ${c.admin_note ? `<div style="font-size:14px;color:var(--gold);margin-top:6px;padding:6px 8px;background:rgba(240,192,64,.07);border-radius:6px">📝 ${escHtmlA(c.admin_note)}</div>` : ''}
      </div>
      ${canAct ? `
      <div style="display:flex;flex-direction:column;gap:8px;flex-shrink:0;min-width:160px">
        <button class="btn btn-gold" onclick="openPayoutModal(${c.id})" style="width:100%;font-size:15px;padding:10px">
          💰 Process Payout
        </button>
        <button class="btn btn-red" onclick="resolveCashout(${c.id},'rejected')" style="width:100%;font-size:14px;padding:8px">
          ✗ Deny
        </button>
        <button onclick="resolveCashout(${c.id},'deleted')" style="width:100%;background:rgba(255,255,255,.04);border:1px solid var(--border);color:var(--text2);border-radius:8px;padding:8px;font-size:14px;cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700">
          🗑 Delete
        </button>
      </div>` : ''}
    </div>
  </div>`;
}

async function loadCashouts(status, btn=null) {
  if (btn) { document.querySelectorAll('#section-cashouts .ftab').forEach(b=>b.classList.remove('active')); btn.classList.add('active'); }
  const d  = await apiFetch('cashouts&status=' + status);
  const el = document.getElementById('cashouts-table');
  if (!d.success || !d.cashouts.length) { el.innerHTML = '<div class="empty" style="padding:24px;text-align:center">No cashouts found.</div>'; return; }
  el.innerHTML = d.cashouts.map(c => cashoutRow(c, true)).join('');
}

async function loadDashCashouts() {
  const d  = await apiFetch('cashouts&status=pending');
  const el = document.getElementById('dash-cashouts');
  if (!d.success || !d.cashouts.length) { el.innerHTML = '<div class="empty">No pending cashouts 🎉</div>'; return; }
  el.innerHTML = d.cashouts.map(c => cashoutRow(c, true)).join('');
}

async function resolveCashout(id, status) {
  const labels = { approved:'✓ Payment Sent', rejected:'✗ Cashout Denied', deleted:'🗑 Request Deleted' };
  const confirmMsgs = {
    approved: 'Mark this cashout as SENT? This confirms you have sent the payment to the player.',
    rejected: 'Deny this cashout request? Tokens will be returned to the player.',
    deleted:  'Delete this cashout request?'
  };
  if (!confirm(confirmMsgs[status]||'Are you sure?')) return;
  const note = (document.getElementById('cnote-'+id)?.value||'').trim();
  const d    = await apiFetch('resolve_cashout','POST',{id,status,note});
  if (d.success) {
    toast(labels[status]||'Done', status==='approved'?'ok':'err');
    loadCashouts('pending');
    loadDashCashouts();
    loadStats();
  } else toast(d.error||'Error','err');
}

// ─── USERS ─────────────────────────────────────────────────
// ─── GAMER MANAGEMENT ──────────────────────────────────────
let GM = { all: [], filtered: [], filter: 'all', current: null, chatLastId: 0, chatPoll: null };

const AVATAR_COLORS = ['#9b5de5','#e63946','#457b9d','#2ec4b6','#f4a261','#7b2fbe','#ff6b35','#00b4d8'];
function avatarColor(username) { let h=0; for(let c of username) h=(h*31+c.charCodeAt(0))%AVATAR_COLORS.length; return AVATAR_COLORS[h]; }
function avatarInit(username) { return (username||'?').charAt(0).toUpperCase(); }

async function loadUsers() {
  const d = await apiFetch('users');
  if (!d.success) return;
  GM.all = d.users;
  applyGamerFilter();
}

function setGamerFilter(f, btn) {
  GM.filter = f;
  document.querySelectorAll('.gm-filter').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');
  applyGamerFilter();
}

function filterGamers(q) {
  const base = GM.filter === 'all' ? GM.all
    : GM.filter === 'unverified' ? GM.all.filter(u => !parseInt(u.email_verified))
    : GM.all.filter(u => u.status === GM.filter);
  if (!q) { GM.filtered = base; }
  else {
    const lq = q.toLowerCase();
    GM.filtered = base.filter(u =>
      u.username.toLowerCase().includes(lq) ||
      u.alias.toLowerCase().includes(lq) ||
      (u.email||'').toLowerCase().includes(lq)
    );
  }
  renderGamerGrid();
}

function applyGamerFilter() {
  const q = document.getElementById('gm-search').value;
  filterGamers(q);
}

function renderGamerGrid() {
  const el = document.getElementById('gm-grid');
  const users = GM.filtered;

  // Mini stats
  const total = GM.all.length;
  const active = GM.all.filter(u=>u.status==='active'&&parseInt(u.email_verified)).length;
  const susp = GM.all.filter(u=>u.status==='suspended').length;
  const unver = GM.all.filter(u=>!parseInt(u.email_verified)).length;
  document.getElementById('gm-stats-mini').innerHTML =
    `<span style="color:var(--green)">${active} active</span> · <span style="color:var(--red)">${susp} suspended</span> · <span style="color:var(--yellow)">${unver} unverified</span> · ${total} total`;

  if (!users.length) {
    el.innerHTML = '<div class="gm-empty">No players match this filter.</div>';
    return;
  }

  el.innerHTML = users.map(u => {
    const color = avatarColor(u.username);
    const init  = avatarInit(u.username);
    const verified = parseInt(u.email_verified);
    const isSupended = u.status === 'suspended';
    const cardClass = isSupended ? 'suspended' : (!verified ? 'unverified' : '');
    const lastSeen = u.last_login ? timeAgo(u.last_login) : 'Never';
    return `
    <div class="gm-card ${cardClass}" onclick="openGamer(${u.id})">
      <div class="gm-card-top">
        <div class="gm-card-avatar" style="background:linear-gradient(135deg,${color},${color}aa)">${init}</div>
        <div class="gm-card-info">
          <div class="gm-card-name">${escHtmlA(u.username)}</div>
          <div class="gm-card-alias">${escHtmlA(u.alias)}</div>
          <div class="gm-card-badges">
            <span class="badge b-${u.status}">${u.status}</span>
            ${verified ? '<span class="badge" style="background:rgba(0,230,118,.12);color:var(--green)">✓ verified</span>' : '<span class="badge b-pending">⚠ unverified</span>'}
            ${u.is_admin ? '<span class="badge" style="background:rgba(240,192,64,.15);color:var(--gold)">admin</span>' : ''}
          </div>
        </div>
      </div>
      <div class="gm-card-stats">
        <div class="gm-stat"><div class="gm-stat-val">${parseFloat(u.tokens||0)}</div><div class="gm-stat-lbl">TOKENS</div></div>
        <div class="gm-stat"><div class="gm-stat-val" style="font-size:14px;color:var(--text2)">${(u.created_at||'').substring(0,10)}</div><div class="gm-stat-lbl">JOINED</div></div>
        <div class="gm-stat"><div class="gm-stat-val" style="font-size:14px;color:var(--text2)">${lastSeen}</div><div class="gm-stat-lbl">LAST SEEN</div></div>
      </div>
      <div class="gm-card-email">${escHtmlA(u.email||'No email')}</div>
      <div class="gm-card-hover-cta">VIEW PLAYER PROFILE →</div>
    </div>`;
  }).join('');
}

async function openGamer(uid) {
  const d = await apiFetch('user_detail&user_id=' + uid);
  if (!d.success) { toast('Failed to load player', 'err'); return; }
  GM.current = d.user;
  GM.chatLastId = 0;

  document.getElementById('gm-list-view').style.display = 'none';
  document.getElementById('gm-detail-view').style.display = 'block';

  renderGamerProfile(d.user);
  renderGamerOverview(d.user, d.stats);
  populateGamerEdit(d.user);
  updateAdminToggleBtn();
  loadGamerPurchases(uid);
  loadGamerCashouts(uid);
  loadGamerChat(uid, true);

  // Switch to overview tab
  switchGamerTab('overview', document.querySelector('.gm-tab'));

  // Poll chat while detail open
  clearInterval(GM.chatPoll);
  GM.chatPoll = setInterval(() => {
    if (GM.current && document.getElementById('gtab-chat').classList.contains('active')) {
      loadGamerChat(GM.current.id, false);
    }
  }, 3000);
}

function renderGamerProfile(u) {
  const color = avatarColor(u.username);
  const verified = parseInt(u.email_verified);
  document.getElementById('gm-profile-card').innerHTML = `
    <div class="gm-profile-avatar" style="background:linear-gradient(135deg,${color},${color}99)">${avatarInit(u.username)}</div>
    <div class="gm-profile-info">
      <div class="gm-profile-name">${escHtmlA(u.username)}</div>
      <div class="gm-profile-alias">🎮 ${escHtmlA(u.alias)}</div>
      <div class="gm-profile-email">📧 ${escHtmlA(u.email||'No email')}</div>
      <div style="font-size:15px;color:var(--text2);margin-top:4px">
        Joined ${(u.created_at||'').substring(0,10)} ·
        Last login: ${u.last_login ? timeAgo(u.last_login) : 'Never'}
      </div>
    </div>
    <div class="gm-profile-right">
      <div class="gm-profile-tokens">${parseFloat(u.tokens||0)}</div>
      <div class="gm-profile-tok-lbl">TOKENS</div>
      <div class="gm-profile-badges">
        <span class="badge b-${u.status}">${u.status}</span>
        ${verified ? '<span class="badge" style="background:rgba(0,230,118,.12);color:var(--green)">✓ verified</span>' : '<span class="badge b-pending">unverified</span>'}
        ${u.is_admin ? '<span class="badge" style="background:rgba(240,192,64,.15);color:var(--gold)">admin</span>' : ''}
      </div>
    </div>`;
  // Update token display in tokens tab
  document.getElementById('gm-token-display').textContent = parseFloat(u.tokens||0) + ' 🪙';
  // Update suspend button
  const sb  = document.getElementById('gm-suspend-btn');
  const db2 = document.querySelector('[onclick="gmDeleteAccount()"]');
  const isMasterUser = parseInt(u.id) === MASTER_ADMIN_ID;
  if (isMasterUser) {
    sb.textContent  = '🔒 Cannot Suspend Master Admin';
    sb.className    = 'btn';
    sb.disabled     = true;
    sb.style.cssText = 'opacity:.4;cursor:not-allowed;background:rgba(255,68,68,.06);color:var(--red);border:1px solid rgba(255,68,68,.2)';
    if (db2) { db2.disabled = true; db2.style.opacity = '.4'; db2.style.cursor = 'not-allowed'; db2.title = 'Cannot delete master admin account'; }
  } else {
    sb.disabled = false;
    sb.style.cssText = '';
    if (db2) { db2.disabled = false; db2.style.opacity = ''; db2.style.cursor = ''; db2.title = ''; }
    if (u.status === 'active') {
      sb.textContent = '🔒 SUSPEND ACCOUNT (Lock Login)';
      sb.className = 'btn btn-red';
    } else {
      sb.textContent = '🔓 ACTIVATE ACCOUNT (Restore Login)';
      sb.className = 'btn btn-green';
    }
  }
}

function renderGamerOverview(u, stats) {
  const verified = parseInt(u.email_verified);
  document.getElementById('gm-info-grid').innerHTML = [
    { label: 'User ID',       val: '#' + u.id },
    { label: 'Username',      val: escHtmlA(u.username) },
    { label: 'Alias',         val: escHtmlA(u.alias) },
    { label: 'Email',         val: u.email ? escHtmlA(u.email) : '—' },
    { label: 'Status',        val: `<span class="badge b-${u.status}">${u.status}</span>` },
    { label: 'Email Verified',val: verified ? '<span style="color:var(--green)">✓ Yes</span>' : '<span style="color:var(--yellow)">⚠ No</span>' },
    { label: 'Token Balance',  val: `<span style="color:var(--gold);font-family:\'Exo 2\',sans-serif;font-weight:700">${parseFloat(u.tokens||0)} 🪙</span>` },
    { label: 'Total Spent',        val: stats ? `<span style="color:var(--green);font-weight:700">$${parseFloat(stats.total_spent||0).toFixed(2)}</span>` : '—' },
    { label: 'Tokens Purchased',    val: stats ? `<span style="color:var(--gold)">${stats.total_tokens_bought} 🪙</span>` : '—' },
    { label: 'Completed Purchases', val: stats ? `<span style="color:var(--green)">${stats.completed_purchases}</span>` : '—' },
    { label: 'Pending Payments',    val: stats ? `<span style="color:var(--yellow)">${stats.pending_purchases}</span>` : '—' },
    { label: 'Failed Payments',     val: stats ? `<span style="color:var(--red)">${stats.failed_purchases}</span>` : '—' },
    { label: 'Cashout Requests',    val: stats ? stats.total_cashouts + ' total' : '—' },
    { label: 'Joined',        val: (u.created_at||'').substring(0,16) },
    { label: 'Last Login',    val: u.last_login ? u.last_login.substring(0,16) : 'Never' },
    { label: 'Admin Access',  val: u.is_admin ? '<span style="color:var(--gold)">Yes</span>' : 'No' },
  ].map(item => `
    <div class="gm-info-item">
      <div class="gm-info-label">${item.label}</div>
      <div class="gm-info-val">${item.val}</div>
    </div>`).join('');

  document.getElementById('gm-action-btns').innerHTML = `
    <button class="btn btn-gold" style="flex:1;min-width:140px" onclick="switchGamerTab('tokens',document.querySelectorAll('.gm-tab')[1])">🪙 Manage Tokens</button>
    <button class="btn btn-cyan" style="flex:1;min-width:140px" onclick="switchGamerTab('chat',document.querySelectorAll('.gm-tab')[4])">💬 Message Player</button>
    <button class="btn" style="flex:1;min-width:140px;background:rgba(155,93,229,.12);color:#c77dff;border:1px solid rgba(155,93,229,.3)" onclick="switchGamerTab('edit',document.querySelectorAll('.gm-tab')[5])">✏️ Edit Account</button>
    ${!parseInt(u.email_verified) ? '<button class="btn btn-gold" style="flex:1;min-width:140px" onclick="gmResendVerify()">📧 Resend Verify Email</button>' : ''}`;
}

function populateGamerEdit(u) {
  document.getElementById('gm-edit-username').value = u.username || '';
  document.getElementById('gm-edit-alias').value    = u.alias    || '';
  document.getElementById('gm-edit-email').value    = u.email    || '';
  document.getElementById('gm-edit-password').value = '';
}

async function loadGamerPurchases(uid) {
  const d = await apiFetch('user_purchases&user_id=' + uid);
  const el = document.getElementById('gm-purchases-table');
  if (!d.success || !d.purchases.length) { el.innerHTML = '<div class="gm-empty">No purchases found.</div>'; return; }

  // Summary strip
  const total = d.purchases.length;
  const completed = d.purchases.filter(p=>p.status==='completed').length;
  const pending   = d.purchases.filter(p=>p.status==='pending').length;
  const failed    = d.purchases.filter(p=>p.status==='failed').length;
  const revenue   = d.purchases.filter(p=>p.status==='completed').reduce((s,p)=>s+(p.amount_cents/100),0);
  const tokens    = d.purchases.filter(p=>p.status==='completed').reduce((s,p)=>s+parseInt(p.tokens),0);

  el.innerHTML = `
  <div class="pm-summary">
    <div class="pm-sum-item"><div class="pm-sum-val" style="color:var(--green)">$${revenue.toFixed(2)}</div><div class="pm-sum-lbl">Revenue</div></div>
    <div class="pm-sum-item"><div class="pm-sum-val" style="color:var(--gold)">${tokens} 🪙</div><div class="pm-sum-lbl">Tokens Sold</div></div>
    <div class="pm-sum-item"><div class="pm-sum-val" style="color:var(--green)">${completed}</div><div class="pm-sum-lbl">Completed</div></div>
    <div class="pm-sum-item"><div class="pm-sum-val" style="color:var(--yellow)">${pending}</div><div class="pm-sum-lbl">Pending</div></div>
    <div class="pm-sum-item"><div class="pm-sum-val" style="color:var(--red)">${failed}</div><div class="pm-sum-lbl">Failed</div></div>
  </div>
  ${d.purchases.map(p => {
    const isCustom  = parseInt(p.is_custom);
    const isPending = p.status === 'pending';
    const isManual  = p.payment_method !== 'card';
    const billing   = [p.billing_name, p.billing_address, [p.billing_city, p.billing_state, p.billing_zip].filter(Boolean).join(' ')].filter(Boolean).join(' · ');
    return `
    <div class="pm-card pm-${p.status}">
      <div class="pm-card-top">
        <div class="pm-card-left">
          <div class="pm-order-id">#${p.id} ${isCustom ? '<span class="pm-custom-badge">CUSTOM</span>' : ''}</div>
          <div class="pm-date">${(p.created_at||'').substring(0,16)}</div>
        </div>
        <div class="pm-card-right">
          <div class="pm-amount">$${(p.amount_cents/100).toFixed(2)}</div>
          <div class="pm-tokens">${p.tokens} 🪙</div>
        </div>
      </div>
      <div class="pm-card-mid">
        <div class="pm-detail-row">
          <span class="badge ${methodClass(p.payment_method)}">${methodLabel(p.payment_method)}</span>
          <span class="badge b-${p.status}">${p.status}</span>
          ${p.card_brand ? `<span class="pm-card-info">💳 ${p.card_brand} ····${p.card_last4||''}</span>` : ''}
        </div>
        <div class="pm-detail-row" style="margin-top:6px">
          <span class="pm-lbl">Platform:</span> <span class="pm-val">${pname(p.platform_id)}</span>
          &nbsp;·&nbsp;
          <span class="pm-lbl">Alias:</span> <span class="pm-val" style="color:var(--cyan)">${escHtmlA(p.game_alias||'—')}</span>
        </div>
        ${billing ? `<div class="pm-detail-row" style="margin-top:4px"><span class="pm-lbl">Billing:</span> <span class="pm-val">${escHtmlA(billing)}</span></div>` : ''}
        ${p.billing_email ? `<div class="pm-detail-row"><span class="pm-lbl">Email:</span> <span class="pm-val" style="color:var(--cyan)">${escHtmlA(p.billing_email)}</span></div>` : ''}
        ${p.square_payment_id ? `<div class="pm-detail-row" style="margin-top:4px"><span class="pm-lbl">Square ID:</span> <span class="pm-val" style="font-family:monospace;font-size:15px;color:var(--text2)">${p.square_payment_id}</span></div>` : ''}
        ${p.failure_reason ? `<div class="pm-failure">⚠️ ${escHtmlA(p.failure_reason)}</div>` : ''}
        ${p.admin_note ? `<div class="pm-admin-note">📝 Admin: ${escHtmlA(p.admin_note)}</div>` : ''}
        ${p.receipt_url ? `<div style="margin-top:6px"><a href="${p.receipt_url}" target="_blank" class="pm-receipt-link">🧾 View Receipt</a></div>` : ''}
      </div>
      ${isPending && isManual ? `
      <div class="pm-actions">
        <input type="text" class="fi-sm" id="pnote-${p.id}" placeholder="Admin note..." style="flex:1">
        <button class="btn btn-green btn-sm" onclick="resolveGamerPurchase(${p.id},'completed',${uid})">✓ Approve</button>
        <button class="btn btn-red btn-sm" onclick="resolveGamerPurchase(${p.id},'failed',${uid})">✗ Reject</button>
      </div>` : ''}
    </div>`
  }).join('')}`;
}

async function resolveGamerPurchase(id, status, uid) {
  const note = (document.getElementById('pnote-'+id)?.value||'').trim();
  const d = await apiFetch('resolve_purchase','POST',{id,status,note});
  if (d.success) {
    toast(status==='completed'?'✓ Tokens credited!':'✗ Purchase rejected', status==='completed'?'ok':'err');
    loadGamerPurchases(uid);
    // Refresh profile token display
    const uData = await apiFetch('user_detail&user_id='+uid);
    if (uData.success) { GM.current = uData.user; renderGamerProfile(uData.user); }
    loadStats();
  } else toast(d.error||'Error','err');
}

async function loadGamerCashouts(uid) {
  const d = await apiFetch('user_cashouts&user_id=' + uid);
  const el = document.getElementById('gm-cashouts-table');
  if (!d.success || !d.cashouts.length) { el.innerHTML = '<div class="gm-empty">No cashouts found.</div>'; return; }
  el.innerHTML = `<table>
    <thead><tr><th>#</th><th>Platform</th><th>Alias</th><th>Tokens</th><th>Status</th><th>Date</th></tr></thead>
    <tbody>${d.cashouts.map(c => `<tr>
      <td style="color:var(--text2)">#${c.id}</td>
      <td>${pname(c.platform_id)}</td>
      <td style="color:var(--cyan)">${escHtmlA(c.alias)}</td>
      <td><strong style="color:var(--gold)">${c.tokens} 🪙</strong></td>
      <td><span class="badge b-${c.status}">${c.status}</span></td>
      <td style="color:var(--text2);font-size:15px">${(c.created_at||'').substring(0,16)}</td>
    </tr>`).join('')}</tbody>
  </table>`;
}

async function loadGamerChat(uid, scrollToBottom) {
  const d = await apiFetch(`chat_thread&user_id=${uid}&since=${GM.chatLastId}`);
  if (!d.success) return;
  const container = document.getElementById('gm-chat-messages');
  if (d.messages.length === 0 && GM.chatLastId === 0) {
    container.innerHTML = '<div style="text-align:center;padding:24px;color:var(--text2);font-size:15px">No messages yet with this player.</div>';
    return;
  }
  if (d.messages.length > 0) {
    if (GM.chatLastId === 0) container.innerHTML = '';
    let lastDate = '';
    d.messages.forEach(msg => {
      const msgDate = msg.created_at.substring(0,10);
      if (msgDate !== lastDate) {
        lastDate = msgDate;
        const div = document.createElement('div');
        div.className = 'admin-date-div';
        div.textContent = formatAdminDateLabel(msgDate);
        container.appendChild(div);
      }
      container.appendChild(buildAdminBubble(msg));
      GM.chatLastId = Math.max(GM.chatLastId, parseInt(msg.id));
    });
    if (scrollToBottom || (container.scrollHeight - container.scrollTop - container.clientHeight < 120))
      container.scrollTop = container.scrollHeight;
  }
}

async function gmClearThread() {
  if (!GM.current) return;
  if (!confirm('Clear all chat messages with ' + GM.current.username + '?\n\nThis cannot be undone.')) return;
  const d = await apiFetch('chat_clear_thread', 'POST', { user_id: GM.current.id });
  if (d.success) {
    document.getElementById('gm-chat-messages').innerHTML =
      '<div style="color:var(--text2);font-size:15px;text-align:center;padding:24px">Conversation cleared.</div>';
    GM.chatLastId = 0;
    toast('Conversation cleared', 'ok');
    loadChatBadge();
  } else toast(d.error || 'Error', 'err');
}

async function gmSendMsg() {
  const input = document.getElementById('gm-chat-input');
  const msg = input.value.trim();
  if (!msg || !GM.current) return;
  input.value = '';
  const container = document.getElementById('gm-chat-messages');
  const temp = buildAdminBubble({ id:'tmp', sender:'admin', message:msg, created_at:new Date().toISOString().replace('T',' ').substring(0,19) });
  temp.style.opacity = '0.6';
  container.appendChild(temp);
  container.scrollTop = container.scrollHeight;
  const d = await apiFetch('chat_admin_send','POST',{user_id:GM.current.id, message:msg});
  if (d.success) { temp.style.opacity='1'; GM.chatLastId = Math.max(GM.chatLastId, d.id); }
  else { temp.remove(); toast('Send failed','err'); }
}

async function gmAdjustTokens(sign) {
  const amt = parseFloat(document.getElementById('gm-tok-amount').value);
  const reason = document.getElementById('gm-tok-reason').value.trim();
  const msgEl = document.getElementById('gm-tok-msg');
  if (isNaN(amt) || amt <= 0) { showAdminAlert(msgEl,'Enter a valid positive amount.','error'); return; }
  const d = await apiFetch('adjust_tokens','POST',{user_id:GM.current.id, amount: sign * amt, reason});
  if (d.success) {
    GM.current.tokens = d.new_balance;
    document.getElementById('gm-token-display').textContent = d.new_balance + ' 🪙';
    document.getElementById('gm-profile-tokens') && (document.querySelector('.gm-profile-tokens') ? document.querySelector('.gm-profile-tokens').textContent = d.new_balance : null);
    renderGamerProfile(GM.current);
    showAdminAlert(msgEl, `Balance updated: ${d.new_balance} tokens`, 'success');
    document.getElementById('gm-tok-amount').value = '';
    loadUsers();
  } else showAdminAlert(msgEl, d.error||'Error','error');
}

async function gmSetTokens() {
  const newBal = parseFloat(document.getElementById('gm-tok-set').value);
  const msgEl = document.getElementById('gm-tok-msg');
  if (isNaN(newBal) || newBal < 0) { showAdminAlert(msgEl,'Enter a valid balance.','error'); return; }
  const d = await apiFetch('set_tokens','POST',{user_id:GM.current.id, balance:newBal});
  if (d.success) {
    GM.current.tokens = d.new_balance;
    document.getElementById('gm-token-display').textContent = d.new_balance + ' 🪙';
    renderGamerProfile(GM.current);
    showAdminAlert(msgEl, `Balance set to ${d.new_balance} tokens`, 'success');
    document.getElementById('gm-tok-set').value = '';
    loadUsers();
  } else showAdminAlert(msgEl, d.error||'Error','error');
}

async function gmSaveEdit() {
  const al = document.getElementById('gm-edit-alert');
  const username = document.getElementById('gm-edit-username').value.trim();
  const alias    = document.getElementById('gm-edit-alias').value.trim();
  const email    = document.getElementById('gm-edit-email').value.trim();
  const password = document.getElementById('gm-edit-password').value;
  if (!username||!alias) { showAdminAlert(al,'Username and alias are required.','error'); return; }
  const d = await apiFetch('edit_user','POST',{user_id:GM.current.id, username, alias, email, password});
  if (d.success) {
    GM.current = {...GM.current, username, alias, email};
    renderGamerProfile(GM.current);
    showAdminAlert(al,'Player info updated!','success');
    loadUsers();
    toast('Saved!','ok');
  } else showAdminAlert(al, d.error||'Error saving.','error');
}

async function gmToggleSuspend() {
  if (GM.current && parseInt(GM.current.id) === MASTER_ADMIN_ID) { toast('Cannot suspend master admin','err'); return; }
  const isSuspended = GM.current.status === 'suspended';
  const action = isSuspended ? 'activate' : 'suspend';
  if (!isSuspended && !confirm(`Suspend ${GM.current.username}? They will be locked out immediately.`)) return;
  const d = await apiFetch('toggle_user','POST',{user_id:GM.current.id});
  if (d.success) {
    GM.current.status = isSuspended ? 'active' : 'suspended';
    renderGamerProfile(GM.current);
    renderGamerOverview(GM.current, null);
    toast(`Account ${isSuspended?'activated':'suspended'}`, 'ok');
    loadUsers();
  } else toast('Error','err');
}

async function gmSendPasswordReset() {
  if (!GM.current.email) { toast('No email on file for this player','err'); return; }
  const d = await apiFetch('send_password_reset','POST',{user_id:GM.current.id});
  if (d.success) toast('Password reset email sent!','ok');
  else toast(d.error||'Error','err');
}

async function gmResendVerify() {
  if (!GM.current.email) { toast('No email on file','err'); return; }
  const d = await apiFetch('resend_verification','POST',{user_id:GM.current.id});
  if (d.success) toast('Verification email sent!','ok');
  else toast(d.error||'Error','err');
}

async function gmToggleAdmin() {
  const u = GM.current;
  if (!u) return;
  const making = !parseInt(u.is_admin);
  const msg = making
    ? 'Grant ADMIN access to ' + u.username + '? They will have full admin panel access.'
    : 'Remove admin access from ' + u.username + '?';
  if (!confirm(msg)) return;
  const d = await apiFetch('toggle_admin','POST',{user_id: u.id});
  if (d.success) {
    GM.current.is_admin = d.is_admin;
    const msg = d.is_admin ? u.username+' is now an ADMIN' : 'Admin removed from '+u.username;
    toast(msg + ' — they must log out and back in for changes to take effect', 'ok');
    renderGamerProfile(GM.current);
    renderGamerOverview(GM.current, null);
    updateAdminToggleBtn();
    loadUsers();
  } else {
    toast(d.error || 'Error', 'err');
  }
}

function updateAdminToggleBtn() {
  const u = GM.current;
  const btn = document.getElementById('gm-admin-toggle-btn');
  if (!btn || !u) return;
  // Only master admin can see/use this button
  if (!IS_MASTER_ADMIN) { btn.style.display = 'none'; return; }
  btn.style.display = 'block';
  const isMaster = u.id == MASTER_ADMIN_ID;
  if (isMaster) {
    btn.textContent = '🔒 Master Admin (Locked)';
    btn.disabled = true;
    btn.className = 'btn';
    btn.style.cssText = 'background:rgba(240,192,64,.08);color:var(--gold);border:1px solid rgba(240,192,64,.2);cursor:not-allowed;opacity:.7';
  } else if (parseInt(u.is_admin)) {
    btn.textContent = '⬇️ Remove Admin Access';
    btn.disabled = false;
    btn.className = 'btn btn-red';
    btn.style.cssText = '';
  } else {
    btn.textContent = '⬆️ Grant Admin Access';
    btn.disabled = false;
    btn.className = 'btn btn-gold';
    btn.style.cssText = '';
  }
}

async function gmDeleteAccount() {
  if (GM.current && parseInt(GM.current.id) === MASTER_ADMIN_ID) { toast('Cannot delete master admin account','err'); return; }
  if (!confirm(`⚠️ PERMANENTLY delete ${GM.current.username}?\n\nThis removes all their data and cannot be undone.`)) return;
  if (!confirm(`Are you absolutely sure? Type OK to confirm deletion of ${GM.current.username}.`)) return;
  const d = await apiFetch('delete_user','POST',{user_id:GM.current.id});
  if (d.success) {
    toast(`${GM.current.username} deleted`,'ok');
    clearInterval(GM.chatPoll);
    showGamerList();
    loadUsers();
    loadStats();
  } else toast(d.error||'Error','err');
}

function showGamerList() {
  clearInterval(GM.chatPoll);
  GM.current = null;
  document.getElementById('gm-list-view').style.display = 'block';
  document.getElementById('gm-detail-view').style.display = 'none';
}

function switchGamerTab(name, btn) {
  document.querySelectorAll('.gm-tab').forEach(b => b.classList.remove('active'));
  document.querySelectorAll('.gm-tab-panel').forEach(p => p.classList.remove('active'));
  if (btn) btn.classList.add('active');
  document.getElementById('gtab-'+name)?.classList.add('active');
  if (name === 'chat' && GM.current) loadGamerChat(GM.current.id, true);
  if (name === 'billing' && GM.current) loadGamerBilling(GM.current.id);
  if (name === 'aliases' && GM.current) gmLoadAliases(GM.current.id);
  if (name === 'payout'     && GM.current) gmLoadPayout(GM.current.id);
  if (name === 'platforms'  && GM.current) gmLoadPlatformAccounts(GM.current.id);
  if (name === 'platforms'  && GM.current) gmLoadPlatformAccounts(GM.current.id);
}

function showAdminAlert(el, msg, type) {
  el.textContent = msg;
  el.className = `alert show alert-${type}`;
  setTimeout(() => el.className = 'alert', 4000);
}

function timeAgo(dtStr) {
  const d = new Date(dtStr.replace(' ','T'));
  const diff = (Date.now() - d) / 1000;
  if (diff < 60) return 'Just now';
  if (diff < 3600) return Math.floor(diff/60) + 'm ago';
  if (diff < 86400) return Math.floor(diff/3600) + 'h ago';
  if (diff < 604800) return Math.floor(diff/86400) + 'd ago';
  return d.toLocaleDateString('en-US',{month:'short',day:'numeric'});
}

// Alias old functions so nothing breaks
function filterUsers(q) { filterGamers(q); }
function adjustTokens(uid) {}
function toggleUser(uid) {}

// ─── FULL HISTORY ──────────────────────────────────────────
var _histPage = 1;

async function loadHistory(page) {
  if (page) _histPage = page;
  const el   = document.getElementById('history-table');
  const pgEl = document.getElementById('hist-pagination');
  const ctEl = document.getElementById('hist-count');
  const stEl = document.getElementById('hist-stats');

  el.innerHTML = '<div style="padding:24px;text-align:center;color:var(--text2)">Loading audit log...</div>';
  if (pgEl) pgEl.innerHTML = '';

  const category = document.getElementById('hist-category')?.value || '';
  const severity = document.getElementById('hist-severity')?.value || '';
  const search   = document.getElementById('hist-search')?.value.trim() || '';
  const date     = document.getElementById('hist-date')?.value || '';

  const params = new URLSearchParams({
    action: 'activity_log_v2',
    page:   _histPage,
    limit:  20,
    category, severity, search, date
  });

  const d = await fetch('/api/admin.php?' + params.toString()).then(r=>r.json());
  if (!d.success) { el.innerHTML = '<div class="empty">Failed to load audit log.</div>'; return; }

  const events = d.events || [];
  const total  = d.total  || 0;
  const pages  = Math.ceil(total / 20);

  if (ctEl) ctEl.textContent = total + ' total events';

  // Stats bar
  if (stEl && d.stats) {
    const s = d.stats;
    stEl.innerHTML = [
      { label:'Total Events', val: total, color:'var(--text)' },
      { label:'Critical', val: s.critical||0, color:'var(--red)' },
      { label:'Warnings',  val: s.warning||0,  color:'var(--gold)' },
      { label:'Unique IPs', val: s.unique_ips||0, color:'var(--cyan)' },
    ].map(x =>
      '<div class="card" style="text-align:center;padding:10px 8px">'+
      '<div style="font-family:\'Exo 2\',sans-serif;font-weight:900;font-size:20px;color:'+x.color+'">'+x.val+'</div>'+
      '<div style="font-size:14px;color:var(--text2);text-transform:uppercase;letter-spacing:.5px">'+x.label+'</div></div>'
    ).join('');
  }

  if (!events.length) {
    el.innerHTML = '<div class="empty" style="padding:24px;text-align:center">No events match these filters.</div>';
    return;
  }

  const SEV_COLORS = { critical:'var(--red)', warning:'var(--gold)', info:'var(--text2)' };
  const CAT_ICONS  = { auth:'🔐', player:'👤', admin:'🛡️', security:'⚠️', general:'📋' };

  let lastDate = '';
  let rows = '';
  for (const e of events) {
    const dt   = (e.created_at||'').substring(0,10);
    const time = (e.created_at||'').substring(11,19);
    if (dt !== lastDate) {
      lastDate = dt;
      const isToday = dt === new Date().toISOString().substring(0,10);
      const label   = isToday ? 'Today' : new Date(dt+'T12:00:00').toLocaleDateString('en-US',{weekday:'short',month:'short',day:'numeric',year:'numeric'});
      rows += '<div style="padding:10px 0 6px;font-size:15px;font-weight:700;color:var(--text2);letter-spacing:1px;text-transform:uppercase;border-bottom:1px solid var(--border);margin-bottom:6px">'+label+'</div>';
    }

    const sevColor = SEV_COLORS[e.severity] || 'var(--text2)';
    const catIcon  = CAT_ICONS[e.category]  || '📋';
    const who      = e.alias || e.username   || '—';
    const adminBy  = e.admin_username ? ' <span style="font-size:14px;color:var(--gold)">by '+escHtmlA(e.admin_username)+'</span>' : '';
    const action   = e.action.replace(/_/g,' ');

    // Build detail row
    let details = '';
    if (e.detail)    details += '<div style="font-size:15px;color:var(--text2);margin-top:2px">'+escHtmlA(e.detail)+'</div>';
    if (e.old_value && e.new_value)
      details += '<div style="font-size:15px;margin-top:2px"><span style="color:var(--red)">'+escHtmlA(e.old_value)+'</span> → <span style="color:var(--green)">'+escHtmlA(e.new_value)+'</span></div>';
    if (e.ip)        details += '<div style="font-size:14px;color:var(--text2);margin-top:2px">IP: '+escHtmlA(e.ip)+' | Session: '+escHtmlA(e.session_id||'—')+'</div>';
    if (e.page)      details += '<div style="font-size:14px;color:var(--text2);">Page: '+escHtmlA(e.page)+'</div>';
    if (e.user_agent)details += '<div style="font-size:15px;color:var(--text2);word-break:break-all;opacity:.7">UA: '+escHtmlA(e.user_agent.substring(0,120))+'</div>';

    rows += '<div style="border-left:3px solid '+sevColor+';padding:8px 12px;margin-bottom:4px;border-radius:0 6px 6px 0;background:rgba(255,255,255,.02)">' +
      '<div style="display:flex;align-items:flex-start;gap:10px">' +
      '<span style="font-size:14px;flex-shrink:0;margin-top:1px">'+catIcon+'</span>' +
      '<div style="flex:1;min-width:0">' +
      '<span style="font-weight:700;font-size:15px;color:'+sevColor+'">'+action+'</span>'+adminBy +
      details + '</div>' +
      '<div style="text-align:right;flex-shrink:0;min-width:90px">' +
      '<div style="font-size:14px;font-weight:700">'+escHtmlA(who)+'</div>' +
      '<div style="font-size:14px;color:var(--text2)">'+time+'</div>' +
      '<div style="font-size:15px;color:'+sevColor+';text-transform:uppercase;letter-spacing:.5px">'+e.severity+'</div>' +
      '</div></div></div>';
  }

  el.innerHTML = '<div style="padding:4px 0">'+rows+'</div>';

  // Pagination
  if (pgEl && pages > 1) {
    let pg = '';
    if (_histPage > 1) pg += '<button onclick="loadHistory('+(_histPage-1)+')" class="btn btn-outline" style="padding:6px 14px;font-size:14px">← Prev</button>';
    const start2 = Math.max(1, _histPage-2);
    const end2   = Math.min(pages, _histPage+2);
    for (let p = start2; p <= end2; p++) {
      pg += '<button onclick="loadHistory('+p+')" class="btn '+(p===_histPage?'btn-gold':'btn-outline')+'" style="padding:6px 12px;font-size:14px">'+p+'</button>';
    }
    if (_histPage < pages) pg += '<button onclick="loadHistory('+(_histPage+1)+')" class="btn btn-outline" style="padding:6px 14px;font-size:14px">Next →</button>';
    pg += '<span style="font-size:14px;color:var(--text2);align-self:center">Page '+_histPage+' of '+pages+'</span>';
    pgEl.innerHTML = pg;
  }
}

async function exportHistory() {
  const category = document.getElementById('hist-category')?.value || '';
  const severity = document.getElementById('hist-severity')?.value || '';
  const search   = document.getElementById('hist-search')?.value.trim() || '';
  const date     = document.getElementById('hist-date')?.value || '';
  window.open('/api/admin.php?action=activity_log_csv&category='+encodeURIComponent(category)+'&severity='+encodeURIComponent(severity)+'&search='+encodeURIComponent(search)+'&date='+encodeURIComponent(date));
}

// ─── TOAST ─────────────────────────────────────────────────
function toast(msg,type='ok'){const el=document.getElementById('toast');el.textContent=msg;el.className='show '+type;setTimeout(()=>el.className='',3000);}

// ─── ADMIN GAMER ALIASES ──────────────────────────────────
async function gmLoadPayout(uid) {
  const el = document.getElementById('gm-payout-list');
  const d  = await apiFetch('payout_methods_get&user_id=' + uid);
  if (!d.success || !d.methods.length) {
    el.innerHTML = '<div class="gm-empty">No payout methods saved by this player.</div>';
    return;
  }
  const ICONS  = { venmo:'💙', cashapp:'💚', zelle:'💜', chime:'🟢', bank:'🏦', other:'💰' };
  const LABELS = { venmo:'Venmo', cashapp:'Cash App', zelle:'Zelle', chime:'Chime', bank:'Bank Transfer', other:'Other' };
  el.innerHTML = d.methods.map(m => `
    <div style="display:flex;align-items:center;gap:12px;padding:12px;background:${parseInt(m.is_default)?'rgba(0,229,255,.07)':'var(--bg2)'};border:1px solid ${parseInt(m.is_default)?'rgba(0,229,255,.25)':'var(--border)'};border-radius:8px;margin-bottom:8px">
      <span style="font-size:24px">${ICONS[m.method_type]||'💰'}</span>
      <div style="flex:1">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px">${escHtmlA(m.label)}
          ${parseInt(m.is_default)?'<span style="font-size:14px;color:var(--cyan);border:1px solid rgba(0,229,255,.2);border-radius:4px;padding:2px 6px;margin-left:6px">DEFAULT</span>':''}
        </div>
        <div style="font-size:14px;color:var(--text2)">${LABELS[m.method_type]||m.method_type} · ${escHtmlA(m.account_handle)}</div>
      </div>
    </div>`).join('');
}

async function gmLoadPlatformAccounts(uid) {
  const el = document.getElementById('gm-platforms-list');
  const d  = await apiFetch('platform_accounts_user&user_id=' + uid);
  if (!d.success || !d.accounts.length) {
    el.innerHTML = '<div class="gm-empty">No platform account requests for this player.</div>';
    return;
  }
  const STATUS = { pending:'⏳ Pending', approved:'✅ Active', denied:'❌ Denied', deleted:'🗑 Deleted' };
  const SCLS   = { pending:'ac-pending', approved:'ac-completed', denied:'ac-failed', deleted:'ac-failed' };
  el.innerHTML = d.accounts.map(a => `
    <div style="border:1px solid var(--border);border-radius:8px;padding:12px;margin-bottom:8px">
      <div style="display:flex;align-items:center;gap:10px;margin-bottom:${a.status==='approved'?'10':'0'}px">
        <div style="font-size:20px">${a.color?`<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:${a.color}"></span>`:'🎮'}</div>
        <div style="flex:1">
          <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px">${escHtmlA(a.display_name||a.platform_slug)}</div>
          <span class="activity-status ${SCLS[a.status]||'ac-pending'}">${STATUS[a.status]||a.status}</span>
        </div>
        ${a.status==='approved'?`<button onclick="openPaUpdateModal(${a.id},'${escAttr(GM.current?.alias||'')}','${escAttr(a.display_name||'')}','${escAttr(a.provided_username||'')}','${escAttr(a.provided_password||'')}')" style="background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.18);color:var(--cyan);border-radius:6px;padding:5px 10px;font-size:15px;font-weight:700;cursor:pointer">✏️ Update</button>`:
        a.status==='pending'?`<button onclick="openPaModal(${a.id},'${escAttr(GM.current?.alias||'')}','${escAttr(a.display_name||'')}')" class="btn btn-green" style="padding:5px 12px;font-size:15px">✅ Approve</button>`:''}
      </div>
      ${a.status==='approved'?`<div style="background:rgba(0,229,255,.05);border:1px solid rgba(0,229,255,.12);border-radius:6px;padding:8px 10px;font-size:14px">
        <div><span style="color:var(--text2)">Username:</span> <strong>${escHtmlA(a.provided_username||'—')}</strong></div>
        <div><span style="color:var(--text2)">Password:</span> <strong style="color:var(--gold)">${escHtmlA(a.provided_password||'—')}</strong></div>
        ${a.player_url?`<a href="${escHtmlA(a.player_url)}" target="_blank" style="color:var(--cyan);font-size:15px">↗ Open platform</a>`:''}
      </div>`:''}
    </div>`).join('');
}
async function gmLoadAliases(uid) {
  const el = document.getElementById('gm-aliases-list');
  const [aliasRes, platRes] = await Promise.all([
    apiFetch('game_aliases_get&user_id=' + uid),
    fetch('/api/platforms.php?action=list').then(r=>r.json())
  ]);
  const aliases   = (aliasRes.success ? aliasRes.aliases : {}) || {};
  const platforms = platRes.success ? platRes.platforms : [];
  if (!platforms.length) { el.innerHTML = '<div class="gm-empty">No games configured.</div>'; return; }
  el.innerHTML = platforms.map(p => `
    <div style="display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid var(--border)">
      <div style="width:10px;height:10px;border-radius:50%;background:${p.color};box-shadow:0 0 8px ${p.color};flex-shrink:0"></div>
      <div style="flex:1;min-width:0">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text);margin-bottom:5px">${escHtmlA(p.name)}</div>
        <input class="fi-sm" id="gm-alias-${p.id}" type="text" maxlength="100"
          value="${escHtmlA(aliases[p.id]||'')}"
          placeholder="No alias set..."
          style="width:100%;padding:8px 12px;font-size:15px">
      </div>
    </div>`).join('') + '<div style="height:1px"></div>';
}

async function gmSaveAllAliases() {
  if (!GM.current) return;
  const al = document.getElementById('gm-aliases-alert');
  const aliases = {};
  document.querySelectorAll('[id^="gm-alias-"]').forEach(el => {
    const slug = el.id.replace('gm-alias-', '');
    aliases[slug] = el.value.trim();
  });
  const d = await apiFetch('game_aliases_save_all', 'POST', { user_id: GM.current.id, aliases });
  if (d.success) { showAdminAlert(al, 'Aliases saved!', 'success'); toast('Aliases saved', 'ok'); }
  else showAdminAlert(al, d.error || 'Save failed', 'error');
}
async function loadGamerBilling(uid) {
  const d = await apiFetch('billing_get&user_id=' + uid);
  const noCard  = document.getElementById('gm-billing-no-card');
  const cardDiv = document.getElementById('gm-billing-card-display');
  const cardEl  = document.getElementById('gm-billing-card');

  if (d.success && d.billing) {
    const b = d.billing;
    // Fill form
    ['first','last','email','address','city','state','zip'].forEach(f => {
      const el = document.getElementById('gm-b-'+f);
      if (el) el.value = b[f==='first'?'first_name':f==='last'?'last_name':f] || '';
    });
    // Show card info
    if (b.card_last4) {
      cardEl.innerHTML = `
        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
          <span style="font-family:'Exo 2',sans-serif;font-weight:900;font-size:16px;color:#fff;letter-spacing:2px">${escHtmlA(b.card_brand||'CARD')}</span>
          <span style="font-size:20px">💳</span>
        </div>
        <div style="font-family:'Courier New',monospace;font-size:16px;color:#fff;letter-spacing:4px;margin-bottom:16px">···· ···· ···· ${escHtmlA(b.card_last4)}</div>
        <div style="display:flex;justify-content:space-between;color:#fff">
          <div><div style="font-size:15px;color:rgba(255,255,255,.5);margin-bottom:2px">CARD HOLDER</div><div style="font-weight:700">${escHtmlA([b.first_name,b.last_name].filter(Boolean).join(' '))||'—'}</div></div>
          <div style="text-align:right"><div style="font-size:15px;color:rgba(255,255,255,.5);margin-bottom:2px">EXPIRES</div><div style="font-weight:700">${b.card_exp_month&&b.card_exp_year?b.card_exp_month+'/'+b.card_exp_year.slice(-2):'—'}</div></div>
        </div>`;
      cardDiv.style.display = 'block';
      noCard.style.display  = 'none';
    } else {
      cardDiv.style.display = 'none';
      noCard.style.display  = 'block';
    }
  } else {
    cardDiv.style.display = 'none';
    noCard.style.display  = 'block';
  }
}

async function gmSaveBilling() {
  if (!GM.current) return;
  const al = document.getElementById('gm-billing-alert');
  const data = {
    user_id:    GM.current.id,
    first_name: document.getElementById('gm-b-first')?.value.trim()   || '',
    last_name:  document.getElementById('gm-b-last')?.value.trim()    || '',
    email:      document.getElementById('gm-b-email')?.value.trim()   || '',
    address:    document.getElementById('gm-b-address')?.value.trim() || '',
    city:       document.getElementById('gm-b-city')?.value.trim()    || '',
    state:      (document.getElementById('gm-b-state')?.value.trim()  || '').toUpperCase(),
    zip:        document.getElementById('gm-b-zip')?.value.trim()     || '',
  };
  const d = await apiFetch('billing_save','POST', data);
  if (d.success) { toast('Billing info saved','ok'); showAdminAlert(al,'Billing saved!','success'); }
  else toast(d.error||'Error','err');
}

async function gmClearCard() {
  if (!GM.current || !confirm('Remove saved card info for this player?')) return;
  const d = await apiFetch('billing_clear_card','POST',{user_id:GM.current.id});
  if (d.success) { toast('Card removed','ok'); loadGamerBilling(GM.current.id); }
  else toast('Error','err');
}

async function gmClearAllBilling() {
  if (!GM.current || !confirm('Clear ALL billing info for this player? Cannot be undone.')) return;
  const d = await apiFetch('billing_clear_all','POST',{user_id:GM.current.id});
  if (d.success) { toast('Billing cleared','ok'); loadGamerBilling(GM.current.id); }
  else toast('Error','err');
}

// ─── PAYMENT SETTINGS ─────────────────────────────────────
const PMT_ICONS = { venmo:'💙', chime:'🟢', cashapp:'💚', zelle:'💜' };

async function loadPaymentSettings() {
  const d  = await apiFetch('payment_settings_list');
  const el = document.getElementById('payment-methods-list');
  if (!d.success) { el.innerHTML = '<div class="empty">Failed to load.</div>'; return; }
  // Sort: card first, then by sort_order
  const methods = [...d.methods].sort((a,b) => a.method_key==='card'?-1:b.method_key==='card'?1:a.sort_order-b.sort_order);
  el.innerHTML = methods.map(m => {
    const isCard  = m.method_key === 'card';
    const enabled = parseInt(m.is_enabled);
    const icon    = PMT_ICONS[m.method_key] || '💰';
    const bg      = enabled ? 'var(--green)' : 'rgba(255,255,255,.15)';
    const knobL   = enabled ? '22px' : '2px';
    const clr     = enabled ? 'var(--green)' : 'var(--red)';

    const fields = isCard
      ? '<div style="padding:10px 14px;background:rgba(0,229,255,.05);border-radius:8px;font-size:14px;color:var(--text2)">'+
        'Card payments run through <strong style="color:var(--cyan)">Square</strong>. When enabled, players can pay by credit or debit card. Your Square account must be active and connected.'+
        '<a href="https://squareup.com/dashboard" target="_blank" style="color:var(--cyan);display:block;margin-top:6px">Open Square Dashboard →</a></div>'
      : '<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px">'+
        '<div><label class="gm-edit-label">Display Name</label>'+
        '<input class="fi-sm" id="pmt-label-'+m.id+'" type="text" value="'+escHtmlA(m.label)+'" style="width:100%;padding:9px 12px"></div>'+
        '<div><label class="gm-edit-label">Handle / Address</label>'+
        '<input class="fi-sm" id="pmt-handle-'+m.id+'" type="text" value="'+escHtmlA(m.handle||'')+'" placeholder="@YourHandle" style="width:100%;padding:9px 12px"></div></div>'+
        '<div style="margin-bottom:10px"><label class="gm-edit-label">Instructions (optional)</label>'+
        '<input class="fi-sm" id="pmt-instructions-'+m.id+'" type="text" value="'+escHtmlA(m.instructions||'')+'" placeholder="Shown to player at checkout" style="width:100%;padding:9px 12px"></div>'+
        '<button class="btn btn-gold" style="width:100%" onclick="savePaymentMethod('+m.id+')">Save</button>';

    return '<div class="card" style="margin-bottom:12px;'+(isCard?'border-color:rgba(0,229,255,.25)':'')+'" id="pmt-card-'+m.id+'">'+
      '<div style="display:flex;align-items:center;gap:12px;margin-bottom:12px">'+
      '<div style="font-size:26px">'+icon+'</div>'+
      '<div style="flex:1"><div style="font-family:\'Exo 2\',sans-serif;font-weight:700;font-size:15px">'+escHtmlA(m.label)+'</div>'+
      '<div style="font-size:15px;color:var(--text2);margin-top:1px">'+(isCard?'Square Card Processing':'Manual payment'+(m.handle?' · '+escHtmlA(m.handle):''))+'</div></div>'+
      '<label style="display:flex;align-items:center;gap:8px;cursor:pointer">'+
      '<span style="font-size:14px;color:'+clr+'" id="pmt-status-'+m.id+'">'+(enabled?'Enabled':'Disabled')+'</span>'+
      '<div onclick="togglePaymentMethod('+m.id+','+m.is_enabled+')" style="width:44px;height:24px;border-radius:12px;background:'+bg+';position:relative;cursor:pointer;transition:background .2s;flex-shrink:0" id="pmt-toggle-'+m.id+'">'+
      '<div style="position:absolute;top:2px;left:'+knobL+';width:20px;height:20px;border-radius:50%;background:#fff;transition:left .2s" id="pmt-knob-'+m.id+'"></div></div>'+
      '</label></div>'+
      fields+'</div>';
  }).join('');
  window._pmtData = d.methods;
}

async function togglePaymentMethod(id, currentEnabled) {
  const newEnabled = parseInt(currentEnabled) ? 0 : 1;
  const d = await apiFetch('payment_settings_update','POST',{
    id, is_enabled: newEnabled,
    label: document.getElementById('pmt-label-'+id)?.value || '',
    handle: document.getElementById('pmt-handle-'+id)?.value || '',
    instructions: document.getElementById('pmt-instructions-'+id)?.value || '',
    sort_order: 0
  });
  if (d.success) {
    // Update toggle UI
    const toggle = document.getElementById('pmt-toggle-'+id);
    const knob   = document.getElementById('pmt-knob-'+id);
    const status = document.getElementById('pmt-status-'+id);
    if (toggle) toggle.style.background = newEnabled ? 'var(--green)' : 'rgba(255,255,255,.15)';
    if (knob)   knob.style.left = newEnabled ? '22px' : '2px';
    if (status) { status.textContent = newEnabled ? 'Enabled' : 'Disabled'; status.style.color = newEnabled ? 'var(--green)' : 'var(--red)'; }
    // Update onclick for next toggle
    const toggleEl = document.getElementById('pmt-toggle-'+id)?.parentElement;
    if (toggleEl) toggleEl.setAttribute('onclick', `togglePaymentMethod(${id},${newEnabled})`);
    toast(newEnabled ? 'Payment method enabled' : 'Payment method disabled', 'ok');
  } else toast(d.error||'Error','err');
}

async function savePaymentMethod(id) {
  const d = await apiFetch('payment_settings_update','POST',{
    id,
    label:        document.getElementById('pmt-label-'+id)?.value.trim() || '',
    handle:       document.getElementById('pmt-handle-'+id)?.value.trim() || '',
    instructions: document.getElementById('pmt-instructions-'+id)?.value.trim() || '',
    is_enabled:   window._pmtData?.find(m=>m.id==id)?.is_enabled ?? 1,
    sort_order:   window._pmtData?.find(m=>m.id==id)?.sort_order ?? 0,
  });
  if (d.success) toast('Saved!','ok');
  else toast(d.error||'Save failed','err');
}


// PAYOUT SETTINGS
async function loadPayoutSettings() {
  const el = document.getElementById('payout-settings-list');
  if (!el) return;
  const d = await fetch('/api/payout_process.php?action=list_settings').then(r=>r.json());
  if (!d.success || !d.settings.length) { el.innerHTML='<div class="empty">No payout settings.</div>'; return; }
  window._payoutSettings = d.settings;
  const icons = {venmo:'Venmo',cashapp:'Cash App',zelle:'Zelle',chime:'Chime',square_gift:'Square Gift Card'};
  el.innerHTML = d.settings.map(s => {
    const isGC = s.method_type === 'square_gift_card';
    const enabled = parseInt(s.is_enabled);
    return '<div class="card" style="margin-bottom:12px;' + (isGC?'border-color:rgba(0,229,255,.3)':'') + '">' +
      '<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">' +
      '<div style="flex:1"><div style="font-family:\'Exo 2\',sans-serif;font-weight:700;font-size:14px">' + escHtmlA(s.label) + '</div>' +
      '<div style="font-size:15px;color:' + (isGC?'var(--cyan)':'var(--text2)') + '">' + (isGC?'Real-time via Square':'Manual — send outside app') + '</div></div>' +
      '<label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:14px;font-weight:700">' +
      '<input type="checkbox" ' + (enabled?'checked':'') + ' onchange="togglePayoutSetting(' + s.id + ',this.checked)" style="width:16px;height:16px;accent-color:var(--green)"> ' +
      (enabled?'<span style="color:var(--green)">Enabled</span>':'<span style="color:var(--text2)">Disabled</span>') + '</label></div>' +
      (isGC ? '<div style="font-size:14px;color:var(--text2);padding:10px;background:rgba(0,229,255,.05);border-radius:8px">Creates a Square digital gift card loaded with the cashout amount. Player redeems anywhere Square is accepted. No handle needed.</div>' :
        '<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px">' +
        '<div><label class="gm-edit-label">Your Handle</label><input class="fi-sm" type="text" id="ps-handle-' + s.id + '" value="' + escHtmlA(s.handle||'') + '" placeholder="@handle" style="width:100%;padding:8px 10px"></div>' +
        '<div><label class="gm-edit-label">Sort</label><input class="fi-sm" type="number" id="ps-sort-' + s.id + '" value="' + s.sort_order + '" style="width:100%;padding:8px 10px"></div></div>' +
        '<div style="margin-bottom:10px"><label class="gm-edit-label">Instructions</label><input class="fi-sm" type="text" id="ps-instr-' + s.id + '" value="' + escHtmlA(s.instructions||'') + '" placeholder="Steps to send" style="width:100%;padding:8px 10px"></div>' +
        '<button class="btn btn-gold" onclick="savePayoutSetting(' + s.id + ')" style="font-size:14px;padding:8px 16px">Save</button>') +
      '</div>';
  }).join('');
}
async function togglePayoutSetting(id, enabled) {
  await fetch('/api/payout_process.php?action=update_setting',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id,is_enabled:enabled?1:0})}).then(r=>r.json());
}
async function savePayoutSetting(id) {
  const d = await fetch('/api/payout_process.php?action=update_setting',{method:'POST',headers:{'Content-Type':'application/json'},
    body:JSON.stringify({id,handle:document.getElementById('ps-handle-'+id)?.value.trim(),instructions:document.getElementById('ps-instr-'+id)?.value.trim(),sort_order:parseInt(document.getElementById('ps-sort-'+id)?.value)||0,is_enabled:1})}).then(r=>r.json());
  if (d.success) toast('Saved','ok'); else toast('Error','err');
}

// PROCESS PAYOUT MODAL
let PPM = {cashoutId:null,cashout:null,settings:[]};
async function openPayoutModal(cashoutId) {
  PPM.cashoutId=cashoutId;
  const modal=document.getElementById('process-payout-modal');
  modal.style.display='flex';
  document.getElementById('ppm-alert').className='alert';
  document.getElementById('ppm-note').value='';
  document.getElementById('ppm-method-detail').innerHTML='';
  const [dr,sr]=await Promise.all([
    fetch('/api/payout_process.php?action=cashout_detail&id='+cashoutId).then(r=>r.json()),
    fetch('/api/payout_process.php?action=list_settings').then(r=>r.json()),
  ]);
  if (!dr.success){toast('Load failed','err');closePayoutModal();return;}
  PPM.cashout=dr.cashout;
  PPM.settings=(sr.settings||[]).filter(s=>parseInt(s.is_enabled));
  const c=PPM.cashout;
  const amt=parseFloat(c.tokens).toFixed(2);
  document.getElementById('ppm-player-info').innerHTML=
    '<div style="display:flex;align-items:center;justify-content:space-between;gap:12px">'+
    '<div><div style="font-family:\'Exo 2\',sans-serif;font-weight:700;font-size:16px">'+escHtmlA(c.alias||c.username)+'</div>'+
    '<div style="font-size:14px;color:var(--text2)">@'+escHtmlA(c.username)+' | '+escHtmlA(c.email||'')+'</div>'+
    '<div style="font-size:14px;color:var(--text2)">'+pname(c.platform_id)+' | '+escHtmlA(c.alias||'')+'</div></div>'+
    '<div style="text-align:right"><div style="font-family:\'Exo 2\',sans-serif;font-weight:900;font-size:28px;color:var(--gold)">'+c.tokens+' Tokens</div>'+
    '<div style="font-size:14px;font-weight:700;color:var(--green)">$'+amt+'</div></div></div>';
  const spm=document.getElementById('ppm-saved-method');
  const ph=c.saved_payout_handle||c.payout_handle;
  const pt=c.saved_payout_label||c.payout_method_type||'';
  spm.innerHTML=ph?
    '<div style="background:rgba(0,229,255,.06);border:1px solid rgba(0,229,255,.15);border-radius:8px;padding:10px 14px">'+
    '<div style="font-size:15px;font-weight:700;color:var(--text2);margin-bottom:4px">PLAYER PAYOUT METHOD</div>'+
    '<div style="font-size:14px;font-weight:700">'+escHtmlA(pt)+' | <span style="color:var(--cyan)">'+escHtmlA(ph)+'</span></div></div>':
    '<div style="font-size:14px;color:var(--red)">No payout method on file for this player</div>';
  const sel=document.getElementById('ppm-method-select');
  sel.innerHTML='<option value="">-- Select method --</option>'+
    PPM.settings.map(s=>'<option value="'+escHtmlA(s.method_key)+'" data-type="'+s.method_type+'">'+
      (s.method_type==='square_gift_card'?'[INSTANT] ':'')+escHtmlA(s.label)+'</option>').join('');
}
function closePayoutModal(){
  document.getElementById('process-payout-modal').style.display='none';
  PPM={cashoutId:null,cashout:null,settings:[]};
}
function onPayoutMethodChange(){
  const key=document.getElementById('ppm-method-select').value;
  const detail=document.getElementById('ppm-method-detail');
  const btn=document.getElementById('ppm-submit-btn');
  if (!key){detail.innerHTML='';btn.textContent='Process Payout';return;}
  const s=PPM.settings.find(x=>x.method_key===key);
  if (!s) return;
  const amt=parseFloat(PPM.cashout?.tokens||0).toFixed(2);
  const c=PPM.cashout;
  if (s.method_type==='square_gift_card'){
    detail.innerHTML='<div style="background:rgba(0,229,255,.07);border:1px solid rgba(0,229,255,.2);border-radius:10px;padding:14px">'+
      '<div style="font-size:15px;font-weight:700;color:var(--cyan);margin-bottom:8px">INSTANT Square Gift Card</div>'+
      '<div style="font-size:15px">Creates a digital gift card for <strong style="color:var(--gold)">$'+amt+'</strong> via your Square account instantly. Card number shows here — send to player via chat.</div></div>';
    btn.textContent='Process via Square Gift Card';
  } else {
    const ph=c?.payout_handle||c?.saved_payout_handle||'(none on file)';
    detail.innerHTML='<div style="background:rgba(240,192,64,.07);border:1px solid rgba(240,192,64,.2);border-radius:10px;padding:14px">'+
      '<div style="font-size:15px;font-weight:700;color:var(--gold);margin-bottom:8px">Manual Processing</div>'+
      '<div style="font-size:15px;line-height:2.0">'+
      '1. Open <strong>'+escHtmlA(s.label)+'</strong><br>'+
      '2. Send <strong style="color:var(--gold)">$'+amt+'</strong> to: <span style="color:var(--cyan)"><strong>'+escHtmlA(ph)+'</strong></span><br>'+
      (s.instructions?'3. '+escHtmlA(s.instructions):'')+'</div>'+
      (s.handle?'<div style="font-size:14px;color:var(--text2);margin-top:8px">Your handle: <strong>'+escHtmlA(s.handle)+'</strong></div>':'')+'</div>';
    btn.textContent='Mark as Sent (Manual)';
  }
}
async function submitPayout(){
  const key=document.getElementById('ppm-method-select').value;
  const note=document.getElementById('ppm-note').value.trim();
  const al=document.getElementById('ppm-alert');
  al.className='alert';
  if (!key){showAdminAlert(al,'Select a payout method.','error');return;}
  const s=PPM.settings.find(x=>x.method_key===key);
  if (!s) return;
  const isGC=s.method_type==='square_gift_card';
  const amt=parseFloat(PPM.cashout?.tokens||0).toFixed(2);
  if (!confirm(isGC?'Create Square gift card for $'+amt+'?':'Confirm you have sent $'+amt+' via '+s.label+'. Mark as sent?')) return;
  const btn=document.getElementById('ppm-submit-btn');
  btn.disabled=true; btn.textContent='Processing...';
  try {
    const res=await fetch('/api/payout_process.php?action=process_payout',{method:'POST',headers:{'Content-Type':'application/json'},
      body:JSON.stringify({cashout_id:PPM.cashoutId,payout_method_key:key,payout_type:s.method_type,note})}).then(r=>r.json());
    if (res.success){
      showAdminAlert(al,isGC?'Gift card created!':'Marked as sent!','success');
      if (res.gift_card_gan){
        al.innerHTML+='<div style="margin-top:10px;font-family:monospace;font-size:16px;color:var(--gold);word-break:break-all;user-select:all">Card #: <strong>'+res.gift_card_gan+'</strong></div>'+
          '<div style="font-size:14px;color:var(--text2);margin-top:4px">Copy and send this card number to the player. Balance: $'+(res.gift_card_balance/100).toFixed(2)+'</div>';
      }
      toast(isGC?'Gift card sent!':'Marked sent','ok');
      loadCashouts('pending');loadDashCashouts();loadStats();
      if (!isGC) setTimeout(closePayoutModal,1500);
    } else {
      showAdminAlert(al,res.error||'Processing failed','error');
    }
  } catch(e){showAdminAlert(al,'Network error','error');}
  finally{btn.disabled=false;btn.textContent=isGC?'Process via Square Gift Card':'Mark as Sent (Manual)';}
}

// ─── REFERRAL MANAGEMENT ──────────────────────────────────
let _refTiers = [];
let _refListReqId = 0;

function showRefSection(section) {
  document.getElementById('ref-admin-list').style.display     = section==='list'?'block':'none';
  document.getElementById('ref-tiers-section').style.display  = section==='tiers'?'block':'none';
  document.getElementById('ref-shares-section').style.display = section==='shares'?'block':'none';
  if (section==='tiers')  loadAdminTiers();
  if (section==='shares') loadAdminShares('pending', document.querySelector('#ref-shares-section .ftab'));
}

async function loadAdminReferrals(status, btn) {
  const reqId = ++_refListReqId;
  document.getElementById('ref-admin-list').style.display='block';
  document.getElementById('ref-tiers-section').style.display='none';
  document.getElementById('ref-shares-section').style.display='none';
  if (btn) { document.querySelectorAll('#section-referrals .ftab').forEach(b=>b.classList.remove('active')); btn.classList.add('active'); }
  const el = document.getElementById('ref-admin-list');
  el.innerHTML = '<div style="padding:16px;text-align:center;color:var(--text2)">Loading...</div>';
  const d = await fetch('/api/referrals.php?action=admin_list&status='+status).then(r=>r.json());
  if (reqId !== _refListReqId) return; // discard stale response
  if (!d.success||!d.referrals.length) { el.innerHTML='<div class="empty" style="padding:24px;text-align:center">No '+status+' referrals.</div>'; return; }
  el.innerHTML = d.referrals.map(r => buildRefCard(r, status)).join('');
}

function buildRefCard(r, status) {
  const note    = r.admin_note ? '<div style="font-size:15px;color:var(--text2)">'+escHtmlA(r.admin_note)+'</div>' : '';
  const awarded = r.tokens_awarded>0 ? '<div style="font-size:15px;color:var(--green)">+'+r.tokens_awarded+' tokens awarded</div>' : '';
  const actions = status==='pending' ? [
    '<input class="fi-sm" type="text" id="rn-'+r.id+'" placeholder="Note" style="width:100%;padding:7px 10px;font-size:14px;margin-bottom:6px">',
    '<button class="btn btn-green" style="width:100%;font-size:14px;padding:7px;margin-bottom:4px" onclick="resolveReferral('+r.id+', \'verified\')">Verify + Award</button>',
    '<button class="btn btn-red" style="width:100%;font-size:14px;padding:7px" onclick="resolveReferral('+r.id+', \'denied\')">Deny</button>',
  ].join('') : '';
  return '<div class="card" style="margin-bottom:10px"><div style="display:flex;align-items:flex-start;gap:12px">'+
    '<div style="flex:1"><div style="font-size:15px"><strong>'+escHtmlA(r.referrer_alias||r.referrer_name)+'</strong> referred <strong>'+escHtmlA(r.referred_alias||r.referred_name)+'</strong></div>'+
    '<div style="font-size:15px;color:var(--text2);margin-top:3px">'+(r.created_at||'').substring(0,16)+' | Email verified: '+(r.email_verified?'Yes':'No')+'</div>'+
    awarded+note+'</div>'+
    '<div style="flex-shrink:0;min-width:140px">'+actions+'</div></div></div>';
}

async function resolveReferral(id, status) {
  const note = document.getElementById('rn-'+id)?.value.trim() || '';
  if (!confirm(status==='verified' ? 'Verify and award tokens?' : 'Deny this referral?')) return;
  const d = await fetch('/api/referrals.php?action=resolve_referral', {
    method:'POST', headers:{'Content-Type':'application/json'},
    body: JSON.stringify({id, status, note})
  }).then(r=>r.json());
  if (d.success) {
    toast(status==='verified' ? 'Verified! '+d.tokens_awarded+' tokens awarded' : 'Denied', status==='verified'?'ok':'err');
    // Reload the pending tab (items resolved out of pending); active tab indicator stays correct
    const pendingBtn = document.querySelector('#section-referrals .ftab');
    loadAdminReferrals('pending', pendingBtn);
    loadStats();
  } else toast(d.error||'Error','err');
}

async function loadAdminTiers() {
  const el = document.getElementById('ref-tiers-admin-list');
  const d  = await fetch('/api/referrals.php?action=all_tiers').then(r=>r.json());
  if (!d.success||!d.tiers.length) { el.innerHTML='<div class="empty" style="padding:20px;text-align:center">No tiers yet. Add one above.</div>'; return; }
  _refTiers = d.tiers;
  el.innerHTML = d.tiers.map(t => {
    const inactive = !parseInt(t.is_active) ? '<span style="font-size:14px;color:var(--red);margin-left:6px">INACTIVE</span>' : '';
    return '<div style="display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid var(--border)">'+
      '<div style="flex:1"><div style="font-family:\'Exo 2\',sans-serif;font-weight:700;font-size:14px">'+escHtmlA(t.name)+inactive+'</div>'+
      '<div style="font-size:14px;color:var(--text2)">Min '+t.min_referrals+' refs | '+t.tokens_per_ref+' tok/ref'+(t.bonus_tokens>0?' + '+t.bonus_tokens+' milestone bonus':'')+'</div></div>'+
      '<div style="display:flex;gap:6px">'+
      '<button data-tid="'+t.id+'" onclick="editRefTier(this.dataset.tid)" style="background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.2);color:var(--cyan);border-radius:6px;padding:6px 12px;font-size:14px;font-weight:700;cursor:pointer">Edit</button>'+
      '<button data-tid="'+t.id+'" data-tname="'+escHtmlA(t.name)+'" onclick="deleteRefTier(this.dataset.tid,this.dataset.tname)" style="background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:6px;padding:6px 12px;font-size:14px;font-weight:700;cursor:pointer">Del</button>'+
      '</div></div>';
  }).join('');
}

function editRefTier(id) {
  const t = _refTiers.find(x=>x.id==id); if (!t) return;
  document.getElementById('rt-id').value=t.id; document.getElementById('rt-name').value=t.name;
  document.getElementById('rt-min').value=t.min_referrals; document.getElementById('rt-per').value=t.tokens_per_ref;
  document.getElementById('rt-bonus').value=t.bonus_tokens; document.getElementById('rt-sort').value=t.sort_order;
  document.getElementById('rt-desc').value=t.description||''; document.getElementById('rt-active').value=t.is_active;
  document.getElementById('ref-tier-form-title').textContent = 'Editing: '+t.name;
}

function resetRefTierForm() {
  ['rt-id','rt-name','rt-desc'].forEach(id=>document.getElementById(id).value='');
  document.getElementById('rt-min').value=1; document.getElementById('rt-per').value=5;
  document.getElementById('rt-bonus').value=0; document.getElementById('rt-sort').value=0;
  document.getElementById('rt-active').value=1;
  document.getElementById('ref-tier-form-title').textContent='Add Referral Tier';
}

async function saveRefTier() {
  const al  = document.getElementById('ref-tier-alert');
  const id  = document.getElementById('rt-id').value;
  const data = {
    id:             id ? parseInt(id) : undefined,
    name:           document.getElementById('rt-name').value.trim(),
    min_referrals:  parseInt(document.getElementById('rt-min').value)||1,
    tokens_per_ref: parseFloat(document.getElementById('rt-per').value)||5,
    bonus_tokens:   parseFloat(document.getElementById('rt-bonus').value)||0,
    description:    document.getElementById('rt-desc').value.trim(),
    sort_order:     parseInt(document.getElementById('rt-sort').value)||0,
    is_active:      parseInt(document.getElementById('rt-active').value),
  };
  if (!data.name) { showAdminAlert(al,'Name is required.','error'); return; }
  const d = await fetch('/api/referrals.php?action='+(id?'tier_update':'tier_create'),{
    method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(data)
  }).then(r=>r.json());
  if (d.success) { showAdminAlert(al,id?'Updated!':'Created!','success'); resetRefTierForm(); loadAdminTiers(); toast('Saved','ok'); }
  else showAdminAlert(al,d.error||'Error','error');
}

async function deleteRefTier(id, name) {
  if (!confirm('Delete tier "'+name+'"?')) return;
  const d = await fetch('/api/referrals.php?action=tier_delete',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id})}).then(r=>r.json());
  if (d.success) { toast('Deleted','ok'); loadAdminTiers(); } else toast(d.error||'Error','err');
}

async function loadAdminShares(status, btn) {
  if (btn) { document.querySelectorAll('#ref-shares-section .ftab').forEach(b=>b.classList.remove('active')); btn.classList.add('active'); }
  const el = document.getElementById('ref-shares-admin-list');
  const d  = await fetch('/api/referrals.php?action=admin_shares&status='+status).then(r=>r.json());
  if (!d.success||!d.shares.length) { el.innerHTML='<div class="empty" style="padding:20px;text-align:center">No '+status+' shares.</div>'; return; }
  const verifyLabels = {
    code_found:         '✅ Code found in page',
    login_required:     '🔒 Login required',
    unreachable:        '⚠️ URL unreachable',
    not_found:          '❌ Code not in page',
    site_found_no_code: '⚠️ Site mentioned, code missing',
    invalid_url:        '❌ Invalid URL',
  };
  el.innerHTML = d.shares.map(s => {
    const autoTag    = parseInt(s.auto_verified) ? '<span style="font-size:12px;color:var(--green);margin-left:6px">⚡ auto-verified</span>' : '';
    const verifyNote = s.verify_result && !parseInt(s.auto_verified)
      ? '<div style="font-size:13px;color:var(--text2);margin-top:2px">Auto-check: '+(verifyLabels[s.verify_result]||s.verify_result)+'</div>' : '';
    const urlLink    = s.share_url
      ? '<div style="margin-top:4px"><a href="'+escHtmlA(s.share_url)+'" target="_blank" rel="noopener" style="color:var(--cyan);font-size:13px;word-break:break-all">🔗 '+escHtmlA(s.share_url.length>70?s.share_url.substring(0,70)+'…':s.share_url)+'</a></div>'
      : '<div style="font-size:13px;color:var(--text2);margin-top:2px;font-style:italic">No URL submitted</div>';
    const btns = status==='pending'
      ? '<div style="display:flex;gap:6px;margin-top:8px">'+
        '<button data-sid="'+s.id+'" onclick="resolveShare(this.dataset.sid,&quot;approved&quot;)" class="btn btn-green" style="font-size:14px;padding:7px 12px">Approve</button>'+
        '<button data-sid="'+s.id+'" onclick="resolveShare(this.dataset.sid,&quot;denied&quot;)" class="btn btn-red" style="font-size:14px;padding:7px 12px">Deny</button></div>' : '';
    return '<div class="card" style="margin-bottom:8px">'+
      '<div style="font-size:15px;font-weight:700">'+escHtmlA(s.alias||s.username)+' | <span style="color:var(--cyan)">'+escHtmlA(s.platform)+'</span>'+autoTag+'</div>'+
      '<div style="font-size:14px;color:var(--text2);margin-top:2px">'+(s.created_at||'').substring(0,16)+' | Bonus: '+s.bonus_tokens+' tokens</div>'+
      urlLink+verifyNote+btns+'</div>';
  }).join('');
}

async function resolveShare(id, status) {
  const d = await fetch('/api/referrals.php?action=resolve_share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id,status})}).then(r=>r.json());
  if (d.success) { toast(status==='approved'?'Approved! Tokens awarded':'Denied','ok'); loadAdminShares('pending'); }
  else toast(d.error||'Error','err');
}

// ─── PLATFORM ACCOUNTS ────────────────────────────────────
async function loadPlatformAccountRequests(status, btn) {
  if (btn) { document.querySelectorAll('#section-platform-accounts .ftab').forEach(b=>b.classList.remove('active')); btn.classList.add('active'); }
  const el = document.getElementById('pa-requests-list');
  el.innerHTML = '<div style="padding:16px;text-align:center;color:var(--text2)">Loading...</div>';
  const d = await apiFetch('platform_accounts_list&status='+status);
  if (!d.success||!d.accounts.length) { el.innerHTML='<div class="empty" style="padding:24px;text-align:center">No '+status+' requests.</div>'; return; }
  el.innerHTML = d.accounts.map(a => buildAdminPaCard(a, status==='pending')).join('');
}

async function gmLoadPlatformAccounts(uid) {
  const el = document.getElementById('gm-platform-accounts-list');
  const d  = await apiFetch('platform_accounts_list&user_id='+uid);
  if (!d.success||!d.accounts.length) { el.innerHTML='<div class="gm-empty">No platform account requests.</div>'; return; }
  el.innerHTML = d.accounts.map(a => buildAdminPaCard(a, true)).join('');
}

function buildAdminPaCard(a, showActions) {
  const statusLabel = { pending:'⏳ Pending', approved:'✅ Approved', denied:'❌ Denied', deleted:'🗑 Deleted' };
  const statusColor = { pending:'var(--gold)', approved:'var(--green)', denied:'var(--red)', deleted:'var(--text2)' };
  return '<div class="card" style="margin-bottom:12px">' +
    '<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:10px">' +
    '<div><div style="font-family:\'Exo 2\',sans-serif;font-weight:700;font-size:14px">' + escHtmlA(a.username||'?') + ' <span style="color:var(--text2)">· ' + escHtmlA(a.user_alias||'') + '</span></div>' +
    '<div style="font-size:14px;color:var(--cyan)">' + escHtmlA(a.platform_name||a.platform_slug) + '</div>' +
    '<div style="font-size:15px;color:var(--text2)">' + (a.requested_at||'').substring(0,16) + '</div></div>' +
    '<span style="font-size:15px;font-weight:700;color:' + (statusColor[a.status]||'var(--text2)') + ';border:1px solid currentColor;border-radius:6px;padding:3px 10px">' + (statusLabel[a.status]||a.status) + '</span></div>' +
    '<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px">' +
    '<div><label class="gm-edit-label">Username</label><input class="fi-sm" type="text" id="pa-uname-' + a.id + '" value="' + escHtmlA(a.platform_username||'') + '" placeholder="username" style="width:100%;padding:8px 10px"></div>' +
    '<div><label class="gm-edit-label">Password</label><input class="fi-sm" type="text" id="pa-pass-' + a.id + '" value="' + escHtmlA(a.platform_password||'') + '" placeholder="password" style="width:100%;padding:8px 10px"></div></div>' +
    '<div style="margin-bottom:10px"><label class="gm-edit-label">Note to Player</label>' +
    '<input class="fi-sm" type="text" id="pa-note-' + a.id + '" value="' + escHtmlA(a.admin_note||'') + '" placeholder="Optional note" style="width:100%;padding:8px 10px"></div>' +
    '<div style="display:flex;gap:8px">' +
    (a.status==='pending' ? '<button class="btn btn-green" onclick="resolvePlatformAccount('+a.id+',\'approved\')" style="flex:1;font-size:14px">Approve</button><button class="btn btn-red" onclick="resolvePlatformAccount('+a.id+',\'denied\')" style="font-size:14px;padding:8px 14px">Deny</button>' : '') +
    (a.status==='approved' ? '<button class="btn btn-gold" onclick="updatePlatformAccount('+a.id+')" style="flex:1;font-size:14px">Update Credentials</button>' : '') +
    '</div></div>';
}

async function resolvePlatformAccount(id, status) {
  const uname = document.getElementById('pa-uname-'+id)?.value.trim();
  const pass  = document.getElementById('pa-pass-'+id)?.value.trim();
  const note  = document.getElementById('pa-note-'+id)?.value.trim();
  if (status==='approved'&&!uname) { toast('Username required to approve','err'); return; }
  if (!confirm(status==='approved'?'Approve and send credentials to player?':'Deny this request?')) return;
  const d = await apiFetch('platform_account_resolve','POST',{id,status,platform_username:uname,platform_password:pass,admin_note:note});
  if (d.success) {
    toast(status==='approved'?'Approved!':'Denied','ok');
    loadPlatformAccountRequests('pending', document.querySelector('#section-platform-accounts .ftab'));
    if (GM.current) gmLoadPlatformAccounts(GM.current.id);
  } else toast(d.error||'Error','err');
}

async function updatePlatformAccount(id) {
  const d = await apiFetch('platform_account_update','POST',{
    id, platform_username: document.getElementById('pa-uname-'+id)?.value.trim(),
    platform_password: document.getElementById('pa-pass-'+id)?.value.trim(),
    admin_note: document.getElementById('pa-note-'+id)?.value.trim()
  });
  if (d.success) toast('Updated','ok'); else toast(d.error||'Error','err');
}

async function sendBroadcast() {
  const subject = document.getElementById('bc-subject')?.value.trim();
  const message = document.getElementById('bc-message')?.value.trim();
  const target  = document.getElementById('bc-target')?.value || 'all';
  const al      = document.getElementById('bc-alert');
  if (al) al.className = 'alert';

  if (!subject) { if(al) showAdminAlert(al,'Subject is required.','error'); return; }
  if (!message) { if(al) showAdminAlert(al,'Message is required.','error'); return; }

  const btn = document.querySelector('#section-broadcasts .btn-gold');
  if (btn) { btn.disabled = true; btn.textContent = 'Sending...'; }

  const d = await apiFetch('broadcast_send','POST',{ subject, message, target });

  if (btn) { btn.disabled = false; btn.textContent = '📢 SEND BROADCAST'; }

  if (d.success) {
    if (al) showAdminAlert(al, '✓ Broadcast sent to ' + (d.recipient_count||0) + ' players!', 'success');
    document.getElementById('bc-subject').value = '';
    document.getElementById('bc-message').value = '';
    setTimeout(() => { if(al){al.className='alert';al.textContent='';} }, 4000);
    loadBroadcasts();
  } else {
    if (al) showAdminAlert(al, d.error || 'Failed to send.', 'error');
  }
}

async function loadBroadcasts() {
  const el = document.getElementById('bc-list');
  if (!el) return;
  el.innerHTML = '<div style="padding:20px;text-align:center;color:var(--text2)">Loading broadcasts...</div>';
  let d;
  try { d = await apiFetch('broadcast_list'); } catch(e) {
    el.innerHTML = '<div class="empty" style="padding:24px;text-align:center;color:var(--red)">Failed to load broadcasts.</div>';
    return;
  }
  if (!d || !d.success) {
    el.innerHTML = '<div class="empty" style="padding:24px;text-align:center;color:var(--red)">' + (d?.error||'Error loading broadcasts') + '</div>';
    return;
  }
  if (!d.broadcasts || !d.broadcasts.length) {
    el.innerHTML = '<div class="empty" style="padding:24px;text-align:center;color:var(--text2)">No broadcasts sent yet.</div>';
    return;
  }
  const TGT = { all:'👥 All', verified:'✅ Verified', unverified:'⏳ Unverified', admins:'🔑 Admins' };
  el.innerHTML = d.broadcasts.map(b => {
    const readPct = b.total_players > 0 ? Math.round((b.read_count/b.total_players)*100) : 0;
    const dt = (b.sent_at||'').substring(0,16).replace('T',' ');
    return `<div class="card" style="margin-bottom:10px">
      <div style="display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap">
        <div style="flex:1;min-width:200px">
          <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:16px;color:var(--text);margin-bottom:4px">${escHtmlA(b.subject)}</div>
          <div style="font-size:14px;color:var(--text2);margin-bottom:8px;line-height:1.5">${escHtmlA(b.message.substring(0,120))}${b.message.length>120?'...':''}</div>
          <div style="display:flex;gap:10px;flex-wrap:wrap;font-size:13px;color:var(--text2)">
            <span style="color:var(--gold);font-weight:700">${TGT[b.target]||b.target}</span>
            <span>📅 ${dt}</span>
            <span>👤 ${escHtmlA(b.sender_name)}</span>
            <span style="color:var(--cyan)">👁 ${b.read_count}/${b.total_players} read (${readPct}%)</span>
            <span style="color:var(--purple)">💬 ${b.reply_count} ${b.reply_count==1?'reply':'replies'}</span>
          </div>
          <div style="margin-top:8px;background:rgba(255,255,255,.08);border-radius:4px;height:5px;width:200px;max-width:100%">
            <div style="height:5px;border-radius:4px;background:var(--cyan);width:${readPct}%"></div>
          </div>
        </div>
        <div style="display:flex;flex-direction:column;gap:6px;flex-shrink:0">
          <button onclick="editBroadcast(${b.id},'${escAttr(b.subject)}','${escAttr(b.message)}','${b.target}')"
            style="background:rgba(155,93,229,.1);border:1px solid rgba(155,93,229,.3);color:var(--purple);border-radius:6px;padding:7px 14px;font-size:13px;font-weight:700;cursor:pointer">✏️ Edit</button>
          <button onclick="resendBroadcast(${b.id},'${escAttr(b.subject)}')"
            style="background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.2);color:var(--cyan);border-radius:6px;padding:7px 14px;font-size:13px;font-weight:700;cursor:pointer">↩ Resend</button>
          <button onclick="deleteBroadcast(${b.id},'${escAttr(b.subject)}')"
            style="background:rgba(255,68,68,.07);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:6px;padding:7px 14px;font-size:13px;font-weight:700;cursor:pointer">🗑 Delete</button>
        </div>
      </div>
    </div>`;
  }).join('');
}

async function editBroadcast(id, subject, message, target) {
  const newSubject = prompt('Edit Subject:', subject);
  if (newSubject === null) return;
  const newMessage = prompt('Edit Message:', message);
  if (newMessage === null) return;
  const targets = ['all','verified','unverified','admins'];
  const labels  = ['All Players','Verified Only','Unverified Only','Admins Only'];
  const tIdx    = targets.indexOf(target);
  const newTarget = prompt('Send To (all/verified/unverified/admins):', target);
  if (!targets.includes(newTarget)) { alert('Invalid target. Use: all, verified, unverified, or admins'); return; }
  const d = await apiFetch('broadcast_edit','POST',{id, subject:newSubject, message:newMessage, target:newTarget});
  if (d.success) { toast('Broadcast updated','ok'); loadBroadcasts(); }
  else toast(d.error||'Failed to update','error');
}

async function resendBroadcast(id, subject) {
  if (!confirm('Resend "'+subject+'" to all recipients? This will mark it as unread for everyone.')) return;
  const d = await apiFetch('broadcast_resend','POST',{id});
  if (d.success) { toast('Resent to '+d.recipient_count+' players','ok'); loadBroadcasts(); }
  else toast(d.error||'Failed to resend','error');
}

async function openBcDrawer(id, subject) {
  bcCurrentId = id;
  document.getElementById('bc-drawer').style.display = 'block';
  document.getElementById('bc-drawer-title').textContent = '📢 ' + subject;
  document.getElementById('bc-drawer').scrollIntoView({behavior:'smooth'});
  switchBcTab('replies', document.getElementById('bc-tab-replies'));
}

function closeBcDrawer() {
  document.getElementById('bc-drawer').style.display = 'none';
  bcCurrentId = null;
}

function switchBcTab(tab, btn) {
  bcCurrentTab = tab;
  document.querySelectorAll('#bc-drawer .ftab').forEach(b=>b.classList.remove('active'));
  if (btn) btn.classList.add('active');
  if (tab === 'replies') loadBcReplies();
  else loadBcReads();
}

async function loadBcReplies() {
  if (!bcCurrentId) return;
  const el = document.getElementById('bc-drawer-content');
  el.innerHTML = '<div style="color:var(--text2);font-size:15px;text-align:center;padding:16px">Loading...</div>';
  const d = await apiFetch('broadcast_replies&broadcast_id=' + bcCurrentId);
  if (!d.success || !d.replies.length) {
    el.innerHTML = '<div style="color:var(--text2);font-size:15px;text-align:center;padding:16px">No replies yet.</div>';
    return;
  }
  el.innerHTML = d.replies.map(r => {
    const isAdm = parseInt(r.is_admin);
    return `<div style="display:flex;gap:10px;margin-bottom:12px">
      <div style="width:32px;height:32px;border-radius:50%;background:${isAdm?'linear-gradient(135deg,#f0c040,#d4a017)':'linear-gradient(135deg,#7b2fbe,#457b9d)'};display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;color:#fff;flex-shrink:0">${(r.username||'?').charAt(0).toUpperCase()}</div>
      <div style="flex:1;background:${isAdm?'rgba(240,192,64,.07)':'var(--bg3)'};border:1px solid ${isAdm?'rgba(240,192,64,.2)':'var(--border)'};border-radius:8px;padding:8px 12px">
        <div style="font-size:15px;font-weight:700;color:${isAdm?'var(--gold)':'var(--cyan)'};margin-bottom:4px">
          ${escHtmlA(r.username)}${isAdm?' 🔑 (Admin)':' · '+escHtmlA(r.alias)} <span style="color:var(--text2);font-weight:400">· ${(r.created_at||'').substring(0,16)}</span>
        </div>
        <div style="font-size:15px;color:var(--text)">${escHtmlA(r.message)}</div>
      </div>
    </div>`;
  }).join('');
}

async function loadBcReads() {
  if (!bcCurrentId) return;
  const el = document.getElementById('bc-drawer-content');
  el.innerHTML = '<div style="color:var(--text2);font-size:15px;text-align:center;padding:16px">Loading...</div>';
  const d = await apiFetch('broadcast_reads&broadcast_id=' + bcCurrentId);
  if (!d.success || !d.reads.length) {
    el.innerHTML = '<div style="color:var(--text2);font-size:15px;text-align:center;padding:16px">No reads yet.</div>';
    return;
  }
  el.innerHTML = `<div style="display:flex;flex-wrap:wrap;gap:8px">${d.reads.map(r=>`
    <div style="background:var(--bg3);border:1px solid var(--border);border-radius:8px;padding:6px 12px;font-size:14px">
      <span style="font-weight:700;color:var(--text)">${escHtmlA(r.username)}</span>
      <span style="color:var(--text2)"> · ${(r.read_at||'').substring(0,16)}</span>
    </div>`).join('')}</div>`;
}

async function adminBroadcastReply() {
  if (!bcCurrentId) return;
  const input = document.getElementById('bc-reply-input');
  const msg   = input.value.trim();
  if (!msg) return;
  input.value = '';
  const d = await apiFetch('broadcast_reply','POST',{broadcast_id:bcCurrentId, message:msg});
  if (d.success) { loadBcReplies(); loadBroadcasts(); }
  else toast(d.error||'Error','err');
}

async function deleteBroadcast(id, subject) {
  if (!confirm('Delete broadcast "' + subject + '"?\n\nThis will remove all replies and read receipts. Cannot be undone.')) return;
  const d = await apiFetch('broadcast_delete','POST',{id});
  if (d.success) { toast('Broadcast deleted','ok'); loadBroadcasts(); if (bcCurrentId===id) closeBcDrawer(); }
  else toast(d.error||'Error','err');
}

// ─── CASHOUT METHOD TYPES ─────────────────────────────────
async function loadCashoutMethods() {
  const d  = await apiFetch('cashout_methods_list');
  const el = document.getElementById('cmt-list');
  const ct = document.getElementById('cmt-count');
  if (!d.success) { el.innerHTML = '<div class="empty">Failed to load.</div>'; return; }
  const types = d.types || [];
  if (ct) ct.textContent = types.length + ' method' + (types.length !== 1 ? 's' : '');
  if (!types.length) { el.innerHTML = '<div class="empty" style="padding:24px;text-align:center">No methods yet. Add one above.</div>'; return; }
  window._cmtData = types;
  el.innerHTML = types.map(m => `
    <div class="game-row${!parseInt(m.is_active)?' inactive-overlay':''}">
      <div style="font-size:26px;flex-shrink:0">${escHtmlA(m.icon||'💰')}</div>
      <div class="game-info">
        <div class="game-name">${escHtmlA(m.label)}
          ${!parseInt(m.is_active)?'<span class="badge" style="background:rgba(255,68,68,.15);color:var(--red);font-size:15px;margin-left:6px">INACTIVE</span>':''}
        </div>
        <div class="game-slug">${escHtmlA(m.slug)}</div>
        ${m.description?`<div style="font-size:14px;color:var(--text2);margin-top:2px">${escHtmlA(m.description)}</div>`:''}
      </div>
      <div style="text-align:right;flex-shrink:0">
        <div style="font-size:15px;color:var(--text2);margin-bottom:6px">Order: ${m.sort_order}</div>
        <div class="game-actions">
          <button class="game-edit-btn" style="background:rgba(0,229,255,.1);color:var(--cyan);border:1px solid rgba(0,229,255,.2)" onclick="editCashoutMethod(${m.id})">✏️ Edit</button>
          <button class="game-edit-btn" style="background:rgba(255,68,68,.1);color:var(--red);border:1px solid rgba(255,68,68,.2)" onclick="deleteCashoutMethod(${m.id},'${escAttr(m.label)}')">🗑</button>
        </div>
      </div>
    </div>`).join('');
}

function editCashoutMethod(id) {
  const m = (window._cmtData||[]).find(x=>x.id==id);
  if (!m) return;
  document.getElementById('cmt-id').value    = m.id;
  document.getElementById('cmt-label').value = m.label;
  document.getElementById('cmt-slug').value  = m.slug;
  document.getElementById('cmt-slug').disabled = true;
  document.getElementById('cmt-icon').value  = m.icon || '💰';
  document.getElementById('cmt-desc').value  = m.description || '';
  document.getElementById('cmt-sort').value  = m.sort_order;
  document.getElementById('cmt-active').value= m.is_active;
  document.getElementById('cmt-form-title').textContent = '✏️ Editing: ' + m.label;
  document.getElementById('cmt-form-card').scrollIntoView({behavior:'smooth'});
}

function resetCmtForm() {
  ['cmt-id','cmt-label','cmt-desc'].forEach(id => document.getElementById(id).value = '');
  document.getElementById('cmt-slug').value    = '';
  document.getElementById('cmt-slug').disabled = false;
  document.getElementById('cmt-icon').value    = '💰';
  document.getElementById('cmt-sort').value    = '99';
  document.getElementById('cmt-active').value  = '1';
  document.getElementById('cmt-form-title').textContent = '➕ Add Cashout Method';
  document.getElementById('cmt-form-alert').className = 'alert';
}

async function saveCashoutMethod() {
  const al  = document.getElementById('cmt-form-alert');
  const id  = document.getElementById('cmt-id').value;
  const data = {
    id:          id ? parseInt(id) : undefined,
    label:       document.getElementById('cmt-label').value.trim(),
    slug:        document.getElementById('cmt-slug').value.trim(),
    icon:        document.getElementById('cmt-icon').value.trim() || '💰',
    description: document.getElementById('cmt-desc').value.trim(),
    sort_order:  parseInt(document.getElementById('cmt-sort').value) || 99,
    is_active:   parseInt(document.getElementById('cmt-active').value),
  };
  if (!data.label) { showAdminAlert(al,'Label is required.','error'); return; }
  if (!id && !data.slug) { showAdminAlert(al,'Slug is required for new methods.','error'); return; }
  const action = id ? 'cashout_methods_update' : 'cashout_methods_create';
  const d = await apiFetch(action,'POST',data);
  if (d.success) {
    showAdminAlert(al, id ? 'Method updated!' : 'Method added!', 'success');
    resetCmtForm();
    loadCashoutMethods();
    toast(id ? 'Updated' : 'Method added', 'ok');
  } else showAdminAlert(al, d.error||'Save failed','error');
}

async function deleteCashoutMethod(id, label) {
  if (!confirm('Delete cashout method "' + label + '"?\n\nPlayers using this method will still have their saved payout methods, but it won\'t appear as an option for new methods.')) return;
  const d = await apiFetch('cashout_methods_delete','POST',{id});
  if (d.success) { toast('Deleted','ok'); loadCashoutMethods(); }
  else toast(d.error||'Error','err');
}

// ─── GAME MANAGEMENT ──────────────────────────────────────
async function loadGames() {
  const d = await apiFetch('platforms_admin');
  const el = document.getElementById('games-list');
  const ct = document.getElementById('games-count');
  if (!d.success) { el.innerHTML = '<div class="empty">Failed to load games.</div>'; return; }
  const games = d.platforms;
  ct.textContent = games.length + ' game' + (games.length !== 1 ? 's' : '');
  if (!games.length) { el.innerHTML = '<div class="empty" style="padding:24px;text-align:center">No games yet. Add one above.</div>'; return; }
  el.innerHTML = games.map(g => `
    <div class="game-row${!parseInt(g.is_active)?' inactive-overlay':''}">
      <div class="game-color-dot" style="background:${g.color};color:${g.color}"></div>
      <div class="game-info">
        <div class="game-name">${escHtmlA(g.name)}
          ${!parseInt(g.is_active) ? '<span class="badge" style="background:rgba(255,68,68,.15);color:var(--red);font-size:15px;margin-left:6px">INACTIVE</span>' : ''}
        </div>
        <div class="game-slug">${escHtmlA(g.slug)}</div>
        <div class="game-urls">
          <div class="game-url-row">
            <span class="game-url-label">PLAYER</span>
            <span class="game-url-val">${escHtmlA(g.player_url)}</span>
            <a href="${escHtmlA(g.player_url)}" target="_blank" class="game-url-link">↗</a>
          </div>
          ${g.agent_link ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--gold)">AGENT LINK</span>
            <span class="game-url-val">${escHtmlA(g.agent_link)}</span>
            <a href="${escHtmlA(g.agent_link)}" target="_blank" class="game-url-link" style="color:var(--gold)">↗</a>
          </div>` : ''}
          ${g.games_link ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--cyan)">GAMES LINK</span>
            <span class="game-url-val">${escHtmlA(g.games_link)}</span>
            <a href="${escHtmlA(g.games_link)}" target="_blank" class="game-url-link" style="color:var(--cyan)">↗</a>
          </div>` : ''}
          ${g.agent_login ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--purple)">LOGIN</span>
            <span class="game-url-val" style="${IS_MASTER_ADMIN?'':'filter:blur(5px);user-select:none;pointer-events:none'}">${escHtmlA(g.agent_login)}</span>
          </div>` : ''}
          ${g.agent_password ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--purple)">PASSWORD</span>
            <span class="game-url-val" style="${IS_MASTER_ADMIN?'':'filter:blur(5px);user-select:none;pointer-events:none'}">${escHtmlA(g.agent_password)}</span>
          </div>` : ''}
          ${g.agent_guide ? `<div style="margin-top:6px;padding:8px 10px;background:rgba(155,93,229,0.07);border-radius:6px;font-size:12px;color:var(--text2);white-space:pre-wrap;max-height:80px;overflow:auto"><span style="color:var(--purple);font-weight:700;font-size:11px;letter-spacing:1px">AGENT GUIDE </span>${escHtmlA(g.agent_guide)}</div>` : ''}
          ${(g.sub_agent_login||g.sub_agent_password) ? `<div style="margin-top:4px;font-size:11px;font-weight:700;color:var(--purple);letter-spacing:1px;text-transform:uppercase;margin-bottom:2px">SUB-ACCOUNT</div>` : ''}
          ${g.sub_agent_login ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--purple)">LOGIN</span>
            <span class="game-url-val" style="${IS_MASTER_ADMIN?'':'filter:blur(5px);user-select:none;pointer-events:none'}">${escHtmlA(g.sub_agent_login)}</span>
          </div>` : ''}
          ${g.sub_agent_password ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--purple)">PASSWORD</span>
            <span class="game-url-val" style="${IS_MASTER_ADMIN?'':'filter:blur(5px);user-select:none;pointer-events:none'}">${escHtmlA(g.sub_agent_password)}</span>
          </div>` : ''}
          ${(g.cashier_login||g.cashier_password) ? `<div style="margin-top:4px;font-size:11px;font-weight:700;color:var(--cyan);letter-spacing:1px;text-transform:uppercase;margin-bottom:2px">CASHIER</div>` : ''}
          ${g.cashier_login ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--cyan)">LOGIN</span>
            <span class="game-url-val" style="${IS_MASTER_ADMIN?'':'filter:blur(5px);user-select:none;pointer-events:none'}">${escHtmlA(g.cashier_login)}</span>
          </div>` : ''}
          ${g.cashier_password ? `<div class="game-url-row">
            <span class="game-url-label" style="color:var(--cyan)">PASSWORD</span>
            <span class="game-url-val" style="${IS_MASTER_ADMIN?'':'filter:blur(5px);user-select:none;pointer-events:none'}">${escHtmlA(g.cashier_password)}</span>
          </div>` : ''}
        </div>
      </div>
      <div style="text-align:right;flex-shrink:0">
        <div style="font-size:15px;color:var(--text2);margin-bottom:4px">Order: ${g.sort_order}</div>
        <div style="font-size:11px;color:var(--text2);margin-bottom:4px" title="Last edited">✏️ ${g.updated_at ? new Date(g.updated_at).toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'}) : '—'}</div>
        <div id="credit-total-${g.id}" style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:13px;color:var(--cyan);margin-bottom:6px">💳 —</div>
        <div class="game-actions">
          <button class="game-edit-btn" style="background:rgba(0,229,255,.1);color:var(--cyan);border:1px solid rgba(0,229,255,.2)" onclick="editGame(${g.id})">✏️ Edit</button>
          ${IS_MASTER_ADMIN ? `<button class="game-edit-btn" style="background:rgba(255,68,68,.1);color:var(--red);border:1px solid rgba(255,68,68,.2)" onclick="deleteGame(${g.id},'${escAttr(g.name)}')">🗑 Archive</button>` : ''}
        </div>
      </div>
    </div>`).join('');
  // Store for edit
  window._gamesData = games;
  // Load credit totals for each game
  games.forEach(g => {
    fetch('/api/platforms.php?action=credits_list&platform_id=' + g.id).then(r=>r.json()).then(d=>{
      const el = document.getElementById('credit-total-' + g.id);
      if (el && d.success) {
        const t = d.total||0;
        el.textContent = '💳 ' + (t%1===0 ? t.toLocaleString() : parseFloat(t).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2}));
      }
    }).catch(()=>{});
  });
}

function editGame(id) {
  const g = (window._gamesData || []).find(x => x.id == id);
  if (!g) return;
  document.getElementById('gf-id').value        = g.id;
  document.getElementById('gf-name').value      = g.name;
  document.getElementById('gf-slug').value      = g.slug;
  document.getElementById('gf-slug').disabled   = true;
  document.getElementById('gf-player-url').value  = g.player_url;
  document.getElementById('gf-alias-param').value = g.url_alias_param || '';
  document.getElementById('gf-color').value        = g.color || '#f0c040';
  document.getElementById('gf-color-hex').value  = g.color || '#f0c040';
  document.getElementById('gf-sort').value       = g.sort_order;
  document.getElementById('gf-active').value     = g.is_active;
  document.getElementById('game-form-title').textContent = '✏️ Editing: ' + g.name;

  if (IS_MASTER_ADMIN) {
    // Show edit mode, hide view mode
    document.getElementById('gf-agent-edit').style.display = 'block';
    document.getElementById('gf-agent-view').style.display = 'none';
    document.getElementById('gf-agent-link').value         = g.agent_link     || '';
    document.getElementById('gf-agent-login').value        = g.agent_login    || '';
    document.getElementById('gf-agent-password').value     = g.agent_password || '';
    document.getElementById('gf-games-link').value         = g.games_link     || '';
    document.getElementById('gf-agent-guide').value        = g.agent_guide    || '';
    document.getElementById('gf-sub-agent-login').value    = g.sub_agent_login    || '';
    document.getElementById('gf-sub-agent-password').value = g.sub_agent_password || '';
    document.getElementById('gf-cashier-login').value      = g.cashier_login      || '';
    document.getElementById('gf-cashier-password').value   = g.cashier_password   || '';
    document.getElementById('gf-credit-btn').disabled = false;
  } else {
    // Show view mode, hide edit mode
    document.getElementById('gf-agent-edit').style.display = 'none';
    document.getElementById('gf-agent-view').style.display = 'block';
    document.getElementById('gf-credit-btn').disabled = true;

    const agentFields = [
      {label:'Agent Login',               key:'agent_login',           isUrl:false, isCred:true},
      {label:'Agent Password',            key:'agent_password',        isUrl:false, isCred:true},
      {label:'Agent Link',                key:'agent_link',            isUrl:true,  isCred:false},
      {label:'Games Link',                key:'games_link',            isUrl:true,  isCred:false},
      {label:'Agent Guide',               key:'agent_guide',           isUrl:false, isCred:false},
      {label:'Sub-Account Agent Login',   key:'sub_agent_login',       isUrl:false, isCred:true},
      {label:'Sub-Account Agent Password',key:'sub_agent_password',    isUrl:false, isCred:true},
      {label:'Cashier Login',             key:'cashier_login',         isUrl:false, isCred:true},
      {label:'Cashier Password',          key:'cashier_password',      isUrl:false, isCred:true},
    ];
    const content = document.getElementById('gf-agent-view-content');
    content.innerHTML = agentFields.map(f => {
      const val = g[f.key] || '';
      if (!val) return '';
      const openBtn = f.isUrl ? `<a href="${escHtmlA(val)}" target="_blank" rel="noopener"
          style="background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.25);color:var(--cyan);border-radius:5px;padding:3px 9px;font-size:12px;font-weight:700;cursor:pointer;flex-shrink:0;text-decoration:none">
          ↗ Open
        </a>` : '';
      const valStyle = f.isCred ? 'filter:blur(5px);user-select:none;pointer-events:none' : '';
      const copyBtn = f.isCred ? '' : `<button onclick="copyToClipboard(${JSON.stringify(val)},this)"
          style="background:rgba(155,93,229,0.15);border:1px solid rgba(155,93,229,0.3);color:var(--purple);border-radius:5px;padding:3px 10px;font-size:12px;font-weight:700;cursor:pointer;flex-shrink:0">
          📋 Copy
        </button>`;
      return `<div style="display:flex;align-items:center;gap:8px;padding:7px 10px;background:rgba(155,93,229,0.05);border-radius:6px">
        <span style="font-size:12px;font-weight:700;color:var(--purple);min-width:160px;flex-shrink:0">${escHtmlA(f.label)}</span>
        <span style="flex:1;color:var(--text);font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;${valStyle}">${escHtmlA(val)}</span>
        ${openBtn}
        ${copyBtn}
      </div>`;
    }).join('');
    if (!content.innerHTML.trim()) {
      content.innerHTML = '<div style="color:var(--text2);font-size:14px;padding:8px 0">No agent info has been set for this game.</div>';
    }
  }

  // Load credit total
  fetch('/api/platforms.php?action=credits_list&platform_id=' + g.id).then(r=>r.json()).then(d=>{
    if (d.success) {
      const t = d.total||0;
      document.getElementById('gf-credit-total').textContent = t%1===0 ? t.toLocaleString() : parseFloat(t).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2});
    }
  });
  // Non-master admins need the form card revealed when editing
  document.getElementById('game-form-card').style.display = 'block';
  document.getElementById('game-form-card').scrollIntoView({behavior:'smooth'});
}

function resetGameForm() {
  document.getElementById('gf-id').value          = '';
  document.getElementById('gf-name').value        = '';
  document.getElementById('gf-slug').value        = '';
  document.getElementById('gf-slug').disabled     = false;
  document.getElementById('gf-player-url').value  = '';
  document.getElementById('gf-color').value       = '#f0c040';
  document.getElementById('gf-color-hex').value   = '#f0c040';
  document.getElementById('gf-sort').value        = '99';
  document.getElementById('gf-active').value      = '1';
  document.getElementById('gf-credit-total').textContent = '—';
  document.getElementById('gf-credit-btn').disabled = true;
  if (IS_MASTER_ADMIN) {
    // Master admin: show edit panel (visible for new games too), clear all fields
    document.getElementById('gf-agent-edit').style.display = 'block';
    document.getElementById('gf-agent-view').style.display = 'none';
    document.getElementById('gf-agent-link').value         = '';
    document.getElementById('gf-agent-login').value        = '';
    document.getElementById('gf-agent-password').value     = '';
    document.getElementById('gf-games-link').value         = '';
    document.getElementById('gf-agent-guide').value        = '';
    document.getElementById('gf-sub-agent-login').value    = '';
    document.getElementById('gf-sub-agent-password').value = '';
    document.getElementById('gf-cashier-login').value      = '';
    document.getElementById('gf-cashier-password').value   = '';
  } else {
    // Non-master: hide both panels; they only appear when editing
    document.getElementById('gf-agent-edit').style.display = 'none';
    document.getElementById('gf-agent-view').style.display = 'none';
  }
  document.getElementById('game-form-title').textContent = '➕ Add New Game';
  document.getElementById('game-form-alert').className = 'alert';
}

function syncColorPicker(hex) {
  if (/^#[0-9a-fA-F]{6}$/.test(hex)) document.getElementById('gf-color').value = hex;
}

async function saveGame() {
  const al = document.getElementById('game-form-alert');
  const id  = document.getElementById('gf-id').value;
  const data = {
    id:          id ? parseInt(id) : undefined,
    name:           document.getElementById('gf-name').value.trim(),
    slug:           document.getElementById('gf-slug').value.trim(),
    player_url:       document.getElementById('gf-player-url').value.trim(),
    url_alias_param:  document.getElementById('gf-alias-param').value.trim(),
    agent_link:       document.getElementById('gf-agent-link').value.trim(),
    agent_login:    document.getElementById('gf-agent-login').value.trim(),
    agent_password: document.getElementById('gf-agent-password').value.trim(),
    games_link:     document.getElementById('gf-games-link').value.trim(),
    agent_guide:        document.getElementById('gf-agent-guide').value.trim(),
    sub_agent_login:    document.getElementById('gf-sub-agent-login').value.trim(),
    sub_agent_password: document.getElementById('gf-sub-agent-password').value.trim(),
    cashier_login:      document.getElementById('gf-cashier-login').value.trim(),
    cashier_password:   document.getElementById('gf-cashier-password').value.trim(),
    color:              document.getElementById('gf-color-hex').value.trim() || document.getElementById('gf-color').value,
    sort_order:  parseInt(document.getElementById('gf-sort').value) || 99,
    is_active:   parseInt(document.getElementById('gf-active').value),
  };
  if (!data.name || !data.player_url) { showAdminAlert(al,'Name and Player URL are required.','error'); return; }
  if (!id && !data.slug) { showAdminAlert(al,'Slug is required for new games.','error'); return; }
  const action = id ? 'platforms_update' : 'platforms_create';
  const d = await apiFetch(action, 'POST', data);
  if (d.success) {
    showAdminAlert(al, id ? 'Game updated!' : 'Game added!', 'success');
    resetGameForm();
    loadGames();
    toast(id ? 'Game updated' : 'Game added', 'ok');
  } else {
    showAdminAlert(al, d.error || 'Save failed.', 'error');
  }
}

async function deleteGame(id, name) {
  if (!confirm('Archive "' + name + '"?\n\nThis hides it from active games but does NOT permanently delete it. You can restore it from the Archived Games section below.')) return;
  const d = await apiFetch('platforms_delete','POST',{id});
  if (d.success) { toast('Game archived','ok'); loadGames(); loadArchivedGames(); }
  else toast(d.error||'Error','err');
}

async function loadArchivedGames() {
  const list = document.getElementById('archived-games-list');
  if (!list) return;
  const d = await apiFetch('platforms_archived');
  if (!d.success) { list.innerHTML='<div style="padding:16px 18px;color:var(--red)">Failed to load.</div>'; return; }
  if (!d.platforms.length) {
    list.innerHTML='<div style="padding:16px 18px;color:var(--text2);font-size:14px">No archived games.</div>';
    return;
  }
  list.innerHTML = d.platforms.map(g=>`
    <div style="display:flex;align-items:center;justify-content:space-between;padding:12px 18px;border-bottom:1px solid var(--border);gap:10px">
      <div style="flex:1;min-width:0">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text)">${escHtmlA(g.name)}</div>
        <div style="font-size:12px;font-family:monospace;color:var(--text2);margin-top:2px">${escHtmlA(g.slug)}</div>
        <div style="font-size:11px;color:var(--text2);margin-top:2px">Archived: ${g.deleted_at ? new Date(g.deleted_at).toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'}) : '—'}</div>
      </div>
      <div style="display:flex;gap:6px;flex-shrink:0">
        <button onclick="restoreGame(${g.id},'${escAttr(g.name)}')"
          style="background:rgba(0,230,118,.1);border:1px solid rgba(0,230,118,.25);color:var(--green);border-radius:6px;padding:6px 12px;font-size:13px;font-weight:700;cursor:pointer">
          ↩ Restore
        </button>
        <button onclick="purgeGame(${g.id},'${escAttr(g.name)}')"
          style="background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:6px;padding:6px 12px;font-size:13px;font-weight:700;cursor:pointer">
          🗑 Delete Permanently
        </button>
      </div>
    </div>`).join('');
}

async function restoreGame(id, name) {
  if (!confirm('Restore "' + name + '" back to active games?')) return;
  const d = await apiFetch('platforms_restore','POST',{id});
  if (d.success) { toast('Game restored','ok'); loadGames(); loadArchivedGames(); }
  else toast(d.error||'Error','err');
}

async function purgeGame(id, name) {
  if (!confirm('PERMANENTLY delete "' + name + '"?\n\nThis cannot be undone. Historical purchase records will still reference the slug.')) return;
  if (!confirm('Are you absolutely sure? This is irreversible.')) return;
  const d = await apiFetch('platforms_purge','POST',{id});
  if (d.success) { toast('Game permanently deleted','ok'); loadArchivedGames(); }
  else toast(d.error||'Error','err');
}

// ── CREDIT ACCOUNTING ─────────────────────────────────────────────────────
let _creditPlatformId = null;

async function openCreditModal() {
  const id = document.getElementById('gf-id').value;
  if (!id) return;
  _creditPlatformId = parseInt(id);
  const g = (window._gamesData||[]).find(x=>x.id==id);
  document.getElementById('cm-platform-name').textContent = g ? g.name : ('Platform #' + id);
  document.getElementById('credit-modal').style.display = 'flex';
  document.getElementById('cm-date').value = new Date().toISOString().slice(0,10);
  resetCreditForm();
  await loadCreditEntries();
}

function closeCreditModal() {
  document.getElementById('credit-modal').style.display = 'none';
  _creditPlatformId = null;
}

async function loadCreditEntries() {
  if (!_creditPlatformId) return;
  const d = await fetch('/api/platforms.php?action=credits_list&platform_id=' + _creditPlatformId).then(r=>r.json());
  if (!d.success) { document.getElementById('cm-list').innerHTML='<div style="color:var(--red);padding:16px">Failed to load.</div>'; return; }
  const total = d.total || 0;
  document.getElementById('cm-total').textContent = total % 1 === 0 ? total.toLocaleString() : parseFloat(total).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2});
  document.getElementById('gf-credit-total').textContent = total % 1 === 0 ? total.toLocaleString() : parseFloat(total).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2});
  const list = document.getElementById('cm-list');
  if (!d.credits.length) { list.innerHTML='<div style="color:var(--text2);text-align:center;padding:20px">No credit entries yet.</div>'; return; }
  list.innerHTML = `<table style="width:100%;border-collapse:collapse;font-size:14px">
    <thead><tr style="border-bottom:1px solid var(--border)">
      <th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">DATE</th>
      <th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">TYPE</th>
      <th style="padding:8px 6px;text-align:right;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">AMOUNT</th>
      <th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">METHOD</th>
      <th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">NOTES</th>
      <th style="padding:8px 6px;width:80px"></th>
    </tr></thead>
    <tbody>
    ${d.credits.map(c=>{
      const isDebit = c.type === 'debit';
      const amtColor = isDebit ? 'var(--red)' : 'var(--cyan)';
      const amtPrefix = isDebit ? '−' : '+';
      const rowBg = isDebit ? 'background:rgba(255,68,68,.03)' : '';
      const typeBadge = isDebit
        ? '<span style="background:rgba(255,68,68,.15);color:var(--red);font-size:11px;font-weight:700;padding:2px 7px;border-radius:10px;letter-spacing:.3px">DEBIT</span>'
        : '<span style="background:rgba(0,229,255,.12);color:var(--cyan);font-size:11px;font-weight:700;padding:2px 7px;border-radius:10px;letter-spacing:.3px">CREDIT</span>';
      const refLink = (isDebit && c.purchase_ref_id)
        ? `<button onclick="jumpToPurchase(${c.purchase_ref_id})" style="background:rgba(240,192,64,.1);border:1px solid rgba(240,192,64,.25);color:var(--gold);border-radius:5px;padding:3px 8px;font-size:12px;cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;white-space:nowrap">Purchase #${c.purchase_ref_id} ↗</button>`
        : '';
      const editDel = !isDebit
        ? `<button onclick="editCreditEntry(${c.id})" style="background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.2);color:var(--cyan);border-radius:5px;padding:3px 8px;font-size:13px;cursor:pointer;margin-right:4px">✏️</button>
           <button onclick="deleteCreditEntry(${c.id})" style="background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:5px;padding:3px 8px;font-size:13px;cursor:pointer">🗑</button>`
        : '';
      return `<tr style="border-bottom:1px solid rgba(255,255,255,0.05);${rowBg}">
        <td style="padding:9px 6px;color:var(--text)">${escHtmlA(c.credit_date)}</td>
        <td style="padding:9px 6px">${typeBadge}</td>
        <td style="padding:9px 6px;text-align:right;font-family:'Exo 2',sans-serif;font-weight:700;color:${amtColor}">${amtPrefix}${parseFloat(c.credits_purchased).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2})}</td>
        <td style="padding:9px 6px;color:var(--text2)">${escHtmlA(c.payment_method||'—')}</td>
        <td style="padding:9px 6px;color:var(--text2);font-size:13px;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${escHtmlA(c.notes||'')}">${escHtmlA(c.notes||'')}</td>
        <td style="padding:9px 6px;text-align:right;white-space:nowrap">${refLink}${editDel}</td>
      </tr>`;
    }).join('')}
    </tbody></table>`;
}

function editCreditEntry(id) {
  const rows = document.querySelectorAll('#cm-list tbody tr');
  // Re-fetch from last API response stored on rows via data or refetch
  fetch('/api/platforms.php?action=credits_list&platform_id=' + _creditPlatformId).then(r=>r.json()).then(d=>{
    if (!d.success) return;
    const c = d.credits.find(x=>x.id==id);
    if (!c) return;
    document.getElementById('cm-entry-id').value  = c.id;
    document.getElementById('cm-credits').value   = c.credits_purchased;
    document.getElementById('cm-date').value      = c.credit_date;
    document.getElementById('cm-method').value    = c.payment_method || '';
    document.getElementById('cm-notes').value     = c.notes || '';
    document.getElementById('cm-form-title').textContent = '✏️ Editing Entry #' + c.id;
    document.getElementById('cm-credits').focus();
  });
}

function resetCreditForm() {
  document.getElementById('cm-entry-id').value  = '';
  document.getElementById('cm-credits').value   = '';
  document.getElementById('cm-date').value      = new Date().toISOString().slice(0,10);
  document.getElementById('cm-method').value    = '';
  document.getElementById('cm-notes').value     = '';
  document.getElementById('cm-form-title').textContent = '➕ Add Credit Entry';
  document.getElementById('cm-form-alert').className = 'alert';
}

async function saveCreditEntry() {
  const al = document.getElementById('cm-form-alert');
  const entryId = document.getElementById('cm-entry-id').value;
  const credits = parseFloat(document.getElementById('cm-credits').value);
  const date    = document.getElementById('cm-date').value;
  const method  = document.getElementById('cm-method').value.trim();
  const notes   = document.getElementById('cm-notes').value.trim();
  if (!credits || credits <= 0) { showAdminAlert(al,'Credits Purchased must be greater than 0.','error'); return; }
  if (!date) { showAdminAlert(al,'Date is required.','error'); return; }
  const action = entryId ? 'credits_update' : 'credits_create';
  const payload = entryId
    ? {id:parseInt(entryId),credits_purchased:credits,credit_date:date,payment_method:method,notes}
    : {platform_id:_creditPlatformId,credits_purchased:credits,credit_date:date,payment_method:method,notes};
  const d = await fetch(`/api/platforms.php?action=${action}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(r=>r.json());
  if (d.success) {
    showAdminAlert(al, entryId ? 'Entry updated!' : 'Entry added!', 'success');
    resetCreditForm();
    await loadCreditEntries();
  } else {
    showAdminAlert(al, d.error||'Error saving entry.','error');
  }
}

async function deleteCreditEntry(id) {
  if (!confirm('Delete this credit entry? This cannot be undone.')) return;
  const d = await fetch('/api/platforms.php?action=credits_delete',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id})}).then(r=>r.json());
  if (d.success) { toast('Entry deleted','ok'); await loadCreditEntries(); }
  else toast(d.error||'Error','err');
}

async function jumpToPurchase(purchaseId) {
  closeCreditModal();
  showSec('purchases');
  document.querySelectorAll('#section-purchases .ftab').forEach(b=>b.classList.remove('active'));
  const allTab = document.querySelector('#section-purchases .ftab[onclick*="\'all\'"]');
  if (allTab) allTab.classList.add('active');
  await loadPurchases('all');
  const el = document.getElementById('pr-' + purchaseId);
  if (el) {
    el.scrollIntoView({behavior:'smooth', block:'center'});
    el.style.outline = '2px solid var(--gold)';
    el.style.borderRadius = '12px';
    setTimeout(() => { el.style.outline = ''; el.style.borderRadius = ''; }, 2500);
  }
}

// ── BACKUP SYSTEM ────────────────────────────────────────────
async function loadBackups() {
  const list  = document.getElementById('backup-list');
  const count = document.getElementById('backup-count');
  list.innerHTML = '<div style="padding:24px;text-align:center;color:var(--text2);font-size:15px">Loading...</div>';
  const d = await fetch('/api/backup.php?action=list').then(r=>r.json());
  if (!d.success) { list.innerHTML='<div style="padding:24px;text-align:center;color:var(--red)">Failed to load backups.</div>'; return; }
  count.textContent = d.backups.length + ' / 7';
  if (!d.backups.length) {
    list.innerHTML='<div style="padding:32px;text-align:center;color:var(--text2);font-size:15px">No backups yet. Click <strong>Create Backup Now</strong> to make the first one.</div>';
    return;
  }
  list.innerHTML = d.backups.map((b, i) => {
    const sizeMB = (b.size / 1048576).toFixed(2);
    const isLatest = i === 0;
    return `<div style="display:flex;align-items:center;gap:14px;padding:14px 18px;border-bottom:1px solid var(--border);flex-wrap:wrap;${isLatest?'background:rgba(0,229,255,.025)':''}">
      <div style="font-size:22px;flex-shrink:0">${isLatest ? '🟢' : '💿'}</div>
      <div style="flex:1;min-width:160px">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;color:var(--text)">${escHtmlA(b.name)}</div>
        <div style="font-size:13px;color:var(--text2);margin-top:2px">${escHtmlA(b.created)} · ${sizeMB} MB${isLatest?' · <span style="color:var(--cyan);font-weight:700">Latest</span>':''}</div>
      </div>
      <div style="display:flex;gap:8px;flex-shrink:0">
        <a href="/api/backup.php?action=download&file=${encodeURIComponent(b.name)}"
           style="background:rgba(0,229,255,.1);border:1px solid rgba(0,229,255,.25);color:var(--cyan);border-radius:var(--rs);padding:7px 14px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:13px;text-decoration:none;white-space:nowrap">
          ⬇ Download
        </a>
        <button onclick="deleteBackup('${escHtmlA(b.name)}')"
          style="background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:var(--rs);padding:7px 12px;font-family:'Exo 2',sans-serif;font-weight:700;font-size:13px;cursor:pointer">
          🗑
        </button>
      </div>
    </div>`;
  }).join('') + '<div style="padding:10px 18px;font-size:13px;color:var(--text2);border-top:1px solid var(--border)">Oldest backup is automatically removed when a new one is created beyond the 7-backup limit.</div>';
}

async function createBackup() {
  const btn = document.getElementById('backup-create-btn');
  const al  = document.getElementById('backup-alert');
  btn.disabled = true;
  btn.textContent = '⏳ Creating...';
  al.className = 'alert';
  showAdminAlert(al, 'Creating backup — this may take up to 30 seconds…', 'info');
  try {
    const d = await fetch('/api/backup.php?action=create', {method:'POST'}).then(r=>r.json());
    if (d.success) {
      const sizeMB = (d.size / 1048576).toFixed(2);
      showAdminAlert(al, `✅ Backup created: ${d.name} (${sizeMB} MB)`, 'success');
      loadBackups();
      loadPlatformStats();
    } else {
      showAdminAlert(al, '❌ ' + (d.error || 'Backup failed'), 'error');
    }
  } catch(e) {
    showAdminAlert(al, '❌ Request failed — server may have timed out', 'error');
  }
  btn.disabled = false;
  btn.textContent = '📦 Create Backup Now';
}

async function deleteBackup(name) {
  if (!confirm(`Delete backup "${name}"?\nThis cannot be undone.`)) return;
  const d = await fetch('/api/backup.php?action=delete', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({name})}).then(r=>r.json());
  if (d.success) { toast('Backup deleted', 'ok'); loadBackups(); }
  else toast(d.error || 'Delete failed', 'err');
}

// Sync hex input with color picker
document.addEventListener('DOMContentLoaded', function() {
  const picker = document.getElementById('gf-color');
  const hex    = document.getElementById('gf-color-hex');
  if (picker && hex) {
    picker.addEventListener('input', function() { hex.value = picker.value; });
  }
});

// ─── COMPOSE: send message to any player ──────────────────
let composePlayer = null; // { id, username, alias, email }

function searchComposePlayers(q) {
  const dd = document.getElementById('compose-dropdown');
  if (!q || q.length < 1) { dd.style.display = 'none'; return; }
  const lq = q.toLowerCase();
  const matches = (allUsers.length ? allUsers : GM.all || []).filter(u =>
    u.username.toLowerCase().includes(lq) ||
    (u.alias||'').toLowerCase().includes(lq) ||
    (u.email||'').toLowerCase().includes(lq)
  ).filter(u => !u.is_admin).slice(0, 8);

  if (!matches.length) {
    dd.innerHTML = '<div style="padding:12px;color:var(--text2);font-size:15px;text-align:center">No players found</div>';
    dd.style.display = 'block'; return;
  }
  dd.innerHTML = matches.map(u => {
    const color = avatarColor(u.username);
    const init  = avatarInit(u.username);
    return `<div onclick="selectComposePicker(${u.id},'${escAttr(u.username)}','${escAttr(u.alias||'')}','${escAttr(u.email||'')}','${color}')"
      style="display:flex;align-items:center;gap:10px;padding:10px 14px;cursor:pointer;transition:background .1s"
      onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='none'">
      <div style="width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,${color},${color}99);display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:700;font-size:14px;color:#fff;flex-shrink:0">${init}</div>
      <div style="min-width:0">
        <div style="font-weight:700;font-size:15px;color:var(--text)">${escHtmlA(u.username)} <span style="color:var(--cyan);font-weight:400">· ${escHtmlA(u.alias||'')}</span></div>
        <div style="font-size:15px;color:var(--text2)">${escHtmlA(u.email||'No email')} · ${u.tokens||0} 🪙</div>
      </div>
    </div>`;
  }).join('');
  dd.style.display = 'block';
}

function selectComposePicker(id, username, alias, email, color) {
  composePlayer = { id, username, alias, email };
  const sel  = document.getElementById('compose-selected');
  const av   = document.getElementById('compose-player-avatar');
  const nm   = document.getElementById('compose-player-name');
  const inf  = document.getElementById('compose-player-info');
  av.textContent    = username.charAt(0).toUpperCase();
  av.style.background = `linear-gradient(135deg,${color},${color}99)`;
  nm.textContent    = username + ' · ' + alias;
  inf.textContent   = email || 'No email';
  sel.style.display = 'flex';
  document.getElementById('compose-search').value = '';
  document.getElementById('compose-dropdown').style.display = 'none';
  document.getElementById('compose-msg').focus();
}

function clearComposePicker() {
  composePlayer = null;
  document.getElementById('compose-selected').style.display = 'none';
  document.getElementById('compose-search').value = '';
  document.getElementById('compose-alert').className = 'alert';
}

async function adminComposeSend() {
  const al  = document.getElementById('compose-alert');
  const msg = document.getElementById('compose-msg').value.trim();
  if (!composePlayer) { showAdminAlert(al, 'Select a player first.', 'error'); return; }
  if (!msg)           { showAdminAlert(al, 'Type a message first.', 'error'); return; }

  const d = await apiFetch('chat_admin_send', 'POST', { user_id: composePlayer.id, message: msg });
  if (d.success) {
    document.getElementById('compose-msg').value = '';
    showAdminAlert(al, '✓ Message sent to ' + composePlayer.username + '! They will see it in their Support chat.', 'success');
    loadChatInbox(true); // refresh inbox
    loadChatBadge();
    // Optional: open the thread immediately
    setTimeout(() => {
      openChatThread(composePlayer.id, composePlayer.username, composePlayer.alias);
    }, 800);
  } else {
    showAdminAlert(al, d.error || 'Failed to send.', 'error');
  }
}

// Close compose dropdown when clicking outside
document.addEventListener('click', function(e) {
  const dd = document.getElementById('compose-dropdown');
  const search = document.getElementById('compose-search');
  if (dd && !dd.contains(e.target) && e.target !== search) {
    dd.style.display = 'none';
  }
});
async function loadPendingSignups() {
  const d  = await apiFetch('pending_signups');
  const el = document.getElementById('pending-list');
  if (!d.success || !d.pending.length) {
    el.innerHTML = '<div class="card"><div class="empty" style="padding:24px;text-align:center">✅ No pending registrations.</div></div>';
    document.getElementById('badge-pending').style.display = 'none';
    return;
  }
  const badge = document.getElementById('badge-pending');
  if (badge) { badge.textContent = d.pending.length; badge.style.display = 'inline'; }

  el.innerHTML = d.pending.map(p => {
    const color    = avatarColor(p.username);
    const init     = avatarInit(p.username);
    const created  = (p.created_at||'').substring(0,16);
    const expires  = (p.expires_at||'').substring(0,16);
    const now      = new Date();
    const expDate  = new Date(p.expires_at);
    const expiring = (expDate - now) < 3600000; // < 1hr
    return `
    <div class="card" style="margin-bottom:10px;display:flex;align-items:center;gap:14px;flex-wrap:wrap">
      <div style="width:44px;height:44px;border-radius:50%;background:linear-gradient(135deg,${color},${color}99);display:flex;align-items:center;justify-content:center;font-family:'Exo 2',sans-serif;font-weight:700;font-size:18px;color:#fff;flex-shrink:0">${init}</div>
      <div style="flex:1;min-width:180px">
        <div style="font-family:'Exo 2',sans-serif;font-weight:700;font-size:15px;color:var(--text)">${escHtmlA(p.username)}</div>
        <div style="font-size:14px;color:var(--cyan);margin-top:1px">${escHtmlA(p.alias)}</div>
        <div style="font-size:15px;color:var(--text2);margin-top:2px">${escHtmlA(p.email||'No email')}</div>
        <div style="font-size:14px;margin-top:4px;display:flex;gap:10px;flex-wrap:wrap">
          <span style="color:var(--text2)">Registered: ${created}</span>
          <span style="color:${expiring?'var(--red)':'var(--text2)'}">Expires: ${expires}${expiring?' ⚠️':''}</span>
        </div>
      </div>
      <div style="display:flex;gap:8px;flex-shrink:0">
        <button class="btn btn-green" style="padding:8px 16px;font-size:14px" onclick="approvePending(${p.id},'${escAttr(p.username)}')">
          ✓ Approve
        </button>
        <button class="btn btn-red" style="padding:8px 16px;font-size:14px" onclick="deletePending(${p.id},'${escAttr(p.username)}')">
          ✗ Delete
        </button>
      </div>
    </div>`;
  }).join('');
}

async function approvePending(id, username) {
  if (!confirm('Approve ' + username + '?\n\nThis will create their account immediately and bypass email verification.')) return;
  const d = await apiFetch('approve_pending', 'POST', { id });
  if (d.success) {
    toast('✓ ' + d.username + ' approved and account created!', 'ok');
    loadPendingSignups();
    loadStats();
    loadUsers();
  } else {
    toast(d.error || 'Error approving signup', 'err');
  }
}

async function deletePending(id, username) {
  if (!confirm('Delete pending signup for ' + username + '?\n\nThey will need to register again.')) return;
  const d = await apiFetch('delete_pending', 'POST', { id });
  if (d.success) { toast('Deleted', 'ok'); loadPendingSignups(); loadStats(); }
  else toast('Error', 'err');
}

// ─── ADMIN CHAT ────────────────────────────────────────────
let adminChat = { userId: null, lastId: 0, polling: null, inboxPolling: null };

function showSec(name) {
  document.querySelectorAll('.section').forEach(s=>s.classList.remove('active'));
  document.querySelectorAll('.nav-item').forEach(b=>b.classList.remove('active'));
  const sec = document.getElementById('section-'+name);
  if (sec) sec.classList.add('active');
  // Find the matching nav button safely
  document.querySelectorAll('.nav-item').forEach(b => {
    if (b.getAttribute('onclick') && b.getAttribute('onclick').includes("'"+name+"'")) {
      b.classList.add('active');
    }
  });
  if (name === 'chat') {
    showChatInbox();
    loadChatInbox();
    // Auto-refresh inbox every 5s when inbox is visible
    clearInterval(adminChat.inboxPolling);
    adminChat.inboxPolling = setInterval(() => {
      if (!adminChat.userId) { loadChatInbox(true); } // silent refresh
    }, 5000);
  } else {
    clearInterval(adminChat.inboxPolling);
  }
  if (name === 'pending') loadPendingSignups();
  if (name === 'history') loadHistory(1);
  if (name === 'users') { loadUsers(); showGamerList(); }
  if (name === 'referrals')        { loadAdminReferrals('pending', document.querySelector('#section-referrals .ftab')); }
  if (name === 'platform-accounts') loadPlatformAccountRequests('pending', document.querySelector('#section-platform-accounts .ftab'));
  if (name === 'broadcasts')        loadBroadcasts();
  if (name === 'games')            { loadGames(); loadArchivedGames(); resetGameForm(); }
  if (name === 'payments')         loadPaymentSettings();
  if (name === 'payout-settings')  loadPayoutSettings();
  if (name === 'cashout-methods')  loadCashoutMethods();
  if (name === 'backups')          loadBackups();
}

async function loadChatInbox(silent) {
  const el = document.getElementById('chat-inbox-list');
  if (!silent) el.innerHTML = '<div class="empty" style="padding:24px">Loading conversations...</div>';
  const d = await apiFetch('chat_inbox');
  if (!d.success) return;
  if (!d.inbox.length) {
    el.innerHTML = '<div class="empty" style="padding:30px;text-align:center">&#128172; No messages yet.<br><span style="color:var(--text2);font-size:14px">Users will appear here when they send a message.</span></div>';
    return;
  }
  // Update unread badge in nav
  const totalUnread = d.inbox.reduce((s,r) => s + parseInt(r.unread_count||0), 0);
  const badge = document.getElementById('badge-chat');
  if (badge) { badge.textContent = totalUnread > 9 ? '9+' : totalUnread; badge.style.display = totalUnread > 0 ? 'inline' : 'none'; }

  el.innerHTML = d.inbox.map(row => {
    const init = (row.username||'?').charAt(0).toUpperCase();
    const unread = parseInt(row.unread_count) > 0;
    const preview = (row.last_sender === 'admin' ? 'You: ' : '') + (row.last_message || '').substring(0, 65);
    const time = formatAdminTime(row.last_time);
    return `<div class="chat-inbox-row${unread?' unread':''}" onclick="openChatThread(${row.user_id},'${escAttr(row.username)}','${escAttr(row.alias)}')">
      <div class="ci-avatar" style="background:linear-gradient(135deg,${avatarColor(row.username)},${avatarColor(row.username)}aa)">${init}</div>
      <div class="ci-body">
        <div class="ci-top">
          <div class="ci-name">${escHtmlA(row.username)} <span style="color:var(--cyan);font-weight:400;font-size:14px">· ${escHtmlA(row.alias)}</span></div>
          <div class="ci-time">${time}</div>
        </div>
        <div class="ci-preview${unread?' unread-preview':''}">${escHtmlA(preview)}</div>
      </div>
      ${unread ? `<div class="ci-badge">${row.unread_count > 9 ? '9+' : row.unread_count}</div>` : ''}
    </div>`;
  }).join('');
}

function showChatInbox() {
  document.getElementById('chat-inbox-view').style.display = 'block';
  document.getElementById('chat-thread-view').style.display = 'none';
  clearInterval(adminChat.polling);
  adminChat.userId = null;
  adminChat.lastId = 0;
}

async function openChatThread(userId, username, alias) {
  clearInterval(adminChat.inboxPolling);
  adminChat.userId = userId;
  adminChat.lastId = 0;
  document.getElementById('chat-inbox-view').style.display = 'none';
  document.getElementById('chat-thread-view').style.display = 'block';
  document.getElementById('admin-chat-name').textContent = username + ' · ' + alias;
  document.getElementById('admin-chat-meta').textContent = 'Loading...';
  document.getElementById('admin-chat-avatar').textContent = username.charAt(0).toUpperCase();
  document.getElementById('admin-chat-messages').innerHTML = '<div style="color:var(--text2);font-size:14px;text-align:center;padding:20px">Loading...</div>';
  await loadAdminThread(true);
  clearInterval(adminChat.polling);
  adminChat.polling = setInterval(() => loadAdminThread(false), 3000);
}

async function loadAdminThread(scrollToBottom) {
  if (!adminChat.userId) return;
  const d = await apiFetch('chat_thread&user_id=' + adminChat.userId + '&since=' + adminChat.lastId);
  if (!d.success) return;
  const container = document.getElementById('admin-chat-messages');

  if (d.messages.length === 0 && adminChat.lastId === 0) {
    container.innerHTML = '<div style="color:var(--text2);font-size:15px;text-align:center;padding:24px">No messages in this thread yet.</div>';
  }

  if (d.messages.length > 0) {
    if (adminChat.lastId === 0) container.innerHTML = '';
    let lastDate = '';
    d.messages.forEach(msg => {
      if (container.querySelector('[data-id="' + msg.id + '"]')) return;
      const msgDate = msg.created_at.substring(0,10);
      if (msgDate !== lastDate) {
        lastDate = msgDate;
        const div = document.createElement('div');
        div.className = 'admin-date-div';
        div.textContent = formatAdminDateLabel(msgDate);
        container.appendChild(div);
      }
      const bubble = buildAdminBubble(msg);
      if (msg.sender === 'user' && adminChat.lastId > 0) {
        bubble.style.animation = 'fadeUp .25s ease';
      }
      container.appendChild(bubble);
      adminChat.lastId = Math.max(adminChat.lastId, parseInt(msg.id));
    });
    if (scrollToBottom || (container.scrollHeight - container.scrollTop - container.clientHeight < 160)) {
      container.scrollTop = container.scrollHeight;
    }
  }
  if (d.user) {
    document.getElementById('admin-chat-meta').textContent = 'Alias: ' + d.user.alias + ' · ' + d.user.tokens + ' tokens';
  }
}

function buildAdminBubble(msg) {
  const isAdmin = msg.sender === 'admin';
  const wrap = document.createElement('div');
  wrap.className = 'admin-bubble-wrap ' + (isAdmin ? 'from-admin' : 'from-user');
  wrap.dataset.id = msg.id;
  const time = msg.created_at.substring(11,16);
  wrap.innerHTML =
    '<div class="admin-bubble ' + (isAdmin ? 'from-admin' : 'from-user') + '">' + escHtmlA(msg.message) + '</div>' +
    '<div class="admin-bubble-time">' + (isAdmin ? 'You · ' : 'User · ') + time + '</div>';
  return wrap;
}

async function adminClearThread() {
  if (!adminChat.userId) return;
  const name = document.getElementById('admin-chat-name')?.textContent || 'this player';
  if (!confirm('Clear all messages with ' + name + '?\n\nThis permanently deletes the entire conversation and cannot be undone.')) return;
  const d = await apiFetch('chat_clear_thread', 'POST', { user_id: adminChat.userId });
  if (d.success) {
    document.getElementById('admin-chat-messages').innerHTML =
      '<div style="color:var(--text2);font-size:15px;text-align:center;padding:24px">Conversation cleared.</div>';
    adminChat.lastId = 0;
    toast('Thread cleared', 'ok');
    loadChatBadge();
  } else toast(d.error || 'Error', 'err');
}

async function adminClearAllChats() {
  if (!confirm('Clear ALL chat messages from ALL players?\n\nThis permanently deletes every conversation and cannot be undone.')) return;
  if (!confirm('Are you absolutely sure? This will remove all chat history for every player.')) return;
  const d = await apiFetch('chat_clear_all', 'POST', {});
  if (d.success) {
    toast('All chats cleared', 'ok');
    showChatInbox();
    loadChatInbox();
    loadChatBadge();
  } else toast(d.error || 'Error', 'err');
}

async function adminSendMsg() {
  const input = document.getElementById('admin-chat-input');
  const msg   = input.value.trim();
  if (!msg || !adminChat.userId) return;
  input.value = '';

  const container = document.getElementById('admin-chat-messages');
  const tempWrap = buildAdminBubble({ id: 'temp_' + Date.now(), sender:'admin', message:msg, created_at: new Date().toISOString().replace('T',' ').substring(0,19) });
  tempWrap.style.opacity = '0.65';
  container.appendChild(tempWrap);
  container.scrollTop = container.scrollHeight;

  const d = await apiFetch('chat_admin_send','POST',{ user_id: adminChat.userId, message: msg });
  if (d.success) {
    tempWrap.style.opacity = '1';
    tempWrap.dataset.id = d.id;
    adminChat.lastId = Math.max(adminChat.lastId, d.id);
    loadChatBadge();
  } else {
    tempWrap.remove();
    input.value = msg;
    toast('Send failed','err');
  }
}

async function loadChatBadge() {
  const d = await apiFetch('chat_unread');
  if (d.success) {
    const b     = document.getElementById('badge-chat');
    const alert = document.getElementById('unread-chat-alert');
    const count = document.getElementById('unread-chat-alert-count');
    const text  = document.getElementById('unread-chat-alert-text');
    if (b) { b.textContent = d.count; b.style.display = d.count > 0 ? 'inline-block' : 'none'; }
    if (alert) alert.style.display = d.count > 0 ? 'flex' : 'none';
    if (count) count.textContent = d.count;
    if (text)  text.textContent  = d.count + ' unread message' + (d.count !== 1 ? 's' : '') + ' waiting for a response';
  }
}

function formatAdminTime(dt) {
  if (!dt) return '';
  const d = new Date(dt.replace(' ','T'));
  const now = new Date();
  const diff = (now - d) / 1000;
  if (diff < 60) return 'Just now';
  if (diff < 3600) return Math.floor(diff/60) + 'm ago';
  if (diff < 86400) return d.toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit'});
  return d.toLocaleDateString('en-US',{month:'short',day:'numeric'});
}

function formatAdminDateLabel(dateStr) {
  const d = new Date(dateStr + 'T00:00:00');
  const today = new Date(); today.setHours(0,0,0,0);
  const diff = Math.round((today - d) / 86400000);
  if (diff === 0) return 'Today';
  if (diff === 1) return 'Yesterday';
  return d.toLocaleDateString('en-US',{weekday:'long',month:'short',day:'numeric'});
}

function escHtmlA(s) { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\n/g,'<br>'); }

function openFieldUrl(inputId) {
  const url = document.getElementById(inputId)?.value?.trim();
  if (!url) return false;
  window.open(url, '_blank', 'noopener');
  return false;
}

function copyToClipboard(text, btn) {
  navigator.clipboard.writeText(text).then(() => {
    const orig = btn.innerHTML;
    btn.innerHTML = '✅ Copied';
    btn.style.background = 'rgba(0,230,118,0.15)';
    btn.style.borderColor = 'rgba(0,230,118,0.4)';
    btn.style.color = 'var(--green)';
    setTimeout(() => {
      btn.innerHTML = orig;
      btn.style.background = '';
      btn.style.borderColor = '';
      btn.style.color = '';
    }, 1800);
  }).catch(() => toast('Copy failed — try manually','err'));
}
function escAttr(s) { return String(s||'').replace(/'/g,"\\'").replace(/"/g,'&quot;'); }

// Poll chat badge every 10s
setInterval(loadChatBadge, 10000);
loadChatBadge();

</script>
<div style="position:fixed;bottom:8px;right:12px;font-size:14px;color:rgba(255,255,255,.2);font-family:'Exo 2',sans-serif;pointer-events:none;z-index:999">
  TomTomGames Admin v1.0.0
</div>
</body>
</html>
