// panels-a.jsx — Dashboard, Console, Logs, Players

// ────────────────────────────────────────────────────────────────
// Dashboard
// ────────────────────────────────────────────────────────────────
function DashboardPanel({ srv }) {
  const players = React.useMemo(() => genSeries(7, 48, 8, 5).map((v) => Math.max(0, Math.min(12, v))), []);
  const cpu     = React.useMemo(() => genSeries(11, 48, 18, 6).map((v) => Math.max(2, Math.min(70, v))), []);
  const ram     = React.useMemo(() => genSeries(13, 48, 38, 4).map((v) => Math.max(20, Math.min(70, v))), []);
  const tick    = React.useMemo(() => genSeries(17, 48, 128, 1.4).map((v) => Math.max(110, Math.min(130, v))), []);
  const [pwd, setPwd]   = React.useState(false);
  const [mode, setMode] = React.useState('match');

  return (
    <div>
      <div className="panel-head">
        <div>
          <h1>Dashboard</h1>
          <div className="sub">{srv.name} <span className="fg3">·</span> {srv.addr} <span className="fg3">·</span> connected via rcon</div>
        </div>
        <div className="tools">
          <span className="badge ok pulsing"><span className="dot" />live</span>
          <button className="btn"><span className="ico">{I.reload}</span>Refresh</button>
        </div>
      </div>

      <div className="body">
        {/* Stat row */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12 }}>
          <Stat label="Players"  value="9 / 12" delta="+2" foot="last 5m" />
          <Stat label="Tick rate" value="127.8" unit="hz" foot="target 128"/>
          <Stat label="CPU"      value="22" unit="%" foot="4-core · 0.88 load avg"/>
          <Stat label="RAM"      value="2.1 / 8" unit="GB" foot="resident"/>
        </div>

        {/* Two-col: round info + sparkline + actions */}
        <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 12, marginTop: 12 }}>
          <div className="card">
            <div className="ch">
              <div className="t">Current round</div>
              <div className="meta">tick #{(127.8 * 60 * 11 + 4321).toFixed(0).slice(-6)} · uptime 11h 02m</div>
            </div>
            <div className="cb" style={{ display: 'grid', gridTemplateColumns: '170px 1fr', gap: 18 }}>
              <div className="map-card" style={{ aspectRatio: '16/10' }}>
                <div className="map-thumb"><MapThumb id="de_mirage" /></div>
                <div className="map-foot">
                  <span className="name">de_mirage</span>
                  <span className="mode">competitive</span>
                </div>
              </div>
              <dl className="kv" style={{ alignContent: 'center' }}>
                <dt>map</dt>          <dd>de_mirage <span className="fg3">(active pool)</span></dd>
                <dt>gamemode</dt>     <dd>competitive · MR12 + OT</dd>
                <dt>round</dt>        <dd>8 / 24  <span className="fg2">— CT 4 : 3 T</span></dd>
                <dt>round time</dt>   <dd>0:47 <span className="fg3">remaining</span></dd>
                <dt>warmup</dt>       <dd className="ac">ended · live</dd>
                <dt>session</dt>      <dd>2h 14m · matchzy "live"</dd>
              </dl>
            </div>
          </div>

          <div className="card">
            <div className="ch">
              <div className="t">Quick actions</div>
            </div>
            <div className="cb" style={{ display: 'grid', gap: 8 }}>
              <button className="btn"><span className="ico">{I.reload}</span>Restart server</button>
              <div className="seg" style={{ width: '100%' }}>
                <button className={mode === 'match' ? 'on' : ''} onClick={() => setMode('match')} style={{ flex: 1 }}>match</button>
                <button className={mode === 'prac'  ? 'on' : ''} onClick={() => setMode('prac')}  style={{ flex: 1 }}>practice</button>
                <button className={mode === 'pug'   ? 'on' : ''} onClick={() => setMode('pug')}   style={{ flex: 1 }}>pug</button>
              </div>
              <button className="btn" onClick={() => setPwd(!pwd)}>
                <span className="ico">{pwd ? I.lock : I.unlock}</span>
                {pwd ? 'Password set — ••••••' : 'No password'}
              </button>
              <button className="btn"><span className="ico">{I.bolt}</span>End warmup</button>
              <button className="btn"><span className="ico">{I.users}</span>Auto-shuffle teams</button>
              <button className="btn danger"><span className="ico">{I.power}</span>Stop server</button>
            </div>
          </div>
        </div>

        {/* Graphs */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginTop: 12 }}>
          <div className="card">
            <div className="ch">
              <div className="t"><span className="ico">{I.users}</span>Players</div>
              <div className="meta">24h</div>
            </div>
            <div className="cb" style={{ paddingTop: 8 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 22 }}>9<span className="fg3"> / 12</span></div>
              <div style={{ marginTop: 2, color: 'var(--ac)' }}>
                <Spark data={players} color="var(--ac)" />
              </div>
              <div className="fg3 m" style={{ fontSize: 11 }}>peak 12 · avg 6.4</div>
            </div>
          </div>
          <div className="card">
            <div className="ch">
              <div className="t"><span className="ico">{I.cpu}</span>CPU</div>
              <div className="meta">5m</div>
            </div>
            <div className="cb" style={{ paddingTop: 8 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 22 }}>22<span className="fg3">%</span></div>
              <div style={{ marginTop: 2, color: '#8acff7' }}><Spark data={cpu} color="#8acff7" /></div>
              <div className="fg3 m" style={{ fontSize: 11 }}>peak 41% · sustained 28%</div>
            </div>
          </div>
          <div className="card">
            <div className="ch">
              <div className="t"><span className="ico">{I.ram}</span>Memory</div>
              <div className="meta">5m</div>
            </div>
            <div className="cb" style={{ paddingTop: 8 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 22 }}>2.1<span className="fg3"> GB</span></div>
              <div style={{ marginTop: 2, color: '#c6a6ff' }}><Spark data={ram} color="#c6a6ff" /></div>
              <div className="fg3 m" style={{ fontSize: 11 }}>26% of 8 GB</div>
            </div>
          </div>
          <div className="card">
            <div className="ch">
              <div className="t"><span className="ico">{I.pulse}</span>Tick</div>
              <div className="meta">5m</div>
            </div>
            <div className="cb" style={{ paddingTop: 8 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 22 }}>127.8<span className="fg3"> hz</span></div>
              <div style={{ marginTop: 2, color: '#f4c98a' }}><Spark data={tick} color="#f4c98a" /></div>
              <div className="fg3 m" style={{ fontSize: 11 }}>target 128 · jitter 0.4</div>
            </div>
          </div>
        </div>

        {/* stats RCON dump + recent events */}
        <div style={{ display: 'grid', gridTemplateColumns: '1.1fr 1fr', gap: 12, marginTop: 12 }}>
          <div className="card">
            <div className="ch">
              <div className="t"><span className="ico">{I.term}</span>stats <span className="fg3 m" style={{ fontSize: 11, marginLeft: 4 }}>// rcon dump</span></div>
              <div className="meta">refreshed 4s ago</div>
            </div>
            <div className="cb m" style={{ fontSize: 12, color: 'var(--fg-1)', lineHeight: 1.6 }}>
              <pre style={{ margin: 0, fontFamily: 'inherit', whiteSpace: 'pre-wrap' }}>
{`CPU    NetIn   NetOut    Uptime    Maps   FPS   Players  Svms   +-ms   ~tick
22.0   18.4    61.7      11h02m    14     127.8 9        7.42   0.40   127.8`}
              </pre>
              <hr className="hr" style={{ margin: '10px 0' }} />
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6, fontSize: 11 }}>
                <div><span className="fg2">version:</span> 1.40.6.3 (cs2)</div>
                <div><span className="fg2">protocol:</span> v15 / build 9462</div>
                <div><span className="fg2">os:</span> linux x86_64 (debian 12)</div>
                <div><span className="fg2">vac:</span> <span className="ok">secure</span></div>
                <div><span className="fg2">gotv:</span> 1× spec on :27020</div>
                <div><span className="fg2">workshop:</span> 16 maps · 281 MB</div>
              </div>
            </div>
          </div>
          <div className="card">
            <div className="ch">
              <div className="t"><span className="ico">{I.bolt}</span>Recent events</div>
              <div className="meta"><a className="ac">view all →</a></div>
            </div>
            <div style={{ padding: 0 }}>
              <ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
                {[
                  { t: '12:51', a: 'm0use@', b: 'ended warmup', kind: 'ac' },
                  { t: '12:49', a: 'jaeger', b: 'kicked h4rdy_woods — afk', kind: 'warn' },
                  { t: '12:40', a: 'm0use@', b: 'changed map: de_mirage', kind: 'info' },
                  { t: '12:38', a: 'jaeger', b: 'applied preset: MR12 (24+OT)', kind: 'ac' },
                  { t: '12:35', a: 'm0use@', b: 'edited gamemode_competitive.cfg', kind: 'info' },
                  { t: '12:18', a: 'system', b: 'GotvFix: bind failure', kind: 'err' },
                ].map((e, i) => (
                  <li key={i} style={{ display: 'grid', gridTemplateColumns: '48px 1fr', gap: 12, padding: '8px 14px', borderBottom: '1px solid var(--br)', fontSize: 12 }}>
                    <span className="m fg3">{e.t}</span>
                    <div><span className={"m " + (e.kind === 'err' ? 'fg2' : 'fg2')}>{e.a}</span> <span className="fg">{e.b}</span></div>
                  </li>
                ))}
              </ul>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────
