/* global React, ReactDOM, Jersey, KitBadge, TradeView, PortfolioView, BlockTicker, MusicToggle, LangContext, useT, useLang, Ball, Bnb, Logo, PlayerToon */
const { useState, useEffect, useMemo } = React;

// ============ Helpers ============
const fmtPrice = (n) => n < 0.0001 ? n.toExponential(2) : n.toFixed(5);
const fmtBNB = (n, d = 2) => n >= 1000 ? n.toFixed(0) : n >= 10 ? n.toFixed(1) : n.toFixed(d);
const fmtNum = (n) => n.toLocaleString("en-US");
const fmtVolume = (n) => n >= 1_000_000 ? (n/1_000_000).toFixed(2) + "M" : n >= 1_000 ? (n/1_000).toFixed(2) + "K" : n.toFixed(0);

// Live BNB/USD price — refreshed from Binance ticker every 60s.
// Stored on window so trade-view.jsx and portfolio.jsx can read it too.
if (typeof window.BNB_USD !== "number") window.BNB_USD = 612;
async function refreshBnbPrice() {
  try {
    const r = await fetch("https://api.binance.com/api/v3/ticker/price?symbol=BNBUSDT");
    const d = await r.json();
    const p = parseFloat(d.price);
    if (p > 0) window.BNB_USD = p;
  } catch (e) {}
}
refreshBnbPrice();
setInterval(refreshBnbPrice, 60_000);

// Price → $X.YZ string. Auto-adjusts decimals based on magnitude.
// For very small (memecoin) prices uses DexScreener-style subscript zeros:
// e.g. $0.00001912 → "$0.0₄1912" where ₄ = "four leading zeros".
const SUBS = ["₀","₁","₂","₃","₄","₅","₆","₇","₈","₉"];
function fmtUsdPrice(bnb) {
  const usd = (Number(bnb) || 0) * (window.BNB_USD || 612);
  if (usd === 0) return "$0";
  if (usd >= 1000) return "$" + usd.toFixed(0);
  if (usd >= 100)  return "$" + usd.toFixed(2);
  if (usd >= 1)    return "$" + usd.toFixed(3);
  if (usd >= 0.01) return "$" + usd.toFixed(4);
  if (usd >= 0.001) return "$" + usd.toFixed(5);
  // Sub-cent memecoin format: collapse leading zeros to a subscript count.
  const exp = usd.toExponential(3);                  // "1.912e-5"
  const m = exp.match(/^(\d)\.(\d+)e-(\d+)$/);
  if (!m) return "$" + usd.toFixed(8);
  const digits = (m[1] + m[2]).replace(/0+$/, "");   // "1912"
  const leading = parseInt(m[3], 10) - 1;            // 4 zeros after "0."
  if (leading < 1) return "$" + usd.toFixed(6);
  const zsub = String(leading).split("").map(d => SUBS[+d]).join("");
  return "$0.0" + zsub + digits.slice(0, 4);
}
window.fmtUsdPrice = fmtUsdPrice;

// Tiny inline nav icons — small enough to never crop, replace squashed emoji.
const NavMarketsIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="nav-ic"><path d="M3 17 L9 11 L13 15 L21 7"/><path d="M14 7 L21 7 L21 14"/></svg>
);
const NavGoalIcon = () => (
  <img src="assets/silver.png" width="16" height="16" alt="" className="nav-ic" style={{borderRadius:'50%',background:'#000',objectFit:'cover'}} />
);
const NavGainersIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="nav-ic"><path d="M3 18 L9 12 L13 16 L21 6 M21 6 L21 11 M21 6 L16 6"/></svg>
);
const NavTrophyIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" className="nav-ic" aria-hidden="true">
    <path d="M7 4 H17 V8 Q17 12.5 12 12.5 Q7 12.5 7 8 Z" fill="#f0b90b" stroke="#8a6500" strokeWidth="0.6"/>
    <path d="M7 5 Q4 5 4 8 Q4 10 7 10 M17 5 Q20 5 20 8 Q20 10 17 10" fill="none" stroke="#f0b90b" strokeWidth="1.5"/>
    <rect x="10.5" y="12.5" width="3" height="3" fill="#c79100"/>
    <rect x="8" y="15" width="8" height="2" rx="0.4" fill="#f0b90b"/>
    <rect x="6" y="17" width="12" height="2" rx="0.4" fill="#f0b90b"/>
  </svg>
);
const NavBriefcaseIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" className="nav-ic"><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M9 7 V5 a1 1 0 0 1 1 -1 h4 a1 1 0 0 1 1 1 V7"/><path d="M3 12 H21"/></svg>
);
const NavShieldIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" className="nav-ic" aria-hidden="true">
    <defs>
      <linearGradient id="nav-sh-g" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%"  stopColor="#22e08e"/>
        <stop offset="100%" stopColor="#0a7c44"/>
      </linearGradient>
    </defs>
    <path d="M12 2 L20 5 L20 12 Q20 18 12 22 Q4 18 4 12 L4 5 Z" fill="url(#nav-sh-g)" stroke="#0ecb81" strokeWidth="0.6"/>
    <path d="M8 12 L11 15 L16 9" stroke="#04140a" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
  </svg>
);

// Player name component — shows Chinese + English depending on language
function PlayerName({ p, both = false, size = "md" }) {
  const lang = useLang();
  if (lang === "zh") {
    return (
      <span className={`pn pn-${size}`}>
        <span className="pn-primary">{p.nameZh || p.name}</span>
        {both !== false && <span className="pn-secondary">{p.shortName || p.name}</span>}
      </span>
    );
  }
  return <span className={`pn pn-${size} pn-primary`}>{p.name}</span>;
}

function CountryName({ p }) {
  const lang = useLang();
  return <span>{lang === "zh" ? (p.countryZh || p.country) : p.country}</span>;
}

function ClubName({ p }) {
  const lang = useLang();
  return <span>{lang === "zh" ? (p.clubZh || p.club) : p.club}</span>;
}

