const {
  Brand,
  StatusDot,
  Pill,
  Metric,
  Glyph,
  HashText,
  MiniLogo,
  ProgressBar,
  CopyButton,
  ViewLink,
} = window;

function formatMoney(value, digits = 2) {
  return new Intl.NumberFormat("en-US", {
    minimumFractionDigits: digits,
    maximumFractionDigits: digits,
  }).format(Number.isFinite(value) ? value : 0);
}

function OracleQuoteField() {
  const canvasRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return undefined;

    const context = canvas.getContext("2d", { alpha: false });
    const host = canvas.closest(".site-hero");
    const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    let animationFrame = 0;
    let lastFrame = 0;
    let pageVisible = !document.hidden;
    let fieldVisible = true;
    let width = 1;
    let height = 1;
    let dpr = 1;
    const pointer = { x: 0, y: 0, targetX: 0, targetY: 0 };

    const roundedRect = (x, y, rectWidth, rectHeight, radius) => {
      const safeRadius = Math.min(radius, rectWidth / 2, rectHeight / 2);
      context.beginPath();
      context.moveTo(x + safeRadius, y);
      context.arcTo(x + rectWidth, y, x + rectWidth, y + rectHeight, safeRadius);
      context.arcTo(x + rectWidth, y + rectHeight, x, y + rectHeight, safeRadius);
      context.arcTo(x, y + rectHeight, x, y, safeRadius);
      context.arcTo(x, y, x + rectWidth, y, safeRadius);
      context.closePath();
    };

    const resize = () => {
      const bounds = canvas.getBoundingClientRect();
      width = Math.max(1, bounds.width);
      height = Math.max(1, bounds.height);
      dpr = Math.min(window.devicePixelRatio || 1, width < 700 ? 1.25 : 1.6);
      canvas.width = Math.round(width * dpr);
      canvas.height = Math.round(height * dpr);
      context.setTransform(dpr, 0, 0, dpr, 0, 0);
    };

    const draw = (time = 0) => {
      if (!context || !pageVisible || !fieldVisible) return;

      const mobile = width < 700;
      const motionTime = reducedMotion ? 680 : time;
      pointer.x += (pointer.targetX - pointer.x) * 0.045;
      pointer.y += (pointer.targetY - pointer.y) * 0.045;

      context.fillStyle = "#060a0c";
      context.fillRect(0, 0, width, height);

      const ambient = context.createRadialGradient(
        width * (mobile ? 0.65 : 0.72),
        height * 0.56,
        0,
        width * 0.7,
        height * 0.6,
        Math.max(width, height) * 0.72,
      );
      ambient.addColorStop(0, "rgba(95, 176, 158, 0.16)");
      ambient.addColorStop(0.42, "rgba(26, 80, 76, 0.07)");
      ambient.addColorStop(1, "rgba(6, 10, 12, 0)");
      context.fillStyle = ambient;
      context.fillRect(0, 0, width, height);

      context.save();
      context.translate(pointer.x * (mobile ? 5 : 14), pointer.y * (mobile ? 3 : 8));

      const vanishingX = width * (mobile ? 0.64 : 0.7);
      const horizonY = height * 0.16;
      context.lineWidth = 1;
      for (let ray = -9; ray <= 9; ray += 1) {
        context.strokeStyle = `rgba(190, 226, 211, ${0.018 + Math.abs(ray % 3) * 0.008})`;
        context.beginPath();
        context.moveTo(vanishingX + ray * (mobile ? 8 : 12), horizonY);
        context.lineTo(vanishingX + ray * (mobile ? 76 : 110), height * 1.05);
        context.stroke();
      }

      const rows = mobile ? 8 : 10;
      const columns = mobile ? 11 : 19;
      for (let row = 0; row < rows; row += 1) {
        const depth = row / Math.max(1, rows - 1);
        const easedDepth = depth * depth;
        const baseY = horizonY + height * (0.09 + easedDepth * 0.77);
        const spread = (mobile ? 20 : 28) + easedDepth * (mobile ? 28 : 48);
        const rowAlpha = 0.12 + depth * 0.58;

        context.strokeStyle = `rgba(183, 221, 207, ${0.025 + depth * 0.055})`;
        context.beginPath();
        context.moveTo(width * 0.08, baseY + 12);
        context.lineTo(width * 1.02, baseY + 12);
        context.stroke();

        for (let column = 0; column < columns; column += 1) {
          const offset = column - (columns - 1) / 2;
          const phase = row * 0.83 + column * 0.57;
          const pulse = Math.sin(motionTime * 0.00075 + phase) * 0.5 + 0.5;
          const fastPulse = Math.sin(motionTime * 0.00135 + phase * 1.9) * 0.5 + 0.5;
          const quoteHeight = (mobile ? 30 : 44) + easedDepth * (mobile ? 70 : 124);
          const barHeight = quoteHeight * (0.34 + pulse * 0.66);
          const barWidth = (mobile ? 4 : 5) + easedDepth * (mobile ? 5 : 8);
          const x = vanishingX + offset * spread + Math.sin(motionTime * 0.0003 + row) * depth * 5;
          const y = baseY - barHeight;
          const selected = (column + row * 3) % 11 === 0;

          const barGradient = context.createLinearGradient(x, y, x, baseY);
          if (selected) {
            barGradient.addColorStop(0, `rgba(233, 255, 130, ${0.78 + fastPulse * 0.18})`);
            barGradient.addColorStop(1, `rgba(121, 157, 80, ${0.12 + depth * 0.24})`);
          } else {
            barGradient.addColorStop(0, `rgba(212, 242, 226, ${rowAlpha})`);
            barGradient.addColorStop(0.32, `rgba(116, 203, 174, ${rowAlpha * 0.72})`);
            barGradient.addColorStop(1, `rgba(30, 76, 67, ${rowAlpha * 0.18})`);
          }
          context.fillStyle = barGradient;
          roundedRect(x - barWidth / 2, y, barWidth, barHeight, barWidth / 2);
          context.fill();

          if (selected && depth > 0.38) {
            context.fillStyle = `rgba(235, 255, 159, ${0.34 + fastPulse * 0.42})`;
            context.beginPath();
            context.arc(x, y - 5 - fastPulse * 4, 1.5 + depth, 0, Math.PI * 2);
            context.fill();
          }
        }
      }

      context.restore();

      const sweepX = ((motionTime * 0.035) % (width * 1.45)) - width * 0.2;
      const sweep = context.createLinearGradient(sweepX - 70, 0, sweepX + 70, 0);
      sweep.addColorStop(0, "rgba(224, 255, 166, 0)");
      sweep.addColorStop(0.5, "rgba(224, 255, 166, 0.045)");
      sweep.addColorStop(1, "rgba(224, 255, 166, 0)");
      context.fillStyle = sweep;
      context.fillRect(0, 0, width, height);
    };

    const tick = (time) => {
      if (!pageVisible || !fieldVisible) return;
      animationFrame = window.requestAnimationFrame(tick);
      if (time - lastFrame < 28) return;
      lastFrame = time;
      draw(time);
    };

    const onPointerMove = (event) => {
      if (!host || width < 700) return;
      const bounds = host.getBoundingClientRect();
      pointer.targetX = ((event.clientX - bounds.left) / bounds.width - 0.5) * 2;
      pointer.targetY = ((event.clientY - bounds.top) / bounds.height - 0.5) * 2;
    };

    const onPointerLeave = () => {
      pointer.targetX = 0;
      pointer.targetY = 0;
    };

    const onVisibilityChange = () => {
      pageVisible = !document.hidden;
      window.cancelAnimationFrame(animationFrame);
      if (pageVisible && fieldVisible && !reducedMotion) animationFrame = window.requestAnimationFrame(tick);
    };

    const intersectionObserver = new IntersectionObserver(([entry]) => {
      fieldVisible = entry.isIntersecting;
      window.cancelAnimationFrame(animationFrame);
      if (pageVisible && fieldVisible && !reducedMotion) animationFrame = window.requestAnimationFrame(tick);
    }, { threshold: 0.01 });

    const resizeObserver = new ResizeObserver(() => {
      resize();
      draw(performance.now());
    });
    resizeObserver.observe(canvas);
    intersectionObserver.observe(canvas);
    host?.addEventListener("pointermove", onPointerMove, { passive: true });
    host?.addEventListener("pointerleave", onPointerLeave, { passive: true });
    document.addEventListener("visibilitychange", onVisibilityChange);
    resize();
    draw(680);
    if (!reducedMotion) animationFrame = window.requestAnimationFrame(tick);

    return () => {
      window.cancelAnimationFrame(animationFrame);
      resizeObserver.disconnect();
      intersectionObserver.disconnect();
      host?.removeEventListener("pointermove", onPointerMove);
      host?.removeEventListener("pointerleave", onPointerLeave);
      document.removeEventListener("visibilitychange", onVisibilityChange);
    };
  }, []);

  return <canvas className="oracle-field-canvas" ref={canvasRef} aria-hidden="true" />;
}

