// view-core.jsx — ① コア実機（PoC）：店頭査定の3分体験
const { useState, useEffect, useRef } = React;

const RARITIES = [
  { id: "N",   name: "ノーマル",        pop: "60%" },
  { id: "R",   name: "レア",            pop: "25%" },
  { id: "SR",  name: "スーパーレア",    pop: "10%" },
  { id: "UR",  name: "ウルトラレア",    pop: "4%"  },
  { id: "SEC", name: "シークレットレア",pop: "1%"  },
];

const MARKET_SOURCES = [
  { id: "mer",  name: "メルカリ",       meta: "直近30日 / 出品中含む",      logo: "M"  },
  { id: "sg",   name: "駿河屋",         meta: "買取・販売 中央値",          logo: "駿" },
  { id: "cr",   name: "カードラッシュ", meta: "在庫あり 最安値",            logo: "C"  },
  { id: "tt",   name: "トレトク",       meta: "専門買取 公示価格",          logo: "ト" },
  { id: "cv",   name: "カーナベル",     meta: "専門販売 中央値",            logo: "Ca" },
  { id: "mg",   name: "magi",           meta: "フリマ 売却済中央値",        logo: "m"  },
  { id: "ya",   name: "Yahoo!オク",     meta: "落札 直近30日中央値",        logo: "Y!" },
];

// price tables by rarity (median JPY)
const PRICE_TABLE = {
  N:   { mer: 80,    sg: 50,    cr: 100,   tt: 70,    cv: 120,   mg: 80,    ya: 60    },
  R:   { mer: 480,   sg: 320,   cr: 550,   tt: 410,   cv: 590,   mg: 460,   ya: 380   },
  SR:  { mer: 2800,  sg: 2100,  cr: 3200,  tt: 2400,  cv: 2950,  mg: 2600,  ya: 2300  },
  UR:  { mer: 8400,  sg: 6800,  cr: 9200,  tt: 7600,  cv: 8800,  mg: 8100,  ya: 7200  },
  SEC: { mer: 24800, sg: 19500, cr: 27500, tt: 22000, cv: 26000, mg: 23500, ya: 20000 },
};

// past buyback records (自社DB) — keyed by rarity
const HISTORY = {
  N:   [
    { date: "2026-05-15", cond: "B",  price: 50 },
    { date: "2026-04-22", cond: "A",  price: 70 },
    { date: "2026-03-08", cond: "B",  price: 40 },
  ],
  R:   [
    { date: "2026-05-16", cond: "A",  price: 350 },
    { date: "2026-05-02", cond: "B",  price: 280 },
    { date: "2026-04-11", cond: "A",  price: 380 },
    { date: "2026-03-19", cond: "A",  price: 320 },
    { date: "2026-02-04", cond: "B",  price: 250 },
  ],
  SR:  [
    { date: "2026-05-14", cond: "A",  price: 2000 },
    { date: "2026-05-03", cond: "S",  price: 2400 },
    { date: "2026-04-27", cond: "A",  price: 1900 },
    { date: "2026-04-09", cond: "B",  price: 1500 },
    { date: "2026-03-22", cond: "A",  price: 2100 },
    { date: "2026-02-15", cond: "A",  price: 1800 },
  ],
  UR:  [
    { date: "2026-05-12", cond: "S",  price: 6800 },
    { date: "2026-04-20", cond: "A",  price: 5800 },
    { date: "2026-03-05", cond: "A",  price: 6200 },
    { date: "2026-01-28", cond: "B",  price: 4800 },
  ],
  SEC: [
    { date: "2026-05-08", cond: "S",  price: 20000 },
    { date: "2026-03-14", cond: "A",  price: 17500 },
    { date: "2026-01-22", cond: "A",  price: 16800 },
  ],
};

function fmtJP(n) { return n.toLocaleString("ja-JP"); }
function fmtTime(ms) {
  const total = Math.floor(ms / 10);
  const m = Math.floor(total / 6000);
  const s = Math.floor((total % 6000) / 100);
  const c = total % 100;
  return `${String(m).padStart(2,"0")}:${String(s).padStart(2,"0")}.${String(c).padStart(2,"0")}`;
}