// Real 24h stats — populated by the trades-fetch hook below. For untraded tokens
// or when trade history isn't yet loaded, returns zeros (real state, no fake
// derivation from id seed).
const _stats24h = new Map(); // symbol -> { change24, high24, low24, volume24 }
window.gbSetStats24h = (symbol, stats) => {
  _stats24h.set(symbol, stats);
  // Notify React components (debounced subscribers via the App-level listener)
  try { window.dispatchEvent(new CustomEvent('gb:stats24h', { detail: { symbol } })); } catch (e) {}
};
function deriveStats(p) {
  const cached = _stats24h.get(p.symbol);
  // For untraded tokens or tokens whose reserves netted back to zero, the
  // bonding-curve spot mid stays at the initial price. We surface the
  // last-traded execution price (when available) so the UI matches DEX
  // expectations — what a user actually paid most recently.
  if (cached) {
    return {
      ...cached,
      displayPrice: cached.lastPrice || p.priceBNB || 0,
    };
  }
  return {
    change24: 0,
    high24: p.priceBNB || 0,
    low24: p.priceBNB || 0,
    volume24: 0,
    lastPrice: p.priceBNB || 0,
    displayPrice: p.priceBNB || 0,
  };
}
// Expose so trade-view.jsx (separate <script>) can share the same source of truth.
window.gbDeriveStats24h = deriveStats;

function SearchBox({ onOpen }) {
  const t = useT();
  const lang = useLang();
  const [q, setQ] = useState("");
  const [open, setOpen] = useState(false);

  const results = useMemo(() => {
    const query = q.trim();
    if (!query) return [];
    const lo = query.toLowerCase();
    const nicks = window.PLAYER_NICKNAMES || {};
    return window.PLAYERS.filter(p => {
      const playerNicks = nicks[p.id] || [];
      return (
        p.name.toLowerCase().includes(lo)
        || p.symbol.toLowerCase().includes(lo)
        || p.country.toLowerCase().includes(lo)
        || (p.club && p.club.toLowerCase().includes(lo))
        || (p.nameZh && p.nameZh.includes(query))
        || (p.countryZh && p.countryZh.includes(query))
        || (p.clubZh && p.clubZh.includes(query))
        || String(p.number) === query
        || playerNicks.some(nick => nick.toLowerCase().includes(lo) || nick.includes(query))
      );
    }).slice(0, 8);
  }, [q]);

  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        document.querySelector(".b-search input")?.focus();
      }
      if (e.key === "Escape") setOpen(false);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  return (
    <div className="b-search-wrap">
      <div className="b-search">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
        <input
          placeholder={t("nav.search")}
          value={q}
          onChange={e => { setQ(e.target.value); setOpen(true); }}
          onFocus={() => setOpen(true)}
          onBlur={() => setTimeout(() => setOpen(false), 200)}
        />
        <span className="b-key">⌘ K</span>
      </div>
      {open && q && (
        <div className="b-search-pop">
          {results.length === 0
            ? <div className="b-search-empty">{lang === "zh" ? "未找到匹配的球员" : "No matching players"}</div>
            : results.map(p => (
                <div key={p.id} className="b-search-item" onMouseDown={(e) => { e.preventDefault(); onOpen(p); setQ(""); setOpen(false); }}>
                  <Jersey kit={p.kit} number={p.number} size={28} />
                  <div className="b-search-item-meta">
                    <div className="b-search-item-name">
                      <span className="mono">${p.symbol}</span>
                      <span className="dim">{lang === "zh" ? (p.nameZh || p.name) : p.name}</span>
                    </div>
                    <div className="b-search-item-sub dim">
                      {lang === "zh" ? (p.countryZh || p.country) : p.country} · {lang === "zh" ? (p.clubZh || p.club) : p.club} · #{p.number}
                    </div>
                  </div>
                  <div className="b-search-item-px mono">{fmtUsdPrice(p.priceBNB)}</div>
                </div>
              ))
          }
          <div className="b-search-foot">
            <span className="dim">{lang === "zh" ? "提示:" : "Tip:"}</span>
            <span className="dim">{lang === "zh" ? "可搜姓名 / 代币名 / 国家 / 俱乐部 / 号码" : "name / symbol / country / club / number"}</span>
          </div>
        </div>
      )}
    </div>
  );
}

// ============ Nav ============
function Nav({ onHome, onPortfolio, onJumpToTab, onOpenPlayer, lang, setLang, view }) {
  const t = useT();
  const scroll = (sel) => {
    const el = document.querySelector(sel);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };
  return (
    <header className="b-nav">
      <div className="b-nav-inner">
        <div className="b-brand gb-brand-textlogo" onClick={onHome}>
          <span className="gb-brand-dollar">$</span>GOLDBALL
        </div>
        <nav className="b-nav-tabs">
          <a className={view === "home" ? "active" : ""} onClick={(e) => { e.preventDefault(); if (view !== "home") { onHome(); setTimeout(() => scroll('#markets'), 50); } else { scroll('#markets'); } }}>
            <NavMarketsIcon />{t("nav.markets")}
          </a>
          <a onClick={(e) => { e.preventDefault(); if (view !== "home") { onHome(); setTimeout(() => { onJumpToTab('goals'); scroll('#markets'); }, 50); } else { onJumpToTab('goals'); scroll('#markets'); } }}>
            <NavGoalIcon />{t("nav.goals")}
          </a>
          <a onClick={(e) => { e.preventDefault(); if (view !== "home") { onHome(); setTimeout(() => { onJumpToTab('gainers'); scroll('#markets'); }, 50); } else { onJumpToTab('gainers'); scroll('#markets'); } }}>
            <NavGainersIcon />{t("nav.gainers")}
          </a>
          <a onClick={(e) => { e.preventDefault(); if (view !== "home") { onHome(); setTimeout(() => scroll('#mvp'), 50); } else { scroll('#mvp'); } }}>
            <NavTrophyIcon />{t("nav.mvp")}
          </a>
          <a className={view === "portfolio" ? "active" : ""} onClick={(e) => { e.preventDefault(); onPortfolio(); }}>
            <NavBriefcaseIcon />{t("nav.portfolio")}
          </a>
          <a onClick={(e) => { e.preventDefault(); if (view !== "home") { onHome(); setTimeout(() => scroll('#audit'), 50); } else { scroll('#audit'); } }}>
            <NavShieldIcon />{t("nav.audit")}
          </a>
        </nav>
        <div className="b-nav-right">
          <a href="https://x.com/Goldenballwcp" target="_blank" rel="noopener noreferrer" className="b-x-btn" title="@Goldenballwcp on X">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
          </a>
          <SearchBox onOpen={onOpenPlayer} />
          <div className="b-lang">
            <button className={lang === "zh" ? "active" : ""} onClick={() => setLang("zh")}>中</button>
            <button className={lang === "en" ? "active" : ""} onClick={() => setLang("en")}>EN</button>
          </div>
          <WalletButton />
        </div>
      </div>
    </header>
  );
}