function Website({ currentView, onNavigate }) {
  const evidence = [
    ["01", "报价来源", "6 SOURCE", "rule"],
    ["02", "偏差过滤", "0.08%", "fund"],
    ["03", "节点共识", "5 / 6", "oracle"],
    ["04", "链上结算", "FINAL", "settle"],
  ];

  return (
    <main className="screen site-screen" data-screen-label="FAIRX 官网首页">
      <a className="skip-link" href="#main-content">跳到主要内容</a>
      <header className="site-nav">
        <Brand onClick={() => onNavigate("website")} />
        <nav className="site-links" aria-label="主导航">
          <button onClick={() => onNavigate("fair28-intro")}>产品</button>
          <button onClick={() => onNavigate("fairness")}>公平机制</button>
          <button onClick={() => onNavigate("chain")}>FAIRX 公链</button>
          <button onClick={() => onNavigate("oracle")}>Oracle</button>
          <ViewLink target="explorer-home" currentView={currentView} onNavigate={onNavigate}>区块浏览器</ViewLink>
          <button onClick={() => onNavigate("developer")}>开发者</button>
        </nav>
        <div className="site-actions">
          <button className="network-button"><StatusDot tone="green" pulse /> FAIRX Testnet</button>
          <button className="primary-button primary-compact" onClick={() => onNavigate("dapp")}>进入应用 <span>↗</span></button>
        </div>
      </header>

      <section className="site-hero" id="main-content">
        <OracleQuoteField />
        <div className="hero-shade" aria-hidden="true"></div>
        <div className="hero-copy">
          <div className="eyebrow"><span className="eyebrow-signal"></span> REAL-WORLD ORACLE NETWORK <b>LIVE</b></div>
          <h1>现实世界的报价，<br /><span>在链上形成共识。</span></h1>
          <p>FAIRX 聚合交易所、做市商与机构数据源，在毫秒级偏差过滤后，由独立节点共同确认。每一次报价、签名与结算，都留下可验证证据。</p>
          <div className="hero-actions">
            <button className="primary-button oracle-primary" onClick={() => onNavigate("dapp")}>进入实时市场 <span>↗</span></button>
            <button className="oracle-text-link" onClick={() => onNavigate("oracle")}>查看 Oracle 网络 <span>→</span></button>
          </div>
          <div className="hero-footnotes">
            <span><i></i> 6 个独立数据源</span>
            <span><i></i> 5 / 6 节点已确认</span>
            <span><i></i> 2.4 秒最终结算</span>
          </div>
        </div>

        <div className="hero-oracle-hud" aria-label="实时预言机报价">
          <div className="hud-head">
            <span><StatusDot tone="green" pulse /> ORACLE FEED</span>
            <small>FX-AGG / 07</small>
          </div>
          <div className="hud-price-row">
            <div><small>BTC / USD</small><strong>118,428.36</strong></div>
            <span>+1.84%</span>
          </div>
          <div className="hud-range"><span></span><i></i></div>
          <div className="hud-meta">
            <span><small>MEDIAN DEVIATION</small><b>0.08%</b></span>
            <span><small>UPDATED</small><b>184 ms</b></span>
            <span><small>CONFIDENCE</small><b>99.92%</b></span>
          </div>
          <div className="hud-source-row">
            {["BINANCE", "OKX", "COINBASE", "KRAKEN", "PYTH", "FAIRX"].map((source, index) => (
              <span key={source} className={index === 5 ? "active" : ""}>{source.slice(0, 2)}</span>
            ))}
          </div>
        </div>

        <div className="hero-quote-tape" aria-hidden="true">
          <span><b>ETH / USD</b> 3,742.91 <i>+0.72%</i></span>
          <span><b>XAU / USD</b> 3,418.62 <i>+0.21%</i></span>
          <span><b>TSLA / USD</b> 332.18 <i className="down">-0.34%</i></span>
          <span><b>NVDA / USD</b> 171.42 <i>+1.16%</i></span>
        </div>
      </section>

      <section className="oracle-story" aria-label="预言机报价进入链上结算的过程">
        <div className="oracle-story-sticky">
          <div className="story-kicker"><span>HOW FAIRX REACHES TRUTH</span><b>01 / 04</b></div>
          <div className="mobile-story-progress" aria-hidden="true">
            {[0, 1, 2, 3].map((item) => <i key={item}><span></span></i>)}
          </div>
          <div className="story-layout">
            <div className="story-copy">
              <h2>不是把一个价格搬上链，<br />而是让多个现实来源达成共识。</h2>
              <div className="story-steps">
                <article className="story-step step-source">
                  <span>01</span><div><h3>接入真实世界报价</h3><p>交易所、做市商与机构数据源以独立通道持续提交。</p></div>
                </article>
                <article className="story-step step-filter">
                  <span>02</span><div><h3>过滤异常与时间偏差</h3><p>剔除延迟、离群与不可验证数据，保留有效报价簇。</p></div>
                </article>
                <article className="story-step step-consensus">
                  <span>03</span><div><h3>独立节点签名共识</h3><p>达到阈值后生成可追溯的聚合价格与置信区间。</p></div>
                </article>
                <article className="story-step step-settlement">
                  <span>04</span><div><h3>触发合约公平结算</h3><p>报价、签名、规则和资金状态一起成为链上证明。</p></div>
                </article>
              </div>
            </div>

            <div className="story-machine" aria-hidden="true">
              <div className="machine-grid"></div>
              <div className="source-stack">
                <span className="oracle-source source-a"><i>EX</i><b>118,426.92</b><small>12 ms</small></span>
                <span className="oracle-source source-b"><i>MM</i><b>118,431.07</b><small>19 ms</small></span>
                <span className="oracle-source source-c"><i>FI</i><b>118,428.11</b><small>27 ms</small></span>
                <span className="oracle-source source-d"><i>DX</i><b>118,427.86</b><small>31 ms</small></span>
              </div>
              <div className="source-lines"><i></i><i></i><i></i><i></i></div>
              <div className="consensus-core">
                <span className="consensus-halo halo-one"></span>
                <span className="consensus-halo halo-two"></span>
                <div><small>AGGREGATED</small><b>118,428.36</b><em>5 / 6 SIGNED</em></div>
              </div>
              <div className="settlement-beam"><span></span></div>
              <div className="settlement-block">
                <small>ONCHAIN SETTLEMENT</small>
                <strong>PRICE FINALIZED</strong>
                <span><i>✓</i> Block #13,284,196</span>
                <code>0x84f1...29c7</code>
              </div>
              <div className="proof-seal"><span>✓</span><small>FAIR PROOF</small></div>
            </div>
          </div>
        </div>
      </section>

      <section className="proof-band">
        <div className="proof-band-head">
          <div><span>FAIRNESS, VERIFIED</span><h2>从现实报价到最终结算，全程可验证</h2></div>
          <p>每一层都留下哈希、签名与时间戳。</p>
        </div>
        <div className="evidence-grid">
          {evidence.map(([index, label, value, type], itemIndex) => (
            <React.Fragment key={index}>
              <article className="evidence-card">
                <div className={`evidence-icon icon-${type}`}><span>{index}</span></div>
                <div><small>PROOF {index}</small><h3>{label}</h3></div>
                <strong>{value}</strong>
              </article>
              {itemIndex < evidence.length - 1 && <div className="evidence-connector"><span></span></div>}
            </React.Fragment>
          ))}
        </div>
      </section>

      <section className="oracle-closing">
        <div>
          <span>BUILD ON VERIFIABLE REALITY</span>
          <h2>让市场相信证据，<br />而不是相信平台。</h2>
        </div>
        <button className="primary-button oracle-primary" onClick={() => onNavigate("developer")}>接入 FAIRX Oracle <span>↗</span></button>
        <footer><Brand onClick={() => onNavigate("website")} /><p>Real-world data. Onchain consensus. Fair settlement.</p><small>© 2026 FAIRX Network</small></footer>
      </section>

      <nav className="mobile-site-dock" aria-label="移动端快捷操作">
        <button className="dock-secondary" onClick={() => onNavigate("explorer-home")}><span>◇</span> 验证证明</button>
        <button className="dock-primary" onClick={() => onNavigate("dapp")}>进入市场 <span>↗</span></button>
      </nav>
    </main>
  );
}