// RCON Console
// ────────────────────────────────────────────────────────────────
function ConsolePanel() {
  const [lines, setLines] = React.useState(CONSOLE_HISTORY);
  const [input, setInput] = React.useState('mp_war');
  const [histIdx, setHistIdx] = React.useState(-1);
  const [acIdx, setAcIdx]     = React.useState(0);
  const inputRef = React.useRef(null);
  const outRef = React.useRef(null);

  const completions = React.useMemo(() => {
    const q = input.trim().toLowerCase();
    if (!q) return [];
    return CVAR_DICT.filter((c) => c.name.startsWith(q)).slice(0, 8);
  }, [input]);

  React.useEffect(() => { setAcIdx(0); }, [completions.length]);
  React.useEffect(() => { outRef.current?.scrollTo(0, outRef.current.scrollHeight); }, [lines.length]);

  const onKey = (e) => {
    if (e.key === 'Tab' && completions[acIdx]) { e.preventDefault(); setInput(completions[acIdx].name + ' '); }
    else if (e.key === 'ArrowDown' && completions.length) { e.preventDefault(); setAcIdx((acIdx + 1) % completions.length); }
    else if (e.key === 'ArrowUp' && completions.length)   { e.preventDefault(); setAcIdx((acIdx - 1 + completions.length) % completions.length); }
    else if (e.key === 'Enter' && input.trim()) {
      setLines((ls) => [...ls, { kind: 'rcon', txt: input.trim() }, { kind: 'out', txt: '(simulated reply)' }]);
      setInput('');
    }
  };

  return (
    <div>
      <div className="panel-head">
        <div>
          <h1>RCON Console</h1>
          <div className="sub">tab to autocomplete · ↑↓ history · ctrl-l clears</div>
        </div>
        <div className="tools">
          <div className="seg">
            <button className="on">live</button>
            <button>paused</button>
          </div>
          <button className="btn"><span className="ico">{I.copy}</span>Copy session</button>
          <button className="btn"><span className="ico">{I.download}</span>Export</button>
        </div>
      </div>

      <div className="body" style={{ display: 'grid', gridTemplateColumns: '1fr 280px', gap: 12, height: 'calc(100vh - var(--hdr-h) - var(--foot-h) - 96px)' }}>
        <div className="term" style={{ position: 'relative' }}>
          <div className="out" ref={outRef}>
            {lines.map((l, i) => {
              if (l.kind === 'rcon') return (
                <div key={i} className="ln">
                  <span className="tag">rcon</span><span className="ts"> 12:5{i}:0{i % 9}</span>
                  <span> &gt; </span><span style={{ color: 'var(--fg)' }}>{l.txt}</span>
                </div>
              );
              if (l.kind === 'sys') return <div key={i} className="ln dim">— {l.txt} —</div>;
              return <div key={i} className="ln">{syntaxColor(l.txt)}</div>;
            })}
          </div>
          <div className="input-row">
            <span className="prompt">rcon&nbsp;❯</span>
            <input ref={inputRef} value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={onKey}
                   placeholder="type a command — try mp_warmup_end, status, sv_password" />
            <kbd style={{ color: 'var(--fg-3)' }}>⏎</kbd>
          </div>
          {completions.length > 0 && (
            <div className="acpop">
              {completions.map((c, i) => (
                <div key={c.name} className={"ac-row " + (i === acIdx ? 'on' : '')} onMouseEnter={() => setAcIdx(i)}
                     onClick={() => setInput(c.name + ' ')}>
                  <span className="cv">{c.name}</span>
                  <span className="vl">= {c.val}</span>
                  <span className="ty">{c.ty}</span>
                  {i === acIdx && <div className="desc">{c.desc}</div>}
                </div>
              ))}
            </div>
          )}
        </div>

        <div className="card" style={{ overflow: 'auto' }}>
          <div className="ch"><div className="t"><span className="ico">{I.bolt}</span>RCON macros</div></div>
          <div className="cb" style={{ display: 'grid', gap: 6 }}>
            {[
              { n: 'warmup → live',    c: 'mp_warmuptime 15 ; mp_warmup_end' },
              { n: 'reset score',      c: 'mp_restartgame 1' },
              { n: 'knife → side pick',c: 'matchzy_knife' },
              { n: 'pause match',      c: 'matchzy_pause' },
              { n: 'kick all bots',    c: 'bot_kick' },
              { n: 'demo: start',      c: 'tv_record demos/manual_{ts}' },
              { n: 'demo: stop',       c: 'tv_stoprecord' },
              { n: 'fix stuck round',  c: 'mp_unpause_match ; mp_warmup_end' },
            ].map((m, i) => (
              <button key={i} className="btn" style={{ justifyContent: 'flex-start', height: 30, padding: '0 10px' }}>
                <span style={{ flex: 1, textAlign: 'left' }}>{m.n}</span>
                <span className="m fg3" style={{ fontSize: 10, maxWidth: 130, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.c}</span>
              </button>
            ))}
            <button className="btn ghost" style={{ justifyContent: 'flex-start', color: 'var(--fg-2)' }}>
              <span className="ico">{I.plus}</span>New macro…
            </button>
          </div>

          <div className="ch" style={{ borderTop: '1px solid var(--br)' }}>
            <div className="t"><span className="ico">{I.clock}</span>History</div>
          </div>
          <div className="cb" style={{ paddingTop: 4, fontFamily: 'var(--mono)', fontSize: 11.5 }}>
            {['status', 'mp_warmuptime 15', 'sv_password', 'mp_warmup_end', 'changelevel de_inferno', 'tv_record demos/2026-05-21'].map((h, i) => (
              <div key={i} style={{ padding: '4px 4px', color: 'var(--fg-2)', cursor: 'default' }}
                   onMouseEnter={(e) => e.currentTarget.style.color = 'var(--fg)'} onMouseLeave={(e) => e.currentTarget.style.color = 'var(--fg-2)'}>
                <span className="fg3">›</span> {h}
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}
function syntaxColor(txt) {
  // very lightweight: highlight quoted strings, numbers, and cvar-looking tokens
  const parts = [];
  let i = 0; let key = 0;
  const push = (cls, s) => parts.push(<span key={key++} className={cls}>{s}</span>);
  const re = /"([^"]*)"|(-?\d+(?:\.\d+)?)|((?:mp_|sv_|host_|matchzy_|tv_|cl_|bot_)[a-z_]+)/g;
  let m, last = 0;
  while ((m = re.exec(txt))) {
    if (m.index > last) push('', txt.slice(last, m.index));
    if (m[1] !== undefined) push('str', `"${m[1]}"`);
    else if (m[2] !== undefined) push('num', m[2]);
    else if (m[3] !== undefined) push('cv', m[3]);
    last = re.lastIndex;
  }
  if (last < txt.length) push('', txt.slice(last));
  return <>{parts}</>;
}

// ────────────────────────────────────────────────────────────────
// Live Logs
// ────────────────────────────────────────────────────────────────
function LogsPanel() {
  const [tab, setTab] = React.useState('all');
  const [hideRcon, setHideRcon] = React.useState(false);
  const [q, setQ] = React.useState('');
  const [conn, setConn] = React.useState('LIVE'); // LIVE | RECONNECTING | OFFLINE

  const filtered = React.useMemo(() => {
    let r = LOG_LINES;
    if (tab === 'chat')  r = r.filter((l) => l.cat === 'chat');
    if (tab === 'kill')  r = r.filter((l) => l.cat === 'kill');
    if (tab === 'round') r = r.filter((l) => l.cat === 'round' || l.cat === 'world');
    if (tab === 'conn')  r = r.filter((l) => l.cat === 'conn' || l.cat === 'team');
    if (hideRcon) r = r.filter((l) => l.cat !== 'rcon');
    if (q) r = r.filter((l) => l.txt.toLowerCase().includes(q.toLowerCase()));
    return r;
  }, [tab, hideRcon, q]);

  return (
    <div>
      <div className="panel-head">
        <div>
          <h1>Live Logs</h1>
          <div className="sub">srcds_logaddress · SSE to nokit-relay · {LOG_LINES.length} retained · {filtered.length} shown</div>
        </div>
        <div className="tools">
          <span className={"badge " + (conn === 'LIVE' ? 'ok pulsing' : conn === 'RECONNECTING' ? 'warn' : 'err')}>
            <span className="dot" />{conn}
          </span>
          <button className="btn" onClick={() => setConn(conn === 'LIVE' ? 'OFFLINE' : 'LIVE')}>
            <span className="ico">{conn === 'LIVE' ? I.pause : I.play}</span>{conn === 'LIVE' ? 'Pause' : 'Resume'}
          </button>
          <button className="btn"><span className="ico">{I.download}</span>Download .log</button>
        </div>
      </div>

      <div className="tabs">
        {[
          ['all', 'All', LOG_LINES.length],
          ['chat', 'Chat', LOG_LINES.filter(l => l.cat === 'chat').length],
          ['kill', 'Kills', LOG_LINES.filter(l => l.cat === 'kill').length],
          ['round', 'Rounds', LOG_LINES.filter(l => l.cat === 'round' || l.cat === 'world').length],
          ['conn', 'Connect / team', LOG_LINES.filter(l => l.cat === 'conn' || l.cat === 'team').length],
          ['plug', 'Plugin', LOG_LINES.filter(l => l.cat === 'plug').length],
        ].map(([k, l, n]) => (
          <button key={k} className={tab === k ? 'on' : ''} onClick={() => setTab(k)}>
            {l}<span className="badge" style={{ height: 16, fontSize: 9, padding: '0 5px' }}>{n}</span>
          </button>
        ))}
      </div>

      <div className="body">
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12 }}>
          <div className="input" style={{ minWidth: 280, flex: 1, maxWidth: 480 }}>
            <span className="ico">{I.search}</span>
            <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="grep — e.g. STEAM_1:0, &quot;awp&quot;, defused" />
            <kbd>/</kbd>
          </div>
          <label className="chip" onClick={() => setHideRcon(!hideRcon)} style={{ cursor: 'default' }}>
            <span className={"chk " + (hideRcon ? 'on' : '')}>{hideRcon && <span style={{ fontSize: 10 }}>✓</span>}</span>
            hide rcon noise
          </label>
          <div className="grow" />
          <span className="hint m">tail –f · 1.4k lines/min</span>
        </div>

        <div className="term" style={{ height: 'calc(100vh - var(--hdr-h) - var(--foot-h) - 240px)' }}>
          <div className="out">
            {filtered.map((l, i) => (
              <div key={i} className="ln">
                <span className="ts">{l.ts}</span>
                <span className={catTone(l.cat)}>{l.cat.padEnd(5, ' ')}</span>
                <span>  {syntaxColor(l.txt)}</span>
              </div>
            ))}
            {Array.from({ length: 24 }).map((_, i) => (
              <div key={'b' + i} className="ln dim">{' '}</div>
            ))}
          </div>
          <div className="input-row" style={{ background: '#08080a' }}>
            <span className="prompt" style={{ color: 'var(--fg-3)' }}>tail&nbsp;❯</span>
            <span className="m fg3" style={{ flex: 1, fontSize: 11.5 }}>awaiting next event · backpressure 0 · last frame 1.2s ago</span>
            <span className="badge ac"><span className="dot" />SSE</span>
          </div>
        </div>
      </div>
    </div>
  );
}
function catTone(cat) {
  const m = { rcon: 'tag', chat: 'info', kill: 'err', round: 'ok', world: 'ok', conn: 'warn', team: 'warn', plug: 'cv', srv: 'dim' };
  return m[cat] || 'dim';
}

// ────────────────────────────────────────────────────────────────
// Players
// ────────────────────────────────────────────────────────────────
function PlayersPanel() {
  const [tab, setTab] = React.useState('live');
  const [q, setQ] = React.useState('');

  return (
    <div>
      <div className="panel-head">
        <div>
          <h1>Players</h1>
          <div className="sub">auto-refresh every 4s · {PLAYERS.length} online · {WATCHLIST.length} on watchlist · {BANS.length} bans</div>
        </div>
        <div className="tools">
          <button className="btn"><span className="ico">{I.users}</span>Auto-shuffle</button>
          <button className="btn"><span className="ico">{I.bolt}</span>Mass kick…</button>
          <button className="btn primary"><span className="ico">{I.plus}</span>Add to watchlist</button>
        </div>
      </div>

      <div className="tabs">
        <button className={tab === 'live' ? 'on' : ''} onClick={() => setTab('live')}>Live<span className="badge ok">{PLAYERS.length}</span></button>
        <button className={tab === 'watch' ? 'on' : ''} onClick={() => setTab('watch')}>Watchlist<span className="badge warn">{WATCHLIST.length}</span></button>
        <button className={tab === 'bans' ? 'on' : ''} onClick={() => setTab('bans')}>Bans<span className="badge err">{BANS.length}</span></button>
        <button className={tab === 'history' ? 'on' : ''} onClick={() => setTab('history')}>Session history</button>
      </div>

      <div className="body">
        <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
          <div className="input" style={{ flex: 1, maxWidth: 420 }}>
            <span className="ico">{I.search}</span>
            <input placeholder="search name, steamid, country, notes" value={q} onChange={(e) => setQ(e.target.value)} />
          </div>
          <div className="seg">
            <button className="on">all</button><button>CT</button><button>T</button><button>spec</button>
          </div>
          <div className="grow" />
          <button className="btn"><span className="ico">{I.filter}</span>Filter</button>
        </div>

        {tab === 'live' && <LivePlayers q={q} />}
        {tab === 'watch' && <WatchTable />}
        {tab === 'bans' && <BanTable />}
        {tab === 'history' && (
          <div className="card"><div className="cb fg2" style={{ padding: 24, textAlign: 'center' }}>
            No session history pruned yet. Last 30d retained.
          </div></div>
        )}
      </div>
    </div>
  );
}

function LivePlayers({ q }) {
  const rows = PLAYERS.filter((p) => !q || (p.name + p.steam + p.country + (p.notes || '')).toLowerCase().includes(q.toLowerCase()));
  return (
    <div className="card">
      <table className="tbl">
        <thead><tr>
          <th style={{ width: 28 }}></th>
          <th>Name</th>
          <th>SteamID</th>
          <th>Team</th>
          <th>Ping</th>
          <th>Time</th>
          <th>K/D</th>
          <th>Country</th>
          <th></th>
        </tr></thead>
        <tbody>
        {rows.map((p) => (
          <tr key={p.steam}>
            <td>{p.flagged
                  ? <span className="ac" title={p.notes}>{I.flag}</span>
                  : <span className="fg3">·</span>}</td>
            <td className="fg">
              {p.name}
              {p.flagged && <span className="badge warn" style={{ marginLeft: 8 }}>watch</span>}
            </td>
            <td className="muted">{p.steam}</td>
            <td className={p.team === 'CT' ? 'fg2' : 'fg2'}>
              <span className="badge" style={{
                color: p.team === 'CT' ? 'var(--info)' : 'var(--warn)',
                background: p.team === 'CT' ? 'var(--info-soft)' : 'var(--warn-soft)',
                borderColor: 'transparent',
              }}>{p.team}</span>
            </td>
            <td className="num" style={{ color: p.ping > 60 ? 'var(--warn)' : 'var(--fg-1)' }}>{p.ping}ms</td>
            <td className="muted num">{p.time}</td>
            <td className="num">{p.kd}</td>
            <td className="muted"><Flag c={p.country} />{p.country}</td>
            <td>
              <div className="row-acts">
                <button className="btn sm ghost">profile</button>
                <button className="btn sm">spectate</button>
                <button className="btn sm">kick</button>
                <button className="btn sm danger">ban…</button>
              </div>
            </td>
          </tr>
        ))}
        </tbody>
      </table>
    </div>
  );
}

function WatchTable() {
  return (
    <div className="card">
      <table className="tbl">
        <thead><tr>
          <th style={{ width: 28 }}></th>
          <th>Name</th><th>SteamID</th><th>Reason</th><th>Status</th><th></th>
        </tr></thead>
        <tbody>
        {WATCHLIST.map((w) => (
          <tr key={w.steam}>
            <td><span style={{ color: 'var(--warn)' }}>{I.flag}</span></td>
            <td className="fg">{w.name}</td>
            <td className="muted">{w.steam}</td>
            <td className="muted" style={{ fontFamily: 'var(--sans)' }}>{w.reason}</td>
            <td>
              {w.online
                ? <span className="badge ok pulsing"><span className="dot" />online · this server</span>
                : <span className="badge"><span className="dot" />offline</span>}
            </td>
            <td>
              <div className="row-acts">
                <button className="btn sm">edit note</button>
                <button className="btn sm danger">remove</button>
              </div>
            </td>
          </tr>
        ))}
        </tbody>
      </table>
    </div>
  );
}

function BanTable() {
  return (
    <div className="card">
      <table className="tbl">
        <thead><tr>
          <th>Name</th><th>SteamID</th><th>Reason</th><th>By</th><th>Expires</th><th></th>
        </tr></thead>
        <tbody>
        {BANS.map((b) => (
          <tr key={b.steam}>
            <td className="fg">{b.name}</td>
            <td className="muted">{b.steam}</td>
            <td className="muted" style={{ fontFamily: 'var(--sans)' }}>{b.reason}</td>
            <td>{b.by}</td>
            <td>
              {b.perm
                ? <span className="badge err">permanent</span>
                : <span className="badge warn">{b.expires}</span>}
            </td>
            <td>
              <div className="row-acts">
                <button className="btn sm">edit</button>
                <button className="btn sm">unban</button>
              </div>
            </td>
          </tr>
        ))}
        </tbody>
      </table>
    </div>
  );
}

Object.assign(window, { DashboardPanel, ConsolePanel, LogsPanel, PlayersPanel });