// ============ Wallet Button (real Web3) ============
function WalletButton() {
  const t = useT();
  const lang = useLang();
  const [account, setAccount] = useState(null);
  const [connecting, setConnecting] = useState(false);

  useEffect(() => {
    if (!window.GB) return;
    const unsub = window.GB.onAccountChange(setAccount);
    setAccount(window.GB.account());
    return unsub;
  }, []);

  async function onClick() {
    if (account) { window.GB.disconnect(); return; }
    setConnecting(true);
    try {
      // Reown AppKit modal opens with rich picker (MetaMask + dozens of wallets + WC scan)
      await window.GB.connectWallet();
    } catch (e) {
      console.error("connect failed:", e);
      alert((lang === "zh" ? "钱包连接失败: " : "Wallet connect failed: ") + (e?.message || e));
    } finally {
      setConnecting(false);
    }
  }

  const short = account ? `${account.slice(0, 6)}…${account.slice(-4)}` : null;

  return (
    <button className="b-wallet" onClick={onClick} disabled={connecting} title={account || ""}>
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="6" width="18" height="14" rx="2"/><path d="M16 12h2M3 10h18"/></svg>
      {connecting ? (lang === "zh" ? "连接中..." : "Connecting...") : (short || t("nav.connect"))}
    </button>
  );
}