function AppSidebar({ currentView, onNavigate }) {
  const navItems = [
    ["⌂", "总览", "app-dashboard"],
    ["◫", "市场中心", "dapp"],
    ["28", "FAIR28", "dapp"],
    ["↗", "股票市场", "stock-trade"],
    ["◇", "庄家池", "vault"],
    ["≋", "我的下注", "portfolio"],
    ["◉", "风控中心", "risk"],
  ];
  return (
    <aside className="app-sidebar">
      <Brand compact onClick={() => onNavigate("website")} />
      <div className="sidebar-section-label">WORKSPACE</div>
      <nav className="sidebar-nav">
        {navItems.map(([icon, label, target]) => (
          <button key={label} className={currentView === target ? "active" : ""} aria-current={currentView === target ? "page" : undefined} onClick={() => onNavigate(target)}>
            <Glyph active={currentView === target}>{icon}</Glyph><span>{label}</span>{label === "我的下注" && <em>3</em>}
          </button>
        ))}
      </nav>
      <div className="sidebar-section-label side-gap">VERIFY</div>
      <nav className="sidebar-nav">
        <button onClick={() => onNavigate("explorer")}><Glyph>⌘</Glyph><span>公平证明</span></button>
        <button onClick={() => onNavigate("oracle")}><Glyph>◎</Glyph><span>Oracle 状态</span></button>
      </nav>
      <div className="sidebar-spacer"></div>
      <div className="vault-mini">
        <div className="vault-mini-head"><span><StatusDot tone="green" pulse /> 保险库正常</span><b>68.2%</b></div>
        <ProgressBar value={68} />
        <div className="vault-mini-row"><span>可承接</span><strong>46,580 USDC</strong></div>
      </div>
      <button className="wallet-card">
        <span className="wallet-avatar">0x</span>
        <span><b>0x7A31…91F4</b><small>FAIRX Testnet</small></span>
        <i>···</i>
      </button>
    </aside>
  );
}