function Stopwatch({ runningAt, frozenMs }) {
  const [now, setNow] = useState(Date.now());
  useEffect(() => {
    if (runningAt == null) return;
    let raf;
    const tick = () => { setNow(Date.now()); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [runningAt]);
  const ms = frozenMs != null ? frozenMs : (runningAt != null ? now - runningAt : 0);
  return (
    <div className={`stopwatch ${runningAt != null && frozenMs == null ? "running" : ""}`}>
      <span className="sw-label">{frozenMs != null ? "経過" : "計測中"}</span>
      <span className="sw-time">{fmtTime(ms)}</span>
    </div>
  );
}

function CoreView({ onPriceConfirm }) {
  // stage: idle | analyzing | identified | priced | history | done
  const [stage, setStage] = useState("idle");
  const [rarity, setRarity] = useState(null);
  const [marketLoaded, setMarketLoaded] = useState({});
  const [historyLoaded, setHistoryLoaded] = useState(false);
  const [finalPrice, setFinalPrice] = useState(null);
  const [editedPrice, setEditedPrice] = useState(null);
  const [adjustNote, setAdjustNote] = useState("");
  const [startedAt, setStartedAt] = useState(null);
  const [frozenMs, setFrozenMs] = useState(null);

  const reset = () => {
    setStage("idle"); setRarity(null); setMarketLoaded({}); setHistoryLoaded(false);
    setFinalPrice(null); setEditedPrice(null); setAdjustNote("");
    setStartedAt(null); setFrozenMs(null);
  };

  const startScan = () => {
    setStartedAt(Date.now());
    setStage("analyzing");
    setTimeout(() => { setStage("identified"); }, 2200);
  };

  const selectRarity = (r) => {
    setRarity(r);
    setStage("priced");
    setMarketLoaded({});
    setHistoryLoaded(false);
    setEditedPrice(null);
    setAdjustNote("");
    // staggered "scraping" of 7 sources
    MARKET_SOURCES.forEach((s, i) => {
      setTimeout(() => {
        setMarketLoaded(prev => ({ ...prev, [s.id]: true }));
      }, 500 + i * 350);
    });
    // self-DB historical lookup fires after market sweep
    setTimeout(() => {
      setStage("history");
      setHistoryLoaded(true);
    }, 500 + 7 * 350 + 600);
  };

  const confirm = () => {
    setFinalPrice(editedPrice);
    setFrozenMs(Date.now() - startedAt);
    setStage("done");
    onPriceConfirm && onPriceConfirm({
      sku: "BLU-EWD-001-SEC",
      name: "蒼穹の終焉竜",
      rarity: rarity.id,
      price: editedPrice,
      at: new Date(),
    });
  };

  // buyback recommendation: blend of market (60-70%) and self-history (median)
  const allLoaded = rarity && MARKET_SOURCES.every(s => marketLoaded[s.id]);
  const prices = rarity ? MARKET_SOURCES.map(s => PRICE_TABLE[rarity.id][s.id]) : [];
  const saleMid = prices.length ? Math.round(prices.reduce((a,b)=>a+b,0) / prices.length / 100) * 100 : 0;
  const saleHigh = prices.length ? Math.max(...prices) : 0;
  const saleLow  = prices.length ? Math.min(...prices) : 0;

  // self-DB stats
  const history = rarity ? HISTORY[rarity.id] : [];
  const histSorted = [...history].map(h => h.price).sort((a,b) => a - b);
  const histMedian = histSorted.length
    ? (histSorted.length % 2
        ? histSorted[(histSorted.length - 1) / 2]
        : Math.round((histSorted[histSorted.length/2 - 1] + histSorted[histSorted.length/2]) / 2))
    : 0;
  const histMax = histSorted.length ? Math.max(...histSorted) : 0;
  const histMin = histSorted.length ? Math.min(...histSorted) : 0;
  const histAvg = histSorted.length ? Math.round(histSorted.reduce((a,b)=>a+b,0) / histSorted.length) : 0;
  // recent 3 months recency weight
  const recentCount = history.filter(h => h.date >= "2026-03-01").length;

  // blended recommendation: 60% market(0.65) + 40% history median
  const marketComponent = Math.round(saleMid * 0.65);
  const blended = histMedian
    ? Math.round((marketComponent * 0.6 + histMedian * 0.4) / 100) * 100
    : Math.round(marketComponent / 100) * 100;
  const blendedLow  = Math.round(blended * 0.95 / 100) * 100;
  const blendedHigh = Math.round(blended * 1.05 / 100) * 100;
  const marginLow  = saleMid ? Math.round((1 - blendedHigh / saleMid) * 100) : 0;
  const marginHigh = saleMid ? Math.round((1 - blendedLow  / saleMid) * 100) : 0;

  // when DB load finishes, seed the editable price with the blended midpoint
  useEffect(() => {
    if (historyLoaded && editedPrice == null) {
      setEditedPrice(blended);
    }
  }, [historyLoaded, blended]);

  const currentEditMargin = (saleMid && editedPrice)
    ? Math.round((1 - editedPrice / saleMid) * 100)
    : 0;
  const deltaFromBlended = editedPrice != null && blended ? editedPrice - blended : 0;
  const editStatus = deltaFromBlended === 0
    ? { tone: "neutral", label: "推奨価格と同額" }
    : Math.abs(deltaFromBlended) <= blended * 0.05
      ? { tone: "ok",   label: `推奨価格 ${deltaFromBlended > 0 ? "+" : "−"}¥${fmtJP(Math.abs(deltaFromBlended))}` }
      : deltaFromBlended < 0
        ? { tone: "warn", label: `推奨より安め · ${deltaFromBlended > 0 ? "+" : "−"}¥${fmtJP(Math.abs(deltaFromBlended))}` }
        : { tone: "warn", label: `推奨より高め · +¥${fmtJP(Math.abs(deltaFromBlended))}` };

  const stepStatus = (n) => {
    const order = { idle: 0, analyzing: 1, identified: 2, priced: 3, history: 4, done: 5 };
    const cur = order[stage];
    if (n < cur) return "is-done";
    if (n === cur) return "is-active";
    return "";
  };

  return (
    <div className="view" data-screen-label="01 Core">
      <div className="view-header">
        <div>
          <div className="crumb">① コア / 実機 PoC</div>
          <h1>店頭査定 3分体験フロー</h1>
          <div className="sub">
            クライアント持参のカードをその場で撮影 → AI判定 → レアリティ確定 → 相場7社の実取得 → 価格確定。
            <span className="chip accent" style={{marginLeft: 8}}>本番Webアプリ</span>
          </div>
        </div>
        <div className="header-side">
          <Stopwatch runningAt={startedAt} frozenMs={frozenMs} />
          <button className="btn" onClick={reset}>↻ リセット</button>
        </div>
      </div>

      <div className="core-grid">
        {/* Left: step list */}
        <div className="card">
          <div className="card-head"><span className="h">フロー進行</span><span className="chip navy">PoC兼用</span></div>
          <ol className="steps">
            <li className={`step ${stepStatus(0)}`}>
              <div className="step-n"><span className="num">1</span></div>
              <span className="step-t">カード画像アップロード</span>
              <span className="step-d">店頭撮影 or ドラッグ&ドロップ</span>
            </li>
            <li className={`step ${stepStatus(1)}`}>
              <div className="step-n"><span className="num">2</span></div>
              <span className="step-t">AIがカード名・型番を特定</span>
              <span className="step-d">遊戯王 / ポケカ 100枚モデル</span>
            </li>
            <li className={`step ${stepStatus(2)}`}>
              <div className="step-n"><span className="num">3</span></div>
              <span className="step-t">レアリティ候補を列挙</span>
              <span className="step-d">人手で確定する仕様</span>
            </li>
            <li className={`step ${stepStatus(3)}`}>
              <div className="step-n"><span className="num">4</span></div>
              <span className="step-t">相場サイト 7社から実取得</span>
              <span className="step-d">メルカリ・駿河屋・カードラッシュ他</span>
            </li>
            <li className={`step ${stepStatus(4)}`}>
              <div className="step-n"><span className="num">5</span></div>
              <span className="step-t">自社DBから過去買取実績を取得</span>
              <span className="step-d">現在相場 × 過去実績で実態に即した査定</span>
            </li>
            <li className={`step ${stepStatus(5)}`}>
              <div className="step-n"><span className="num">6</span></div>
              <span className="step-t">価格確定 → POSへ送信</span>
              <span className="step-d">確定イベントが下流に流れる</span>
            </li>
          </ol>
        </div>

        {/* Right: stage content */}
        <div className="stack">
          {stage === "idle" && (
            <div className="card">
              <div className="card-head"><span className="h">Step 1 / カード画像アップロード</span></div>
              <div className="card-pad">
                <div className="uploader" onClick={startScan}>
                  <div className="up-icon">📷</div>
                  <div className="up-title">クリックでサンプル画像を読み込む</div>
                  <div className="up-sub">JPG / PNG / HEIC・最大 8MB / 5秒以内に応答</div>
                </div>
                <div className="row" style={{marginTop: 14, justifyContent: "space-between"}}>
                  <div className="row gap-sm">
                    <span className="chip">遊戯王</span>
                    <span className="chip">ポケカ</span>
                    <span className="chip" style={{opacity: 0.5}}>ワンピース (準備中)</span>
                  </div>
                  <span className="muted" style={{fontSize: 11}}>学習済 102 / 100,000 枚</span>
                </div>
              </div>
            </div>
          )}

          {stage === "analyzing" && (
            <div className="card">
              <div className="card-head"><span className="h">Step 2 / 画像認識中</span><span className="chip warn">処理中</span></div>
              <div className="analyzing">
                <div className="scan-frame" />
                <div className="scan-text">
                  <div className="mono" style={{fontSize: 11, color: "var(--ink-4)", marginBottom: 6}}>vision-model: tcg-id-v0.3.2</div>
                  <div>カード輪郭を検出・型番OCR読取<span className="blink">…</span></div>
                </div>
              </div>
            </div>
          )}

          {(stage === "identified" || stage === "priced" || stage === "done") && (
            <div className="card">
              <div className="card-head">
                <span className="h">Step 3 / カード特定結果</span>
                <span className="chip success">識別成功</span>
              </div>
              <div className="card-preview">
                <div className="card-art">
                  <img src="assets/card-soukyu.png" alt="蒼穹の終焉竜" />
                </div>
                <div>
                  <div className="id-fields">
                    <div className="id-field">
                      <div className="id-label">カード名</div>
                      <div className="id-value">蒼穹の終焉竜<span className="conf">99.2%</span></div>
                    </div>
                    <div className="id-field">
                      <div className="id-label">型番 / Set Code</div>
                      <div className="id-value mono">BLU-EWD-001<span className="conf">98.7%</span></div>
                    </div>
                    <div className="id-field">
                      <div className="id-label">タイトル</div>
                      <div className="id-value">遊戯王 OCG</div>
                    </div>
                    <div className="id-field">
                      <div className="id-label">収録弾</div>
                      <div className="id-value warn">BLUE EXPANSION<span className="conf">候補2件</span></div>
                    </div>
                  </div>

                  <div style={{marginTop: 18}}>
                    <div className="id-label" style={{marginBottom: 6}}>レアリティ候補（人手で確定）</div>
                    <div className="rarity-row">
                      {RARITIES.map(r => (
                        <button
                          key={r.id}
                          className={`rarity-chip ${rarity?.id === r.id ? "is-selected" : ""}`}
                          onClick={() => selectRarity(r)}>
                          <span className="rc-name">{r.name}</span>
                          <span className="rc-pop">{r.id} · 出現率 {r.pop}</span>
                        </button>
                      ))}
                    </div>
                  </div>
                </div>
              </div>
            </div>
          )}

          {(stage === "priced" || stage === "history" || stage === "done") && (
            <div className="card">
              <div className="card-head">
                <span className="h">Step 4 / 相場サイト 7社を巡回</span>
                <span className="row gap-sm">
                  <span className="chip">{rarity.name}</span>
                  <span className="chip success">live</span>
                </span>
              </div>
              <table className="market-table">
                <thead>
                  <tr>
                    <th style={{width: "50%"}}>ソース</th>
                    <th>取得</th>
                    <th className="price-cell">中央値（円）</th>
                  </tr>
                </thead>
                <tbody>
                  {MARKET_SOURCES.map(s => {
                    const loaded = marketLoaded[s.id];
                    const p = loaded ? PRICE_TABLE[rarity.id][s.id] : null;
                    return (
                      <tr key={s.id}>
                        <td>
                          <div className="row" style={{gap: 12}}>
                            <span style={{
                              width: 32, height: 32, borderRadius: 4,
                              background: "var(--bg-deep)",
                              display: "grid", placeItems: "center",
                              fontWeight: 700, fontSize: 13, color: "var(--ink-2)"
                            }}>{s.logo}</span>
                            <div>
                              <div className="src-name">{s.name}</div>
                              <div className="src-meta">{s.meta}</div>
                            </div>
                          </div>
                        </td>
                        <td>
                          {loaded
                            ? <span className="chip success">✓ 完了</span>
                            : <span className="chip warn">取得中…</span>}
                        </td>
                        <td className="price-cell">
                          {loaded ? (
                            <>
                              <div className="price-num">¥{fmtJP(p)}</div>
                              <div className="listings">サンプル数 {Math.round(20 + Math.random()*40)} 件</div>
                            </>
                          ) : (
                            <span className="skeleton" />
                          )}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}

          {/* Step 5 — Self DB history */}
          {(stage === "priced" || stage === "history" || stage === "done") && (
            <div className="card">
              <div className="card-head">
                <span className="h">Step 5 / 自社DB · 過去買取実績</span>
                <span className="row gap-sm">
                  {!historyLoaded
                    ? <span className="chip warn">問い合わせ中…</span>
                    : <>
                        <span className="chip navy">直近12ヶ月 · {history.length} 件</span>
                        <span className="chip success">✓ 取得完了</span>
                      </>}
                </span>
              </div>
              {!historyLoaded ? (
                <div style={{padding: "28px 20px", display: "flex", alignItems: "center", gap: 14, background: "var(--surface-2)"}}>
                  <span className="mono" style={{fontSize: 11, color: "var(--ink-4)", whiteSpace: "nowrap"}}>SELECT * FROM buyback_history WHERE sku='BLU-EWD-001' …</span>
                  <span className="skeleton" style={{flex: 1, height: 14}} />
                </div>
              ) : (
                <>
                  <div className="hist-stats">
                    <div className="hs-block">
                      <div className="hs-label">買取中央値</div>
                      <div className="hs-value">¥{fmtJP(histMedian)}</div>
                      <div className="hs-meta">過去 {history.length} 件 · 平均 ¥{fmtJP(histAvg)}</div>
                    </div>
                    <div className="hs-block">
                      <div className="hs-label">レンジ</div>
                      <div className="hs-value">¥{fmtJP(histMin)} 〜 ¥{fmtJP(histMax)}</div>
                      <div className="hs-meta">状態 S / A / B により変動</div>
                    </div>
                    <div className="hs-block">
                      <div className="hs-label">直近3ヶ月</div>
                      <div className="hs-value">{recentCount} 件</div>
                      <div className="hs-meta">需要トレンド: {recentCount >= 3 ? "↗ 活発" : "→ 横ばい"}</div>
                    </div>
                  </div>
                  <table className="market-table hist-table">
                    <thead>
                      <tr>
                        <th>取引日</th>
                        <th>状態</th>
                        <th>取扱店舗</th>
                        <th className="price-cell">買取価格</th>
                      </tr>
                    </thead>
                    <tbody>
                      {history.slice(0, 6).map((h, i) => (
                        <tr key={i}>
                          <td className="mono" style={{fontSize: 12, color: "var(--ink-3)"}}>{h.date}</td>
                          <td><span className={`cond-badge cond-${h.cond}`}>{h.cond}</span></td>
                          <td style={{fontSize: 12, color: "var(--ink-3)"}}>
                            {i % 2 === 0 ? "宮崎本店" : "都城店"}
                          </td>
                          <td className="price-cell"><span className="price-num" style={{fontSize: 14}}>¥{fmtJP(h.price)}</span></td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </>
              )}
            </div>
          )}

          {/* Step 6 — Final price (blended) */}
          {(stage === "priced" || stage === "history" || stage === "done") && (
            <div className="card">
              <div className="card-head">
                <span className="h">Step 6 / 推奨買取価格 — 相場 × 自社実績ブレンド</span>
                <span className="chip accent">最終判断は担当者</span>
              </div>
              <div className="final-bar final-bar-grid">
                <div className="fp-block">
                  <div className="fp-label">A · 販売相場（7社）</div>
                  <div className="fp-amount" style={{fontSize: 22}}>
                    <span className="yen">¥</span>
                    {allLoaded ? fmtJP(saleMid) : "—"}
                    {allLoaded && <span className="delta">高 ¥{fmtJP(saleHigh)} / 安 ¥{fmtJP(saleLow)}</span>}
                  </div>
                </div>
                <div className="fp-divider" />
                <div className="fp-block">
                  <div className="fp-label">B · 自社DB買取実績</div>
                  <div className="fp-amount" style={{fontSize: 22, color: "var(--navy)"}}>
                    {historyLoaded ? <>¥{fmtJP(histMedian)}</> : "—"}
                    {historyLoaded && <span className="delta">中央値 · {history.length}件参照</span>}
                  </div>
                </div>
                <div className="fp-divider" />
                <div className="fp-block">
                  <div className="fp-label">AI推奨買取価格（A × B）</div>
                  <div className="fp-amount" style={{fontSize: 22, color: "var(--ink-2)"}}>
                    {historyLoaded
                      ? <>¥{fmtJP(blendedLow)}<span style={{margin: "0 4px", color: "var(--ink-4)"}}>〜</span>¥{fmtJP(blendedHigh)}</>
                      : "—"}
                    {historyLoaded && <span className="delta">中心値 ¥{fmtJP(blended)} · 利益率 {marginLow}〜{marginHigh}%</span>}
                  </div>
                </div>
              </div>

              {/* Editable confirm bar */}
              <div className="confirm-bar">
                <div className="cb-left">
                  <div className="cb-label">最終買取価格 <span className="cb-sub">— 担当者が編集して確定</span></div>
                  <div className="cb-input-row">
                    <button
                      className="cb-step"
                      onClick={() => setEditedPrice(p => Math.max(0, (p || 0) - 100))}
                      disabled={!historyLoaded || stage === "done"}
                      aria-label="100円下げる">−100</button>
                    <div className="cb-input-wrap">
                      <span className="cb-yen">¥</span>
                      <input
                        className="cb-input"
                        type="number"
                        step="100"
                        value={editedPrice ?? ""}
                        onChange={e => setEditedPrice(Number(e.target.value) || 0)}
                        disabled={!historyLoaded || stage === "done"}
                      />
                    </div>
                    <button
                      className="cb-step"
                      onClick={() => setEditedPrice(p => (p || 0) + 100)}
                      disabled={!historyLoaded || stage === "done"}
                      aria-label="100円上げる">+100</button>
                    <button
                      className="cb-reset"
                      onClick={() => setEditedPrice(blended)}
                      disabled={!historyLoaded || stage === "done" || editedPrice === blended}
                      title="推奨価格に戻す">↺ 推奨価格に戻す</button>
                  </div>
                  <div className="cb-meta-row">
                    {historyLoaded && (
                      <>
                        <span className={`chip ${editStatus.tone === "ok" ? "success" : editStatus.tone === "warn" ? "warn" : "navy"}`}>
                          {editStatus.label}
                        </span>
                        <span className="muted" style={{fontSize: 11}}>
                          利益率 {currentEditMargin}% (販売相場 ¥{fmtJP(saleMid)} 基準)
                        </span>
                      </>
                    )}
                  </div>
                  <div className="cb-note-row">
                    <input
                      className="cb-note"
                      type="text"
                      placeholder="調整理由（任意）— 例: 状態Bのため −¥200 / 在庫過多のため −¥300"
                      value={adjustNote}
                      onChange={e => setAdjustNote(e.target.value)}
                      disabled={!historyLoaded || stage === "done"}
                    />
                  </div>
                </div>
                <div className="cb-right">
                  <button
                    className="btn btn-accent btn-lg"
                    disabled={!historyLoaded || stage === "done" || !editedPrice}
                    onClick={confirm}>
                    {stage === "done" ? "✓ 価格確定済み" : "価格確定 → POS送信 →"}
                  </button>
                  <div className="cb-confirm-meta">
                    operator: <span className="mono">staff_021</span> · {new Date().toLocaleTimeString("ja-JP", {hour: "2-digit", minute: "2-digit"})}
                  </div>
                </div>
              </div>
            </div>
          )}

          {stage === "done" && (
            <div className="result-banner">
              <div className="rb-check">✓</div>
              <div>
                <div className="rb-title">¥{fmtJP(finalPrice)} で確定 — 経過 <span className="num">{fmtTime(frozenMs)}</span></div>
                <div className="rb-sub">
                  POSへ <span className="mono">price.confirmed</span> イベントを送信しました。LINE一次査定の参考値も同期されます。
                </div>
              </div>
              <div className="rb-side">
                <button className="btn" onClick={reset}>もう一枚 →</button>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

window.CoreView = CoreView;