// ============ Ticker strip ============
function TickerStrip({ players }) {
  const items = [...players].sort((a, b) => deriveStats(b).change24 - deriveStats(a).change24).slice(0, 9);
  return (
    <div className="b-ticker">
      <MusicToggle />
      <div className="b-ticker-track">
        {[...items, ...items].map((p, i) => {
          const s = deriveStats(p);
          return (
            <div key={i} className="b-ticker-item">
              <Jersey kit={p.kit} number={p.number} size={20} />
              <span className="b-tk-sym">${p.symbol}</span>
              <span className="b-tk-px mono">{fmtUsdPrice(p.priceBNB)}</span>
              <span className={`b-tk-ch ${s.change24 >= 0 ? 'up' : 'down'} mono`}>
                {s.change24 >= 0 ? '+' : ''}{s.change24.toFixed(2)}%
              </span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ============ Intro Hero (the protocol explainer that comes BEFORE markets) ============
function IntroHero({ mvpReserveBNB, goldReservePool, onStake, onMarkets, leader }) {
  const lang = useLang();
  return (
    <section className="b-intro">
      <div className="b-intro-row">
        <div className="b-intro-left">
          <div className="b-intro-eyebrow"><Ball variant="silver" size={14} /> FIFA World Cup 2026 · BNB Smart Chain · Powered by Flap</div>
          <h1 className="b-intro-title">
            {lang === "zh"
              ? <>每一粒进球，<br/>都让 <span>金靴</span> 持币人拿回购。</>
              : <>Every goal compounds <br/>the <span>Golden Boot</span> holder’s buyback.</>
            }
          </h1>
          <p className="b-intro-sub">
            {lang === "zh"
              ? "把 2026 世界杯每位射手做成独立 ERC20。质押 GOLDBALL 拿 SILVER 去交易球员币，赚到的部分自动变成 GOLD，从 金球储备池 1:1 提 BNB。决赛后，金靴球员代币被全额回购并销毁。"
              : "Each 2026 WC player is a dedicated ERC20. Stake GOLDBALL for SILVER, trade player tokens; profits crystallize to GOLD redeemable 1:1 for BNB from the Gold Reserve Pool. After the final, the Golden Boot winner’s token gets a full buyback & burn."}
          </p>
          <div className="b-intro-cta">
            <button className="b-intro-btn primary" onClick={onStake}>{lang === "zh" ? "立即质押 GOLDBALL" : "Stake GOLDBALL"} →</button>
            <button className="b-intro-btn ghost" onClick={onMarkets}>{lang === "zh" ? "查看市场" : "View Markets"}</button>
          </div>
        </div>

        <div className="b-intro-flow">
          <BigFlow />
        </div>
      </div>

      <div className="b-pool-row">
        <div className="b-pool-card mvp">
          <div className="b-pool-icon">🏆</div>
          <div className="b-pool-meta">
            <div className="b-pool-label">{lang === "zh" ? "MVP 储备金池 · 决赛回购" : "MVP Reserve Pool · Finals Buyback"}</div>
            <div className="b-pool-value mono">{mvpReserveBNB.toFixed(3)} <span>BNB</span></div>
            <div className="b-pool-sub mono">{lang === "zh" ? "60% 税收 · 全额买入并销毁金靴球员代币" : "60% of tax · Buys & burns the Golden Boot winner’s token"}</div>
          </div>
          {leader && (
            <div className="b-pool-leader">
              <Jersey kit={leader.kit} number={leader.number} size={32} />
              <div>
                <div style={{fontSize: 11, color: 'var(--text-3)'}}>{lang === "zh" ? "当前领跑" : "Current leader"}</div>
                <div style={{fontSize: 13, fontWeight: 600}}><PlayerName p={leader} both={false} /></div>
              </div>
            </div>
          )}
        </div>

        <div className="b-pool-card gold">
          <div className="b-pool-icon"><Ball variant="gold" size={42} /></div>
          <div className="b-pool-meta">
            <div className="b-pool-label">{lang === "zh" ? "金球储备池 · 1:1 BNB 提现" : "Gold Reserve Pool · 1:1 BNB Redeem"}</div>
            <div className="b-pool-value mono">{goldReservePool.toFixed(3)} <span>BNB</span></div>
            <div className="b-pool-sub mono">{lang === "zh" ? "40% 税收 · 交易盈利铸金球随时提现" : "40% of tax · Backs GOLD redemption from trading profits"}</div>
          </div>
        </div>
      </div>
    </section>
  );
}

// Big flow used in the home hero. Two parallel rows: inner-pool (bonding curve, with GOLD/BNB
// profit crystallization) and outer-pool (PancakeSwap V2 after graduation, SILVER burned directly).
function BigFlow() {
  const lang = useLang();

  const Node = ({ cls, el, label }) => (
    <div className={`b-bf-node ${cls}`}>
      <div className="b-bf-icon">{el}</div>
      <div className="b-bf-name">{label}</div>
    </div>
  );

  const Arrow = ({ label, sol, color }) => (
    <div className={`b-bf-arrow ${color || ""}`}>
      <div className="b-bf-arrow-line">
        <svg viewBox="0 0 120 20" preserveAspectRatio="none" width="100%" height="20" className="b-bf-arrow-svg">
          <line x1="4" y1="10" x2="100" y2="10"
            stroke="currentColor" strokeWidth="2.4"
            strokeDasharray="7 5" strokeLinecap="round"
            className="b-bf-dash" />
          <path d="M 95 4 L 108 10 L 95 16"
            stroke="currentColor" strokeWidth="2.4"
            fill="none" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </div>
      <div className="b-bf-arrow-label">{label}</div>
      {sol && <div className="b-bf-arrow-sol mono">{sol}</div>}
    </div>
  );

  return (
    <div className="b-flow-wrap">
      {/* INNER POOL ROW — bonding curve life cycle */}
      <div className="b-flow-row">
        <div className="b-flow-tag inner">{lang === "zh" ? "内盘 · Bonding Curve" : "Inner · Bonding Curve"}</div>
        <div className="b-bigflow">
          <Node cls="yellow" el={<Logo size={28} />} label="GOLDBALL" />
          <Arrow label={lang === "zh" ? "质押" : "stake"} sol="Vault.stake()" />
          <Node cls="silver" el={<Ball variant="silver" size={26} />} label="SILVER" />
          <Arrow label={lang === "zh" ? "买入" : "buy"} sol="PlayerCurve.buy()" />
          <Node cls="player" el={<img src="assets/player.jpg" alt="" className="gb-bf-jersey" />} label={lang === "zh" ? "球员币" : "Player"} />
          <Arrow label={lang === "zh" ? "盈利沉淀" : "profit"} sol="_realizePnL()" color="up" />
          <Node cls="gold" el={<Ball variant="gold" size={26} />} label="GOLD" />
          <Arrow label={lang === "zh" ? "提现" : "redeem"} sol="withdrawGold()" />
          <Node cls="bnb" el={<Bnb size={26} />} label="BNB" />
        </div>
      </div>

      {/* OUTER POOL ROW — graduated to PancakeSwap V2, SILVER burned directly for player token */}
      <div className="b-flow-row">
        <div className="b-flow-tag outer">{lang === "zh" ? "外盘 · PancakeSwap V2" : "Outer · PancakeSwap V2"}</div>
        <div className="b-bigflow">
          <Node cls="silver" el={<Ball variant="silver" size={26} />} label="SILVER" />
          <Arrow label={lang === "zh" ? "销毁直换" : "burn-swap"} sol="Vault.outerBuy()" color="down" />
          <Node cls="player" el={<img src="assets/player.jpg" alt="" className="gb-bf-jersey" />} label={lang === "zh" ? "球员币" : "Player"} />
          <Arrow label={lang === "zh" ? "PancakeSwap" : "PancakeSwap"} sol="V2 LP" />
          <Node cls="pancake" el={<svg viewBox="0 0 32 32" width="26" height="26"><circle cx="16" cy="16" r="16" fill="#1FC7D4"/><path d="M16 7 Q22 7 22 13 Q22 18 18 19 L18 22 Q18 25 16 25 Q14 25 14 22 L14 19 Q10 18 10 13 Q10 7 16 7 Z" fill="#fff"/><circle cx="13.5" cy="12.5" r="1.5" fill="#1FC7D4"/><circle cx="18.5" cy="12.5" r="1.5" fill="#1FC7D4"/></svg>} label="LP" />
        </div>
        <div className="b-flow-foot dim">
          {lang === "zh"
            ? "毕业后 (达 7.5 BNB 阈值),内盘自动迁移到 PancakeSwap V2,SILVER 不再产生 GOLD,而是销毁换取流动性池里的球员币。"
            : "After graduation (7.5 BNB threshold), inner curve migrates to PancakeSwap V2. SILVER no longer crystallizes to GOLD — it's burned to swap directly from the V2 LP."}
        </div>
      </div>
    </div>
  );
}

// ============ Hero banner ============
function HeroBanner({ leader, mvpReserveBNB, onOpen }) {
  const t = useT();
  if (!leader) return null;
  return (
    <div className="b-banner">
      <div className="b-banner-card mvp" id="mvp" onClick={() => onOpen(leader)}>
        <div className="b-bc-left">
          <div className="b-bc-eyebrow">{t("banner.eyebrow.mvp")}</div>
          <div className="b-bc-row">
            <div className="b-bc-jersey">
              {leader.mascot
                ? <img src={leader.mascot} alt="" className="gb-mascot-hero" />
                : leader.jerseyImg
                  ? <img src={leader.jerseyImg} alt="" className="gb-jersey-hero" />
                  : <Jersey kit={leader.kit} number={leader.number} size={86} />}
            </div>
            <div className="b-bc-info">
              <div className="b-bc-name"><PlayerName p={leader} /></div>
              <div className="b-bc-sub"><CountryName p={leader} /> · <ClubName p={leader} /></div>
              <div className="b-bc-goals">
                <span className="big">{leader.goals}</span>
                <span className="lab">{t("banner.goals")}</span>
                {leader.goalDelta > 0 && <span className="delta up">+{leader.goalDelta} {t("banner.thisMatch")}</span>}
              </div>
            </div>
          </div>
        </div>
        <div className="b-bc-divider"></div>
        <div className="b-bc-reserve">
          <div className="b-bc-eyebrow">{t("banner.eyebrow.reserve")}</div>
          <div className="b-bc-reserve-num mono">{fmtBNB(mvpReserveBNB, 3)} <span>BNB</span></div>
          <div className="b-bc-reserve-sub">≈ ${fmtNum(Math.round(mvpReserveBNB * 612))} · {t("banner.dispatch")}</div>
          <button className="b-bc-cta">{t("banner.cta")} ${leader.symbol} →</button>
        </div>
      </div>

      <div className="b-banner-side">
        <CountdownPill />
        <BuybackHistory />
      </div>
    </div>
  );
}

function CountdownPill() {
  const t = useT();
  // World Cup 2026 opening match: 2026-06-11, Estadio Azteca, Mexico City.
  // Counts down to kickoff so users see "how many days until the tournament starts".
  const TARGET_MS = Date.UTC(2026, 5, 11, 19, 0, 0);
  const compute = () => {
    const diff = Math.max(0, TARGET_MS - Date.now());
    const d = Math.floor(diff / 86_400_000);
    const h = Math.floor((diff % 86_400_000) / 3_600_000);
    const m = Math.floor((diff % 3_600_000) / 60_000);
    const s = Math.floor((diff % 60_000) / 1000);
    return { d, h, m, s };
  };
  const [tm, setTm] = useState(compute);
  useEffect(() => {
    const id = setInterval(() => setTm(compute()), 1000);
    return () => clearInterval(id);
  }, []);
  return (
    <div className="b-side-card gb-cd-card">
      <img className="gb-cd-trophy" src="assets/trophy.png" alt="" />
      <div className="b-side-head">
        <span className="b-side-title">{t("cd.title")}</span>
        <span className="b-pulse"></span>
      </div>
      <div className="b-cd-row">
        <div className="b-cd"><div className="n mono">{tm.d}</div><div className="l">{t("cd.d")}</div></div>
        <div className="b-cd"><div className="n mono">{String(tm.h).padStart(2,'0')}</div><div className="l">{t("cd.h")}</div></div>
        <div className="b-cd"><div className="n mono">{String(tm.m).padStart(2,'0')}</div><div className="l">{t("cd.m")}</div></div>
        <div className="b-cd"><div className="n mono">{String(tm.s).padStart(2,'0')}</div><div className="l">{t("cd.s")}</div></div>
      </div>
      <div className="b-side-foot mono">KICKOFF · 2026-06-11 19:00 UTC · Estadio Azteca</div>
    </div>
  );
}

function BuybackHistory() {
  const t = useT();
  const items = [
    { tx: "0x4a7e…b2c1", amt: 0.482, mins: 2, target: "MBAPPE" },
    { tx: "0x91f0…3d4a", amt: 0.317, mins: 7, target: "YAMAL" },
    { tx: "0xa83c…8f12", amt: 0.205, mins: 14, target: "VINI" },
  ];
  return (
    <div className="b-side-card">
      <div className="b-side-head">
        <span className="b-side-title">{t("buyback.title")}</span>
      </div>
      <div className="b-buyback-list">
        {items.map((it, i) => (
          <div key={i} className="b-buyback-row">
            <span className="mono dim">{it.tx}</span>
            <span className="mono">{it.amt} BNB</span>
            <span className="dim">{it.mins} {t("buyback.minAgo")}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ============ Market Table ============
function MarketTable({ players, onOpen, tab, setTab }) {
  const t = useT();
  const lang = useLang();
  const [search, setSearch] = useState("");

  const list = useMemo(() => {
    let arr = players.map(p => ({ ...p, ...deriveStats(p) }));
    if (search) {
      const q = search.toLowerCase();
      const nicks = window.PLAYER_NICKNAMES || {};
      arr = arr.filter(p => {
        const playerNicks = nicks[p.id] || [];
        return (
          p.name.toLowerCase().includes(q)
          || (p.nameZh && p.nameZh.includes(search))
          || p.symbol.toLowerCase().includes(q)
          || p.country.toLowerCase().includes(q)
          || (p.countryZh && p.countryZh.includes(search))
          || playerNicks.some(nick => nick.toLowerCase().includes(q) || nick.includes(search))
        );
      });
    }
    // Legends (CR7=100, Messi=99, others 0) tiebreak when sort metric ties.
    // Pre-tournament all goals=0 → priority order surfaces.
    const pr = (p) => p.priority || 0;
    if (tab === "goals")    arr.sort((a, b) => (b.goals - a.goals) || (pr(b) - pr(a)) || (a.id - b.id));
    if (tab === "gainers")  arr.sort((a, b) => (b.change24 - a.change24) || (pr(b) - pr(a)));
    if (tab === "losers")   arr.sort((a, b) => (a.change24 - b.change24) || (pr(b) - pr(a)));
    if (tab === "volume")   arr.sort((a, b) => (b.volume24 - a.volume24) || (pr(b) - pr(a)));
    if (tab === "new")      arr.sort((a, b) => b.id - a.id);
    if (tab === "graduated") arr = arr.filter(p => p.progressBps >= 10000);
    return arr;
  }, [players, tab, search]);

  return (
    <div className="b-market" id="markets">
      <div className="b-market-head">
        <div className="b-tabs">
          <button className={tab==='goals'    ? 'active' : ''} onClick={() => setTab('goals')}>{t("mt.tab.goals")}</button>
          <button className={tab==='gainers'  ? 'active' : ''} onClick={() => setTab('gainers')}>{t("mt.tab.gainers")}</button>
          <button className={tab==='losers'   ? 'active' : ''} onClick={() => setTab('losers')}>{t("mt.tab.losers")}</button>
          <button className={tab==='volume'   ? 'active' : ''} onClick={() => setTab('volume')}>{t("mt.tab.volume")}</button>
          <button className={tab==='new'      ? 'active' : ''} onClick={() => setTab('new')}>{t("mt.tab.new")}</button>
          <button className={tab==='graduated'? 'active' : ''} onClick={() => setTab('graduated')}>{t("mt.tab.graduated")}</button>
        </div>
        <div className="b-market-search">
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
          <input placeholder={t("mt.search")} value={search} onChange={e => setSearch(e.target.value)} />
        </div>
      </div>

      <table className="b-mt">
        <thead>
          <tr>
            <th style={{width: 44}}>#</th>
            <th>{t("mt.col.pair")}</th>
            <th>{t("mt.col.price")}</th>
            <th>{t("mt.col.change")}</th>
            <th>{t("mt.col.high")}</th>
            <th>{t("mt.col.low")}</th>
            <th>{t("mt.col.vol")}</th>
            <th>{t("mt.col.goals")}</th>
            <th>{t("mt.col.prog")}</th>
            <th style={{textAlign: 'right'}}>{t("mt.col.action")}</th>
          </tr>
        </thead>
        <tbody>
          {list.length === 0 && (
            <tr><td colSpan="10" className="b-empty">{t("mt.empty")}</td></tr>
          )}
          {list.map((p, i) => (
            <tr key={p.id} onClick={() => onOpen(p)} className={p.pending ? 'b-mt-pending' : ''}>
              <td className="dim mono">{i + 1}</td>
              <td>
                <div className="b-mt-pair">
                  {p.mascot
                    ? <div className="gb-mascot-badge"><img src={p.mascot} alt="" /></div>
                    : <Jersey kit={p.kit} number={p.number} size={32} />}
                  <div className="b-mt-pair-meta">
                    <div className="b-mt-name">
                      <span className="b-mt-sym">{p.displayName ? p.displayName : "$" + p.symbol}</span>
                      <span className="b-mt-quote">/ SILVER</span>
                      {!p.pending && i === 0 && tab === 'goals' && <span className="b-mt-tag gold">MVP</span>}
                      {!p.pending && p.progressBps >= 10000 && <span className="b-mt-tag pancake">PancakeSwap</span>}
                      {p.pending && <span className="b-mt-tag pending">{lang === "zh" ? "未上线" : "Soon"}</span>}
                    </div>
                    <div className="b-mt-sub">
                      <PlayerName p={p} both={false} />
                      {p.displayName && <span className="dim"> · ${p.symbol}</span>}
                      {" · "}<CountryName p={p} />
                    </div>
                  </div>
                </div>
              </td>
              <td className="mono"><span className={p.change24 >= 0 ? 'up' : 'down'}>{fmtUsdPrice(p.displayPrice || p.priceBNB)}</span></td>
              <td className="mono"><span className={p.change24 >= 0 ? 'up' : 'down'}>{p.change24 >= 0 ? '+' : ''}{p.change24.toFixed(2)}%</span></td>
              <td className="mono dim">{fmtUsdPrice(p.high24)}</td>
              <td className="mono dim">{fmtUsdPrice(p.low24)}</td>
              <td className="mono">{fmtVolume(p.volume24)} <span className="dim" style={{fontSize:11}}>SILVER</span></td>
              <td>
                <span className="b-goal-pill">
                  <Ball variant="silver" size={14} />
                  <span className="mono">{p.goals}</span>
                  {p.goalDelta > 0 && <span className="delta">+{p.goalDelta}</span>}
                </span>
              </td>
              <td>
                <div className="b-mt-prog">
                  <div className="b-mt-prog-bar"><div className="b-mt-prog-fill" style={{width: (p.progressBps/100) + '%'}}></div></div>
                  <span className="mono dim">{(p.progressBps/100).toFixed(1)}%</span>
                </div>
              </td>
              <td style={{textAlign: 'right'}}>
                <button className="b-mt-btn" onClick={(e) => { e.stopPropagation(); onOpen(p); }}>{t("mt.action")}</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

// ============ Stat strip ============
function StatStrip({ mvpReserveBNB, players }) {
  const t = useT();
  const totalGoals = players.reduce((a, p) => a + p.goals, 0);
  const totalMcap = players.reduce((a, p) => a + p.marketCapBNB, 0);
  const totalHolders = players.reduce((a, p) => a + p.holders, 0);
  return (
    <div className="b-stats">
      <div className="b-stat">
        <div className="lab">{t("stats.totalGoals")}</div>
        <div className="val mono">{totalGoals}</div>
        <div className="sub up mono">{t("stats.totalGoalsSub")}</div>
      </div>
      <div className="b-stat">
        <div className="lab">{t("stats.totalMcap")}</div>
        <div className="val mono">{fmtBNB(totalMcap, 1)} BNB</div>
        <div className="sub dim mono">≈ ${fmtNum(Math.round(totalMcap * 612))}</div>
      </div>
      <div className="b-stat">
        <div className="lab">{t("stats.reserve")}</div>
        <div className="val mono" style={{color: '#f0b90b'}}>{fmtBNB(mvpReserveBNB, 3)} BNB</div>
        <div className="sub dim">{t("stats.reserveSub")}</div>
      </div>
      <div className="b-stat">
        <div className="lab">{t("stats.tokens")}</div>
        <div className="val mono">{players.length} / 48</div>
        <div className="sub dim">{t("stats.tokensSub")}</div>
      </div>
      <div className="b-stat">
        <div className="lab">{t("stats.holders")}</div>
        <div className="val mono">{fmtNum(totalHolders)}</div>
        <div className="sub up mono">+184 {t("stats.24h")}</div>
      </div>
      <div className="b-stat">
        <div className="lab">{t("stats.burned")}</div>
        <div className="val mono">12.84M</div>
        <div className="sub dim mono">{t("stats.burnedSub")}</div>
      </div>
    </div>
  );
}

// ============ How It Works (MVP mechanic) ============
function HowItWorks() {
  const t = useT();
  const lang = useLang();
  const steps = [
    {
      n: "01",
      title: lang === "zh" ? "球员代币上线" : "Player Tokens Launch",
      body:  lang === "zh"
        ? "每位 2026 世界杯报名球员部署一个独立 ERC20 代币，BeaconProxy 可升级。"
        : "Each 2026 World Cup player gets a dedicated ERC20 token, deployed as upgradeable BeaconProxy.",
      pill: "PlayerToken.sol"
    },
    {
      n: "02",
      title: lang === "zh" ? "Bonding Curve 交易" : "Bonding Curve Trading",
      body:  lang === "zh"
        ? "在内盘用 SILVER (质押 GOLDBALL 获得) 买入 / 卖出。达到 7.5 BNB 阈值后自动上 PancakeSwap V2。"
        : "Trade on the inner curve with SILVER (earned by staking GOLDBALL). Graduates to PancakeSwap V2 at the 7.5 BNB threshold.",
      pill: "PlayerCurve.sol · quoteBuy()"
    },
    {
      n: "03",
      title: lang === "zh" ? "进球 = MVP 候选" : "Goals = MVP Candidate",
      body:  lang === "zh"
        ? "Chainlink Sports Oracle 在赛后 90 秒内把进球写入链上，60% 的 BNB 税收进入 MVP Reserve，40% 进入金球储备池。"
        : "Chainlink Sports Oracle writes goal events on-chain within 90s of match-end. 60% of BNB tax flows to the MVP Reserve, 40% to the Gold Reserve Pool.",
      pill: "Vault.sol · mvpReserveBNB"
    },
    {
      n: "04",
      title: lang === "zh" ? "金靴 ＝ 全额回购" : "Golden Boot = Full Buyback",
      body:  lang === "zh"
        ? "世界杯决赛后，Finals Mode 启动。Treasury 调用 executeFinalsBuyback，将 MVP Reserve 全部用于金靴球员代币的回购与销毁。"
        : "After the WC final, Finals Mode activates. Treasury calls executeFinalsBuyback to spend the entire MVP Reserve buying & burning the Golden Boot winner’s token.",
      pill: "executeFinalsBuyback()"
    },
  ];
  return (
    <div className="b-how" id="how">
      <div className="b-how-head">
        <span className="b-side-title">{lang === "zh" ? "⚙ MVP 机制 · How It Works" : "⚙ MVP Mechanic · How It Works"}</span>
        <span className="dim" style={{fontSize: 12}}>{lang === "zh" ? "部署于 BNB Smart Chain · Flap 兼容金库" : "Deployed on BNB Smart Chain · Flap-compatible vault"}</span>
      </div>
      <div className="b-how-grid">
        {steps.map(s => (
          <div key={s.n} className="b-how-card">
            <div className="b-how-n mono">{s.n}</div>
            <div className="b-how-title">{s.title}</div>
            <div className="b-how-body">{s.body}</div>
            <div className="b-how-pill mono">▸ {s.pill}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ============ Matches strip ============
// World Cup 2026 kicks off 2026-06-11. Pre-tournament we show:
//   left  — "no results yet" empty state (no fabricated scores/scorers)
//   right — live countdown to the opening match at Estadio Azteca
function MatchesStrip() {
  const lang = useLang();
  // 2026-06-11 19:00 UTC = unix 1781118000
  const KICKOFF_UTC = 1781118000;
  const [now, setNow] = useState(() => Math.floor(Date.now() / 1000));
  useEffect(() => {
    const id = setInterval(() => setNow(Math.floor(Date.now() / 1000)), 1000);
    return () => clearInterval(id);
  }, []);
  const secLeft = Math.max(0, KICKOFF_UTC - now);
  const days = Math.floor(secLeft / 86400);
  const hours = Math.floor((secLeft % 86400) / 3600);
  const mins = Math.floor((secLeft % 3600) / 60);
  const secs = secLeft % 60;
  const started = secLeft === 0;

  return (
    <div className="b-matches" id="matches">
      <div className="b-matches-card">
        <div className="b-matches-head">
          <span className="b-side-title">{lang === "zh" ? "🔴 已结束 · 上链结算" : "🔴 Completed · Settled on-chain"}</span>
          <span className="dim" style={{fontSize:11}}>Chainlink Sports Oracle</span>
        </div>
        <div className="b-match-empty">
          <div className="b-match-empty-led"></div>
          <div>
            <div className="b-match-empty-title">{lang === "zh" ? "世界杯尚未开赛" : "Tournament not yet started"}</div>
            <div className="b-match-empty-sub dim">{lang === "zh" ? "首场比分将在 Chainlink Sports Oracle 上链后显示" : "First settled match will appear here once Chainlink reports it on-chain"}</div>
          </div>
        </div>
      </div>
      <div className="b-matches-card">
        <div className="b-matches-head">
          <span className="b-side-title">{lang === "zh" ? "🟡 揭幕战倒计时" : "🟡 Opening Match"}</span>
          <span className="dim" style={{fontSize:11}}>Estadio Azteca · Mexico City</span>
        </div>
        <div className="b-match-kickoff">
          <div className="b-match-kickoff-label dim mono">{lang === "zh" ? "距开赛" : "KICKOFF IN"}</div>
          <div className="b-match-kickoff-time mono">
            {started
              ? (lang === "zh" ? "已开赛" : "LIVE")
              : `${String(days).padStart(2,'0')}d ${String(hours).padStart(2,'0')}h ${String(mins).padStart(2,'0')}m ${String(secs).padStart(2,'0')}s`}
          </div>
          <div className="b-match-kickoff-sub dim">{lang === "zh" ? "2026-06-11 · 19:00 UTC · 世界杯揭幕战" : "2026-06-11 · 19:00 UTC · World Cup Opener"}</div>
        </div>
      </div>
    </div>
  );
}

// ============ Audit row ============
function AuditRow() {
  const t = useT();
  const Check = () => (
    <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M5 12 L10 17 L19 7"/>
    </svg>
  );
  const Warn = () => (
    <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <circle cx="12" cy="12" r="9"/>
      <path d="M12 8 V13 M12 16 V16.5"/>
    </svg>
  );
  const ShieldIcon = () => (
    <svg className="b-audit-shield-svg" width="22" height="24" viewBox="0 0 24 26" aria-hidden="true">
      <defs>
        <linearGradient id="aud-sh-g" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%"  stopColor="#22e08e"/>
          <stop offset="100%" stopColor="#0a7c44"/>
        </linearGradient>
      </defs>
      <path d="M12 2 L21 5 L21 13 Q21 20 12 24 Q3 20 3 13 L3 5 Z" fill="url(#aud-sh-g)" stroke="#0ecb81" strokeWidth="0.6"/>
      <path d="M8 13 L11 16 L16 9" stroke="#04140a" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
  const items = [
    { key: t("audit.ready"),   ok: true },
    { key: t("audit.pending"), ok: false },
    { key: t("audit.flap"),    ok: true },
    { key: t("audit.hardhat"), ok: true },
    { key: t("audit.foundry"), ok: true },
    { key: t("audit.bsc"),     ok: true },
  ];
  return (
    <div className="b-audit" id="audit">
      <div className="b-audit-head">
        <span className="b-audit-title-left">
          <ShieldIcon />
          <span>{t("audit.title").replace(/^[🛡]\s*/, "")}</span>
        </span>
        <a href="#">{t("audit.view")}</a>
      </div>
      <div className="b-audit-badges">
        {items.map((it, i) => (
          <div key={i} className={`b-audit-badge ${it.ok ? "ok" : "warn"}`}>
            {it.ok ? <Check /> : <Warn />}
            <span>{it.key.replace(/^[✓●]\s*/, "")}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ============ Footer ============
function Footer() {
  const t = useT();
  return (
    <footer className="b-foot">
      <div className="b-foot-cols">
        <div>
          <div className="b-foot-h">{t("foot.about")}</div>
          <a href="#">{t("nav.markets")}</a>
          <a href="#">{t("nav.mvp")}</a>
          <a href="#">{t("nav.audit")}</a>
        </div>
        <div>
          <div className="b-foot-h">{t("foot.contracts")}</div>
          <a href="#">GoldballToken</a>
          <a href="#">PlayerFactory</a>
          <a href="#">Vault v3</a>
        </div>
        <div>
          <div className="b-foot-h">{t("foot.data")}</div>
          <a href="#">Chainlink Sports Oracle</a>
          <a href="#">DexScreener</a>
          <a href="#">BscScan</a>
        </div>
        <div>
          <div className="b-foot-h">{t("foot.community")}</div>
          <a href="#">Telegram</a>
          <a href="https://x.com/Goldenballwcp" target="_blank" rel="noopener noreferrer">X / Twitter @Goldenballwcp</a>
          <a href="#">GitHub</a>
        </div>
      </div>
      <div className="b-foot-bottom">{t("foot.disc")}</div>
    </footer>
  );
}

// ============ Stadium Hero — pure cartoon stadium image, no data overlay (alignment was off) ============
function StadiumHero() {
  return (
    <div className="gb-stadium-hero">
      <img className="gb-stadium-img" src="assets/stadium.png" alt="" />
    </div>
  );
}

// ============ App ============
function App() {
  // Load players from on-chain factory. Falls back to [] until dev launches.
  const [players, setPlayers] = useState([]);
  const [playersLoading, setPlayersLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;
    async function load() {
      try {
        if (!window.GB) return;
        const onChain = await window.GB.loadRealPlayers();
        if (!cancelled) {
          setPlayers(onChain);
          setPlayersLoading(false);
        }
      } catch (e) {
        console.error("loadRealPlayers failed:", e);
        if (!cancelled) setPlayersLoading(false);
      }
    }
    load();
    const id = setInterval(load, 30000); // refresh every 30s
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  // Re-render when 24h stats arrive (debounced — many gbSetStats24h calls fire
  // back-to-back during initial load, we want one re-render at the end).
  useEffect(() => {
    let pending = null;
    const onUpdate = () => {
      if (pending) return;
      pending = setTimeout(() => {
        pending = null;
        // Force a re-render by replacing the players array reference. Sort/filter
        // memos depend on `players`, so they'll pick up the fresh deriveStats values.
        setPlayers(prev => prev.slice());
      }, 250);
    };
    window.addEventListener('gb:stats24h', onUpdate);
    return () => {
      window.removeEventListener('gb:stats24h', onUpdate);
      if (pending) clearTimeout(pending);
    };
  }, []);

  const leader = useMemo(
    () => players.length > 0 ? [...players].sort((a, b) => b.goals - a.goals)[0] : null,
    [players]
  );

  const [lang, setLangState] = useState(() => {
    try { return localStorage.getItem('gb_lang') || 'zh'; }
    catch (e) { return 'zh'; }
  });
  const setLang = (l) => {
    setLangState(l);
    try { localStorage.setItem('gb_lang', l); } catch (e) {}
  };

  const [view, setView] = useState("home"); // home | trade | portfolio
  const [active, setActive] = useState(null);
  const [marketTab, setMarketTab] = useState("goals");
  const openTrade = (p) => { setActive(p); setView("trade"); window.scrollTo({ top: 0, behavior: 'instant' }); };
  const goHome = () => { setView("home"); setActive(null); };
  const goPortfolio = () => { setView("portfolio"); setActive(null); window.scrollTo({ top: 0, behavior: 'instant' }); };
  const closeTrade = (maybePlayer) => {
    if (maybePlayer && maybePlayer.id !== undefined) setActive(maybePlayer);
    else goHome();
  };

  // Real vault state from chain — replaces the previous hardcoded demo values.
  const [mvpReserve, setMvpReserve] = useState(0);
  const [goldReservePool, setGoldReservePool] = useState(0);
  useEffect(() => {
    if (!window.GB) return;
    let cancelled = false;
    const load = async () => {
      try {
        const v = window.GB.vault(false);
        const state = await v.getVaultState();
        if (cancelled) return;
        setMvpReserve(Number(window.GB.formatEther(state.mvpReserveBNB)));
        setGoldReservePool(Number(window.GB.formatEther(state.goldBallReserveBNB)));
      } catch (e) { /* noop */ }
    };
    load();
    const id = setInterval(load, 10000);
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  return (
    <LangContext.Provider value={lang}>
      {view === "trade" && active ? (
        <div className="b-app">
          <TradeView player={active} onBack={closeTrade} lang={lang} setLang={setLang} />
        </div>
      ) : view === "portfolio" ? (
        <div className="b-app">
          <Nav onHome={goHome} onPortfolio={goPortfolio} onJumpToTab={setMarketTab} onOpenPlayer={openTrade} lang={lang} setLang={setLang} view="portfolio" />
          <PortfolioView players={players} onOpen={openTrade} lang={lang} setLang={setLang} onNavHome={goHome} />
          <Footer />
        </div>
      ) : (
        <div className="b-app">
          <Nav onHome={goHome} onPortfolio={goPortfolio} onJumpToTab={setMarketTab} onOpenPlayer={openTrade} lang={lang} setLang={setLang} view="home" />
          <StadiumHero />
          <TickerStrip players={players} />
          <div className="b-container">
            <IntroHero
              mvpReserveBNB={mvpReserve}
              goldReservePool={goldReservePool}
              onStake={goPortfolio}
              onMarkets={() => document.querySelector('#markets')?.scrollIntoView({behavior:'smooth'})}
              leader={leader}
            />
            <HeroBanner leader={leader} mvpReserveBNB={mvpReserve} onOpen={openTrade} />
            <StatStrip mvpReserveBNB={mvpReserve} players={players} />
            <MarketTable players={players} onOpen={openTrade} tab={marketTab} setTab={setMarketTab} />
            <HowItWorks />
            <MatchesStrip />
            <AuditRow />
          </div>
          <Footer />
        </div>
      )}
    </LangContext.Provider>
  );
}

window.PlayerName = PlayerName;
window.CountryName = CountryName;
window.ClubName = ClubName;
window.deriveStats = deriveStats;
window.Nav = Nav;

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