function MarketChart() {
  return (
    <div className="mini-chart" aria-label="市场交易量走势">
      <div className="chart-grid-lines"><i></i><i></i><i></i></div>
      <div className="chart-bars">
        {fairxChartHeights.map((height, index) => <span key={index} style={{ height: `${height}%` }}></span>)}
      </div>
      <div className="chart-labels"><span>20:28</span><span>20:40</span><span>20:52</span><span>现在</span></div>
    </div>
  );
}

function MobileBottomNav({ active, onNavigate }) {
  return (
    <nav className="mobile-bottom-nav" aria-label="移动端主导航">
      <button className={active === "market" ? "active" : ""} aria-current={active === "market" ? "page" : undefined} onClick={() => onNavigate("dapp")}><Glyph active={active === "market"}>28</Glyph><span>市场</span></button>
      <button className={active === "portfolio" ? "active" : ""} aria-current={active === "portfolio" ? "page" : undefined} onClick={() => onNavigate("portfolio")}><Glyph active={active === "portfolio"}>≋</Glyph><span>订单</span></button>
      <button className={active === "proof" ? "active" : ""} aria-current={active === "proof" ? "page" : undefined} onClick={() => onNavigate("explorer")}><Glyph active={active === "proof"}>◇</Glyph><span>验证</span></button>
      <button className={active === "vault" ? "active" : ""} aria-current={active === "vault" ? "page" : undefined} onClick={() => onNavigate("vault")}><Glyph active={active === "vault"}>0x</Glyph><span>资金</span></button>
    </nav>
  );
}

function Dapp({ currentView, onNavigate }) {
  const [marketMode, setMarketMode] = React.useState("fair28");
  const [selection, setSelection] = React.useState(fairxOutcomes[0]);
  const [amount, setAmount] = React.useState("1000");
  const [placed, setPlaced] = React.useState(false);
  const [seconds, setSeconds] = React.useState(42);

  React.useEffect(() => {
    const timer = window.setInterval(() => setSeconds((value) => value > 0 ? value - 1 : 42), 1000);
    return () => window.clearInterval(timer);
  }, []);

  const numericAmount = Math.max(0, Number(amount) || 0);
  const totalReturn = numericAmount * selection.odds;
  const profit = numericAmount * (selection.odds - 1);

  const placeOrder = () => {
    if (numericAmount <= 0) return;
    setPlaced(true);
    window.setTimeout(() => setPlaced(false), 3200);
  };

  return (
    <main className="screen dapp-screen" data-screen-label="FAIRX DApp 交易台">
      <AppSidebar currentView={currentView} onNavigate={onNavigate} />
      <section className="app-workspace">
        <header className="app-topbar">
          <div className="mobile-app-brand"><Brand compact onClick={() => onNavigate("website")} /></div>
          <div className="market-switcher">
            <button className={marketMode === "fair28" ? "active" : ""} aria-pressed={marketMode === "fair28"} onClick={() => setMarketMode("fair28")}><MiniLogo label="28" /><span><small>数字结果市场</small><b>FAIR28</b></span></button>
            <button className={marketMode === "stocks" ? "active" : ""} aria-pressed={marketMode === "stocks"} onClick={() => onNavigate("stock-trade")}><MiniLogo label="TS" /><span><small>股票方向市场</small><b>TSLA / USD</b></span></button>
          </div>
          <div className="topbar-actions">
            <button className="icon-button" aria-label="搜索">⌕</button>
            <button className="icon-button notification-button" aria-label="通知">○<i></i></button>
            <button className="proof-shortcut" onClick={() => onNavigate("explorer")}><span>◇</span> 公平证明 <b>↗</b></button>
          </div>
        </header>

        <div className="app-content">
          <section className="market-title-row">
            <div>
              <div className="breadcrumb">市场中心 <span>/</span> FAIR28 <span>/</span> 第 202607212104 期</div>
              <div className="title-with-status"><h1>{marketMode === "fair28" ? "FAIR28 · 第 202607212104 期" : "TSLA · 30 分钟方向市场"}</h1><Pill tone="success" dot>投注中</Pill></div>
              <p>{marketMode === "fair28" ? "链上可验证随机结果 · 0—27" : "结算价高于参考价，做多获胜；低于参考价，做空获胜。"}</p>
            </div>
            <div className="countdown-card">
              <small>距离封盘</small>
              <strong>00 : {String(seconds).padStart(2, "0")}</strong>
              <span>21:03:00 UTC+9</span>
            </div>
          </section>

          <section className="market-metrics-row">
            <Metric label="本期成交额" value="48,920.00" meta="USDC" />
            <Metric label="创建者准备金" value="31,806.40" meta="最坏结果已覆盖" tone="cyan" />
            <Metric label="剩余可承接" value="46,580.00" meta="USDC" />
            <Metric label="Oracle 健康度" value="4 / 5" meta="节点在线" tone="green" />
          </section>

          <section className="trade-layout">
            <div className="market-panel panel">
              <div className="panel-head">
                <div><small>SELECT OUTCOME</small><h2>选择结果</h2></div>
                <div className="market-view-tabs"><button className="active">基础玩法</button><button>精确和值</button><button>组合玩法</button></div>
              </div>
              <div className="outcome-grid">
                {fairxOutcomes.map((outcome) => (
                  <button key={outcome.id} className={`outcome-card tone-${outcome.tone} ${selection.id === outcome.id ? "selected" : ""}`} aria-pressed={selection.id === outcome.id} onClick={() => setSelection(outcome)}>
                    <span className="outcome-symbol">{outcome.label}</span>
                    <span><small>{outcome.range}</small><b>{outcome.odds.toFixed(2)}</b></span>
                    <i className="selection-mark"></i>
                  </button>
                ))}
              </div>
              <div className="number-strip-head"><span>精确和值 <small>点击展开完整赔率</small></span><button>查看 0—27 全部结果 <b>→</b></button></div>
              <div className="number-strip">
                {fairxNumbers.slice(10, 19).map((number) => <button key={number.value} className={number.value === 14 ? "highlight" : ""}><b>{number.value}</b><small>{number.odds.toFixed(2)}</small></button>)}
              </div>
              <div className="market-proof-row">
                <div className="market-proof-copy"><span className="proof-diamond">◇</span><div><b>本期规则已固定</b><small>规则哈希 <HashText>0x39de9a…80c2</HashText></small></div></div>
                <div className="market-proof-steps"><span className="done"><i></i>规则</span><b></b><span className="done"><i></i>资金</span><b></b><span><i></i>结果</span><b></b><span><i></i>结算</span></div>
                <button onClick={() => onNavigate("explorer")}>验证 ↗</button>
              </div>
            </div>

            <aside className="order-panel panel">
              <div className="panel-head order-head"><div><small>PLACE ORDER</small><h2>订单确认</h2></div><Pill tone="neutral">赔率锁定 08s</Pill></div>
              <div className="selected-outcome">
                <div><span className={`outcome-symbol compact tone-${selection.tone}`}>{selection.label}</span><span><small>当前选择</small><b>{selection.label} · {selection.range}</b></span></div>
                <strong>{selection.odds.toFixed(2)}<small>赔率</small></strong>
              </div>
              <label className="amount-label"><span>投入金额</span><span>余额 12,480.60 USDC</span></label>
              <div className="amount-input"><input aria-label="投入金额" type="number" value={amount} onChange={(event) => setAmount(event.target.value)} min="0" /><span>USDC</span><button onClick={() => setAmount("12480.60")}>MAX</button></div>
              <div className="quick-amounts">{[["100", "100"], ["500", "500"], ["1000", "1,000"], ["5000", "5,000"]].map(([value, label]) => <button key={value} className={amount === value ? "active" : ""} aria-pressed={amount === value} onClick={() => setAmount(value)}>{label}</button>)}</div>
              <div className="order-summary">
                <div><span>可能获得总金额</span><strong>{formatMoney(totalReturn)} USDC</strong></div>
                <div><span>预计净收益</span><strong className="positive">+{formatMoney(profit)} USDC</strong></div>
                <div><span>创建者新增准备金</span><strong>{formatMoney(profit)} USDC</strong></div>
                <div><span>协议费用</span><strong>结算时计算</strong></div>
              </div>
              <div className="coverage-notice"><span className="notice-icon">✓</span><span><b>最坏结果准备金充足</b><small>本订单成交后覆盖率仍为 100%</small></span><strong>已验证</strong></div>
              <button className="order-button" disabled={numericAmount <= 0} onClick={placeOrder}>确认订单并锁定资金 <span>→</span></button>
              <p className="order-disclaimer">签名即表示接受规则哈希 0x39de…80c2 与市场退款条件。</p>
            </aside>
          </section>

          <section className="lower-grid">
            <div className="risk-card panel">
              <div className="compact-panel-title"><span><small>RISK COVERAGE</small><b>保险库与最坏结果</b></span><button onClick={() => onNavigate("risk")}>查看风控详情 ↗</button></div>
              <div className="risk-body">
                <div className="risk-ring"><div><strong>68.2%</strong><small>风险利用率</small></div></div>
                <div className="risk-stats"><span><small>保险库总额</small><b>120,000 USDC</b></span><span><small>最坏结果</small><b>结果 14</b></span><span><small>最高赔付责任</small><b>31,806 USDC</b></span></div>
                <MarketChart />
              </div>
            </div>
            <div className="oracle-card panel">
              <div className="compact-panel-title"><span><small>ORACLE NETWORK</small><b>结果网络</b></span><Pill tone="success" dot>运行正常</Pill></div>
              <div className="oracle-mini-grid">
                {fairxOracleVotes.map((vote) => <div key={vote.node} className={vote.state}><MiniLogo label={vote.node.slice(0, 1)} /><span><b>{vote.node}</b><small>{vote.state === "confirmed" ? "已同步" : "等待心跳"}</small></span><i></i></div>)}
              </div>
            </div>
          </section>
        </div>
      </section>
      <div className="mobile-trade-dock">
        <div><span className={`outcome-symbol compact tone-${selection.tone}`}>{selection.label}</span><span><small>投入 {formatMoney(numericAmount, 0)} USDC</small><b>可得 {formatMoney(totalReturn)} USDC</b></span></div>
        <button disabled={numericAmount <= 0} onClick={placeOrder}>确认下单 <span>→</span></button>
      </div>
      <MobileBottomNav active="market" onNavigate={onNavigate} />
      {placed && <div className="success-toast" role="status" aria-live="polite"><span>✓</span><div><b>订单已提交</b><small>本金与创建者准备金正在同笔交易中锁定</small></div><HashText>0xC8F2…91A7</HashText></div>}
    </main>
  );
}

function ExplorerSidebar({ currentView, onNavigate }) {
  const groups = [
    ["NETWORK", [["⌁", "总览", "explorer-home"], ["▦", "区块", "explorer-home"], ["≋", "交易", "explorer-home"], ["◇", "地址", "explorer-home"], ["⌘", "合约", "explorer-home"]]],
    ["FAIR PROOF", [["28", "市场", "explorer"], ["◉", "庄家池", "explorer-home"], ["◎", "Oracle", "oracle"], ["✓", "结算", "explorer"], ["△", "风险证明", "explorer"]]],
  ];
  return (
    <aside className="explorer-sidebar">
      <Brand compact onClick={() => onNavigate("website")} />
      <span className="explorer-brand-sub">BLOCK EXPLORER</span>
      {groups.map(([label, items]) => (
        <div className="explorer-nav-group" key={label}>
          <small>{label}</small>
          {items.map(([icon, name, target]) => {
            const isActive = (currentView === "explorer-home" && name === "总览") || (currentView === "explorer" && name === "市场") || (currentView === "oracle" && name === "Oracle");
            return <button key={name} className={isActive ? "active" : ""} aria-current={isActive ? "page" : undefined} onClick={() => onNavigate(target)}><Glyph active={isActive}>{icon}</Glyph>{name}{isActive && <i></i>}</button>;
          })}
        </div>
      ))}
      <div className="explorer-side-footer"><span><StatusDot tone="green" pulse /> Network healthy</span><small>Block #12,984,201</small></div>
    </aside>
  );
}

function Explorer({ currentView, onNavigate }) {
  const [search, setSearch] = React.useState("");
  const [searchState, setSearchState] = React.useState("idle");
  const [tab, setTab] = React.useState("概览");
  const executeSearch = (value = search) => {
    if (!value.trim()) return;
    setSearchState("found");
    window.setTimeout(() => setSearchState("idle"), 2200);
  };
  const submitSearch = (event) => {
    event.preventDefault();
    executeSearch();
  };
  const proofChecks = [
    ["01", "规则未改变", "规则哈希与创建时一致", "0x39de…80c2"],
    ["02", "资金已覆盖", "最坏结果准备金充足", "100%"],
    ["03", "结果已确认", "4 / 5 节点达成一致", "结果 14"],
    ["04", "结算已执行", "全部 1,842 笔订单完成", "21:04:09"],
  ];

  return (
    <main className="screen explorer-screen" data-screen-label="FAIRX 区块浏览器">
      <ExplorerSidebar currentView={currentView} onNavigate={onNavigate} />
      <section className="explorer-workspace">
        <header className="explorer-topbar">
          <div className="mobile-explorer-brand"><Brand compact onClick={() => onNavigate("website")} /></div>
          <form className="explorer-search" onSubmit={submitSearch}><span>⌕</span><input value={search} onChange={(event) => setSearch(event.target.value)} onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); executeSearch(event.currentTarget.value); } }} placeholder="搜索交易哈希、地址、市场、区块…" /><kbd>⌘ K</kbd></form>
          <div className="explorer-actions"><button>开发者 API</button><button className="network-button"><StatusDot tone="green" pulse /> FAIRX Testnet <span>⌄</span></button><button className="primary-button primary-compact" onClick={() => onNavigate("dapp")}>进入应用 ↗</button></div>
        </header>

        <div className="explorer-content">
          <div className="explorer-breadcrumb"><button onClick={() => onNavigate("explorer-home")}>市场</button><span>/</span><button onClick={() => onNavigate("dapp")}>FAIR28</button><span>/</span><strong>202607212104</strong></div>
          <section className="explorer-title-row">
            <div className="market-identity"><MiniLogo label="28" /><div><div><h1>FAIR28 · 第 202607212104 期</h1><Pill tone="success" dot>已结算</Pill></div><p>市场 ID <HashText>#FX28-212104</HashText> · 创建于 2026-07-21 21:00:00</p></div></div>
            <div className="explorer-title-actions"><button>分享证明</button><button className="outline-accent">下载审计记录 ↓</button></div>
          </section>

          <section className="verified-banner">
            <div className="verified-seal"><span>✓</span></div>
            <div><small>FAIRNESS PROOF</small><h2>该市场已通过全部公平性验证</h2><p>规则未改变、准备金充足、结果达到确认门槛、结算已由合约执行。</p></div>
            <div className="verified-meta"><span><small>证明区块</small><b>#12,984,201</b></span><span><small>最终确认</small><b>21:04:12 UTC+9</b></span></div>
          </section>

          <section className="proof-check-grid">
            {proofChecks.map(([index, title, copy, value]) => <article key={index} className="proof-check-card"><div className="proof-check-index">{index}</div><div className="proof-check-title"><span className="check-ring">✓</span><div><h3>{title}</h3><p>{copy}</p></div></div><strong>{value}</strong></article>)}
          </section>

          <nav className="explorer-tabs">
            {["概览", "规则", "资金与风险", "Oracle 提交", "订单 1,842", "结算记录"].map((item) => <button key={item} className={tab === item ? "active" : ""} aria-pressed={tab === item} onClick={() => setTab(item)}>{item}</button>)}
          </nav>

          <section className="explorer-main-grid">
            <div className="explorer-left-stack">
              <article className="proof-detail-card">
                <div className="detail-card-head"><div><small>RULE COMMITMENT</small><h2>市场规则与生命周期</h2></div><Pill tone="success">规则一致</Pill></div>
                <div className="rule-hash-row"><span className="hash-glyph">#</span><div><small>规则哈希 SHA-256</small><HashText>0x39de9a8046b7f3c21a62f32d518e91a65d9c80c2</HashText></div><CopyButton value="0x39de9a8046b7f3c21a62f32d518e91a65d9c80c2" /></div>
                <div className="timeline">
                  {[['市场创建','21:00:00'],['规则固定','21:00:01'],['自动封盘','21:03:00'],['结果确认','21:04:07'],['完成结算','21:04:09']].map(([label,time], index) => <React.Fragment key={label}><div className="timeline-step"><span>✓</span><b>{label}</b><small>{time}</small></div>{index < 4 && <i></i>}</React.Fragment>)}
                </div>
                <div className="rule-spec-grid"><span><small>结果空间</small><b>0—27</b></span><span><small>随机机制</small><b>VRF + 多节点确认</b></span><span><small>确认门槛</small><b>3 / 5</b></span><span><small>无效市场</small><b>超时自动退款</b></span></div>
              </article>

              <article className="proof-detail-card transaction-card">
                <div className="detail-card-head"><div><small>ONCHAIN EVENTS</small><h2>关键链上记录</h2></div><button>查看全部交易 ↗</button></div>
                <table><thead><tr><th>事件</th><th>交易哈希</th><th>时间</th><th>状态</th></tr></thead><tbody>{fairxProofTransactions.map((row) => <tr key={row[0]}><td><span className="event-dot"></span>{row[0]}</td><td><HashText>{row[1]}</HashText></td><td>{row[2]}</td><td><span className="table-status"><i></i>{row[3]}</span></td></tr>)}</tbody></table>
              </article>
            </div>

            <aside className="explorer-right-stack">
              <article className="outcome-proof-card">
                <div className="outcome-proof-head"><span><small>FINAL OUTCOME</small><h2>最终结果</h2></span><Pill tone="success">已确认</Pill></div>
                <div className="final-number"><span>14</span><i></i></div>
                <div className="winning-tags"><span>大</span><span>双</span><span>大双</span><span>和值 14</span></div>
                <div className="result-proof-row"><span>原始随机值</span><HashText>0x9f71…e20a</HashText></div>
                <div className="result-proof-row"><span>结果映射</span><strong>VRF mod 28</strong></div>
              </article>

              <article className="oracle-proof-card">
                <div className="detail-card-head"><div><small>ORACLE CONSENSUS</small><h2>节点确认</h2></div><strong>4 / 5</strong></div>
                <div className="oracle-votes">
                  {fairxOracleVotes.map((vote, index) => <div key={vote.node} className={vote.state}><span className="oracle-index">0{index + 1}</span><MiniLogo label={vote.node.slice(0, 1)} /><span><b>{vote.node}</b><small>{vote.time}</small></span><strong>{vote.value}</strong><i>{vote.state === "confirmed" ? "✓" : "·"}</i></div>)}
                </div>
                <button className="oracle-proof-link">查看全部签名与原始提交 <span>↗</span></button>
              </article>

              <article className="reserve-proof-card">
                <div><span><small>RESERVE PROOF</small><h2>赔付准备金</h2></span><strong>100%</strong></div>
                <ProgressBar value={100} tone="green" />
                <p><span>需要准备金 <b>31,806.40</b></span><span>实际已锁定 <b>31,806.40 USDC</b></span></p>
              </article>
            </aside>
          </section>
        </div>
      </section>
      <MobileBottomNav active="proof" onNavigate={onNavigate} />
      {searchState === "found" && <div className="search-toast" role="status" aria-live="polite"><span>✓</span><div><b>已找到对应市场</b><small>FAIR28 · 第 202607212104 期</small></div></div>}
    </main>
  );
}

Object.assign(window, {
  Website,
  AppSidebar,
  MobileBottomNav,
  Dapp,
  ExplorerSidebar,
  Explorer,
  MarketChart,
  formatMoney,
});
