window.FB = window.FB || {};
FB.ShipTab = function ShipTab({ lang, user }) {
  const { useState, useEffect } = React;
  const t = FB.makeT(lang);
  const [store, setStore] = useState("MY0001");
  const [prices, setPrices] = useState(null);
  const [rows, setRows] = useState({});      // {sell_code:{qty, orig, done}}
  const [state, setState] = useState("idle");
  const [view, setView] = useState("ship");
  const [hist, setHist] = useState(null);
  const [paste, setPaste] = useState(null);
  const [orderMode, setOrderMode] = useState(false);
  const [chk, setChk] = useState(null);      // 库存/日用量参考
  const [review, setReview] = useState(null); // 核对表
  const [ordId, setOrdId] = useState(null);   // 门店待发订单 id
  const [ordDate, setOrdDate] = useState(null);
  const [detail, setDetail] = useState(null);   // 查看/修改某一单
  const [edits, setEdits] = useState({});
  const [amending, setAmending] = useState(false);
  const [photo, setPhoto] = useState(null);
  const [dup, setDup] = useState(null);          // 疑似重复出货 (submit_shipment v5 拦截)
  const [shipDate, setShipDate] = useState(null); // admin 补录旧单日期; null = 今天

  const draftKey = "fb_ship_draft_" + store;
  const todayStr = () => FB.todayLocal();
  // 草稿只在「当天」有效: 隔天自动作废, 否则今天没录入会看到昨天的数量照发
  function loadDraft(key) {
    try {
      const raw = JSON.parse(localStorage.getItem(key) || "null");
      if (!raw || !raw.d || raw.d !== todayStr()) { localStorage.removeItem(key); return {}; }
      return raw.rows || {};
    } catch (e) { localStorage.removeItem(key); return {}; }
  }
  useEffect(() => { FB.api.sellPrices().then(setPrices); FB.api.shipCheckData().then(setChk); }, []);
  useEffect(() => {
    const draft = loadDraft(draftKey);
    setOrdId(null); setOrdDate(null);
    FB.api.pendingOrder(store).then((res) => {
      if (!res) { setRows(draft); setOrderMode(Object.keys(draft).length > 0); return; }
      setOrdId(res.order.id); setOrdDate(res.order.order_date);
      if (Object.keys(draft).length) { setRows(draft); setOrderMode(true); return; }
      // 用 item_code 反查 sell_code
      FB.api.sellPrices().then((ps) => {
        const byItem = {};
        (ps || []).forEach((p) => { if (p.item_code) byItem[p.item_code] = p.sell_code; });
        const out = {};
        res.items.forEach((it) => {
          const sc = byItem[it.item_code];
          if (sc) out[sc] = { qty: Number(it.qty_ordered), orig: Number(it.qty_ordered), done: false };
        });
        setRows(out); setOrderMode(Object.keys(out).length > 0);
      });
    });
  }, [store]);
  useEffect(() => {
    if (!Object.keys(rows).length) { localStorage.removeItem(draftKey); return; }
    localStorage.setItem(draftKey, JSON.stringify({ d: todayStr(), rows }));
  }, [rows, store]);
  useEffect(() => { if (view === "history") FB.api.shipmentHistory().then(setHist); }, [view]);

  const nm = (p) => {
    const it = p.items || {};
    if (lang === "zh") return it.name_cn || p.name_en;
    if (lang === "vi") return it.name_vn || p.name_en;
    return p.name_en;
  };
  const cat = (p) => ((p.items || {}).category) || "Other";

  // 只显示有订量的行 (贴单后)；没订单时显示全部
  const active = (prices || []).filter((p) => rows[p.sell_code] != null);
  const shown = (orderMode && active.length) ? active : (prices || []);
  const groups = {};
  shown.forEach((p) => { const c = cat(p); (groups[c] = groups[c] || []).push(p); });

  const packedCount = shown.filter((p) => (rows[p.sell_code] || {}).done).length;
  const chosen = shown.filter((p) => Number((rows[p.sell_code] || {}).qty) > 0);

  // header 精华: AUSTIN · 已备 3/48 + 进度条 (滚到哪都看得见)
  useEffect(() => {
    if (!prices || !FB.setPageInfo) return;
    const sn = (FB.STORES.find((s) => s.id === store) || {}).name || store;
    FB.setPageInfo({
      text: sn.toUpperCase() + " · " + t("packed") + " " + packedCount + " / " + shown.length,
      num: packedCount, den: shown.length, color: "#4A7A1C",
    });
  }, [prices, store, packedCount, shown.length, lang]);

  function setQty(code, v) {
    setRows((r) => ({ ...r, [code]: { ...(r[code] || {}), qty: Math.max(0, v) } }));
  }
  function toggleDone(code) {
    setRows((r) => {
      const cur = r[code] || {};
      const nowDone = !cur.done;
      const q = Number(cur.qty) || 0;
      return { ...r, [code]: { ...cur, done: nowDone, qty: (nowDone && q === 0) ? 1 : cur.qty } };
    });
  }

  // 贴 WhatsApp 订货单 → 自动填数量
  function parseOrder(text) {
    const out = {};
    text.split(/\n/).forEach((line) => {
      const l = line.trim(); if (!l) return;
      const num = (l.match(/(\d+(?:\.\d+)?)\s*(?:pcs|pkt|pack|roll|btl|packs)?\s*$/i) || [])[1];
      if (!num) return;
      let hit = (prices || []).find((p) => l.toUpperCase().includes(p.sell_code));
      if (!hit) {
        const low = l.toLowerCase();
        hit = (prices || []).find((p) => {
          const en = (p.name_en || "").toLowerCase().split(" ")[0];
          const cn = ((p.items || {}).name_cn) || "";
          return (en.length > 3 && low.includes(en)) || (cn && l.includes(cn));
        });
      }
      if (hit) out[hit.sell_code] = { qty: Number(num), orig: Number(num), done: false };
    });
    setRows(out); setPaste(null); setOrderMode(Object.keys(out).length > 0);
  }

  function invoiceNo() {
    const d = new Date(); const p = (n) => String(n).padStart(2, "0");
    const sn = FB.STORES.find((s) => s.id === store).name.toUpperCase();
    return `INV-${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${sn}-${p(d.getHours())}${p(d.getMinutes())}`;
  }
  function buildInvoiceHtml(no) {
    const sname = FB.STORES.find((s) => s.id === store).name;
    const date = shipDate || FB.todayLocal();
    const list = chosen.map((p) => {
      const q = Number(rows[p.sell_code].qty);
      const price = Number(p.price) || 0;
      return { code: p.sell_code, name: p.name_en, qty: q, unit: p.sell_unit, price, amt: q * price };
    });
    return FB.invoiceHtml({ no, date, storeId: store, storeName: sname, rows: list, preparedBy: user.name });
  }
  // 风险评估: 🔴超库存 🟠超日用量5倍 🟡无参考
  function assess() {
    return chosen.map((p) => {
      const qtySell = Number(rows[p.sell_code].qty);
      const ut = Number(p.unit_transfer) || 1;
      const qtyItem = qtySell / ut;
      const ref = (chk || {})[p.item_code];
      let level = "ok", msg = "";
      if (!p.item_code || !ref) { level = "warn"; msg = lang === "zh" ? "无库存参考" : lang === "vi" ? "Không có dữ liệu" : "no reference"; }
      else {
        const days = ref.usage > 0 ? qtyItem / ref.usage : null;
        if (ref.stock > 0 && qtyItem > ref.stock) {
          level = "bad";
          msg = (lang === "zh" ? "超过库存 " : lang === "vi" ? "Vượt tồn " : "over stock ") + Math.round(ref.stock * 10) / 10;
        } else if (days != null && days > 5) {
          level = "warn";
          msg = "≈" + Math.round(days) + (lang === "zh" ? " 天用量" : lang === "vi" ? " ngày dùng" : " days usage");
        }
      }
      return { p, qtySell, level, msg, stock: ref ? ref.stock : null };
    });
  }
  function isToday(ts) { return FB.localDate(ts) === FB.todayLocal(); }

  async function doAmend() {
    if (!detail) return;
    setAmending(true);
    const sameDay = isToday(detail.ms[0].moved_at);
    const lines = detail.ms.map((m) => ({
      item_code: m.item_code,
      qty: edits[m.item_code] != null ? Number(edits[m.item_code]) : Math.abs(m.qty),
      unit: m.unit,
    }));
    const r = await FB.api.amendShipment({
      ref_id: detail.ref, mode: sameDay ? "edit" : "reverse",
      lines, created_by: user.name, reason: sameDay ? null : "\u540e\u8865\u4fee\u6b63",
    });
    setAmending(false);
    if (r && !r.error) { setDetail(null); setEdits({}); FB.api.shipmentHistory().then(setHist); }
  }

  function reprint(d) {
    const priceOf = {}; (prices || []).forEach((p) => { if (p.item_code) priceOf[p.item_code] = p; });
    const rowsHtml = d.ms.map((m) => {
      const p = priceOf[m.item_code] || {};
      const q = edits[m.item_code] != null ? Number(edits[m.item_code]) : Math.abs(m.qty);
      const price = Number(p.price) || 0;
      return { code: p.sell_code || m.item_code, name: p.name_en || m.item_code, qty: q, unit: p.sell_unit || m.unit || "", price, amt: q * price };
    }).filter((r) => r.qty > 0);
    const sid = d.ms[0].store_id;
    const sname = (FB.STORES.find((s) => s.id === sid) || {}).name || sid;
    const date = String(d.ms[0].moved_at).slice(0, 10);
    const no = "INV-" + date.replace(/-/g, "") + "-" + String(sname).toUpperCase() + "-R";
    const html = FB.invoiceHtml({ no, date, storeId: sid, storeName: sname, rows: rowsHtml, preparedBy: user.name });
    const w = window.open("", "_blank"); if (w) { w.document.write(html); w.document.close(); }
  }

  function openReview() { if (chosen.length) setReview(assess()); }

  async function ship(force) {
    if (!chosen.length) return;
    setState("sending");
    const lines = chosen.filter((p) => p.item_code).map((p) => ({ item_code: p.item_code, qty: Number(rows[p.sell_code].qty), unit: p.sell_unit }));
    const no = invoiceNo();
    const payload = { store_id: store, lines, created_by: user.name };
    if (shipDate && shipDate !== todayStr()) payload.ship_date = shipDate;
    if (force) payload.force = true;
    const r = await FB.api.submitShipment(payload);
    if (r && r.duplicate_suspect) { setState("idle"); setDup(r); return; }
    if (r.error || !r.ok) { setState("error"); return; }
    if (ordId) {
      await FB.api.closeOrder({
        order_id: ordId, invoice_no: no,
        shipped: chosen.filter((p) => p.item_code).map((p) => ({ item_code: p.item_code, qty: Number(rows[p.sell_code].qty) })),
      });
    }
    const w = window.open("", "_blank");
    if (w) { w.document.write(buildInvoiceHtml(no)); w.document.close(); }
    setState("ok"); setRows({}); setOrderMode(false); setReview(null); setOrdId(null); setDup(null); setShipDate(null); localStorage.removeItem(draftKey);
  }

  if (view === "history") return (
    <div className="px-3 py-3 max-w-md mx-auto pb-20">
      <button onClick={() => setView("ship")} className="text-xs text-stone-500 mb-3">← {t("shipTitle")}</button>
      {!hist && <p className="text-sm text-stone-400">{t("loading")}</p>}
      {hist && Object.entries(hist.reduce((a, m) => { (a[m.ref_id] = a[m.ref_id] || []).push(m); return a; }, {})).map(([ref, ms]) => {
        const sn = (FB.STORES.find((s) => s.id === ms[0].store_id) || {}).name || ms[0].store_id;
        return (
          <button key={ref} onClick={() => { setDetail({ ref, ms }); setEdits({}); }}
            className="w-full text-left rounded-xl border border-stone-200 bg-white p-3 mb-2 active:bg-stone-50">
            <div className="flex justify-between items-center">
              <div>
                <p className="text-sm font-medium text-stone-800">{sn}</p>
                <p className="text-[11px] text-stone-400">{String(ms[0].moved_at).slice(0, 16).replace("T", " ")} · {ms.length} {lang === "zh" ? "项" : "items"}</p>
              </div>
              <span className="text-stone-300 text-lg">›</span>
            </div>
          </button>
        );
      })}

      {detail && (
        <div className="fixed inset-0 z-40 flex items-end" style={{ background: "rgba(28,25,23,.45)" }}>
          <div className="bg-white w-full rounded-t-3xl max-h-[88vh] flex flex-col">
            <div className="px-4 pt-4 pb-2 border-b border-stone-100">
              <p className="text-[16px] font-semibold text-stone-900">
                {(FB.STORES.find((s) => s.id === detail.ms[0].store_id) || {}).name}
              </p>
              <p className="text-[11px] text-stone-400 mt-0.5">
                {String(detail.ms[0].moved_at).slice(0, 16).replace("T", " ")} ·{" "}
                <span style={{ color: isToday(detail.ms[0].moved_at) ? "#16A34A" : "#B45309" }}>
                  {isToday(detail.ms[0].moved_at)
                    ? (lang === "zh" ? "当天 · 可直接改" : "same day · direct edit")
                    : (lang === "zh" ? "隔天 · 改动会写冲正流水" : "later day · writes correction")}
                </span>
              </p>
            </div>
            <div className="overflow-y-auto flex-1 px-4 py-2">
              {detail.ms.map((m) => {
                const orig = Math.abs(m.qty);
                const cur = edits[m.item_code] != null ? edits[m.item_code] : orig;
                const changed = Number(cur) !== orig;
                return (
                  <div key={m.item_code} className="flex items-center gap-2 py-2 border-b border-stone-50">
                    <div className="flex-1 min-w-0">
                      <p className="text-[14px] text-stone-800 truncate">{m.item_code}</p>
                      {changed && <p className="text-[11px] text-amber-700">{lang === "zh" ? "原" : "was"} {orig}</p>}
                    </div>
                    <input type="number" inputMode="decimal" value={cur}
                      onChange={(e) => setEdits((x) => ({ ...x, [m.item_code]: e.target.value }))}
                      className="w-16 h-9 px-2 rounded-lg border text-center text-sm"
                      style={{ borderColor: changed ? "#B45309" : "#E7E5E4" }} />
                    <span className="text-[10px] text-stone-400 w-8">{m.unit || ""}</span>
                  </div>
                );
              })}
            </div>
            <div className="px-4 py-3 pb-safe border-t border-stone-100 flex gap-2">
              <button onClick={() => { setDetail(null); setEdits({}); }}
                className="px-4 h-11 rounded-xl border border-stone-200 text-stone-500 text-sm">
                {lang === "zh" ? "关闭" : "Close"}
              </button>
              <button onClick={() => reprint(detail)}
                className="px-4 h-11 rounded-xl border border-stone-300 text-stone-700 text-sm">
                {lang === "zh" ? "补发单据" : "Reprint"}
              </button>
              <button onClick={doAmend} disabled={amending || !Object.keys(edits).length}
                className="flex-1 h-11 rounded-xl bg-red-700 text-white text-sm font-medium disabled:opacity-30">
                {amending ? "…" : (lang === "zh" ? "保存修改" : "Save")}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );

  return (
    <div className="max-w-md mx-auto pb-28">
      <div className="px-4 pt-4 pb-3">
        <h1 className="text-[22px] font-semibold text-stone-900 tracking-tight">{t("shipTitle")}</h1>
        <p className="text-[12px] text-stone-400 mt-1 leading-snug">{t("shipHint")}</p>
      </div>

      <div className="px-4 flex items-center gap-2 mb-2">
        {FB.STORES.map((s) => (
          <button key={s.id} onClick={() => setStore(s.id)}
            className={"px-4 h-9 rounded-full text-xs transition-colors " + (store === s.id ? "bg-red-700 text-white font-semibold" : "bg-white text-stone-500 border border-stone-200")}>
            {s.name.toUpperCase()}
          </button>
        ))}
        {ordId ? (
          <span className="ml-auto text-[11px] tabular-nums flex items-center gap-1" style={{ color: "#C2540A" }}>
            <FB.UI.Icon name="paste" size={12} />{ordDate}
          </span>
        ) : null}
      </div>

      <div className="px-4 flex gap-2 mb-3">
        <button onClick={() => setPaste("")}
          className="flex-1 h-10 rounded-xl border border-stone-200 bg-white text-xs text-stone-500 active:bg-stone-50 flex items-center justify-center gap-1.5">
          <FB.UI.Icon name="paste" size={14} />{t("pasteOrder")}</button>
        <button onClick={() => setView("history")}
          className="px-4 h-10 rounded-xl border border-stone-200 bg-white text-xs text-stone-500 active:bg-stone-50 flex items-center justify-center gap-1.5">
          <FB.UI.Icon name="history" size={14} />{t("history")}</button>
        {user.role === "admin" && (
          <input type="date" value={shipDate || todayStr()} max={todayStr()}
            onChange={(e) => setShipDate(e.target.value === todayStr() ? null : e.target.value)}
            aria-label="ship date"
            className="px-2 h-10 rounded-xl border bg-white text-xs"
            style={{ borderColor: shipDate ? "#C2540A" : "#E7E5E4", color: shipDate ? "#C2540A" : "#78716C", maxWidth: 132 }} />
        )}
      </div>
      {/* admin 补录旧单: 选了过去日期就进补录模式, 流水记该日中午 */}
      {shipDate && (
        <p className="px-4 -mt-1 mb-2 text-[11px] font-medium" style={{ color: "#C2540A" }}>
          {lang === "zh" ? `补录模式: 这单会记为 ${shipDate} 的出货`
            : lang === "vi" ? `Ghi bù: đơn này tính cho ngày ${shipDate}`
            : `Backfill: will be recorded as ${shipDate}`}
        </p>
      )}
      {/* H3 贴单改底部弹层 */}
      {paste != null && (
        <FB.UI.Sheet onClose={() => setPaste(null)}>
          <p className="text-[15px] font-semibold text-stone-900 mb-2">{t("pasteOrder")}</p>
          <textarea value={paste} onChange={(e) => setPaste(e.target.value)} rows={7} placeholder={t("pastePlaceholder")}
            autoFocus className="w-full p-3 rounded-xl border border-stone-300 text-sm" />
          <div className="flex gap-2 mt-3">
            <button onClick={() => { setRows({}); setPaste(null); setOrderMode(false); }}
              className="px-4 h-12 rounded-xl border border-stone-200 text-sm text-stone-500">{t("clear")}</button>
            <button onClick={() => parseOrder(paste)}
              className="flex-1 h-12 rounded-xl bg-red-700 text-white text-sm font-semibold">{t("parse")}</button>
          </div>
        </FB.UI.Sheet>
      )}

      {!prices && <p className="px-4 text-sm text-stone-400">{t("loading")}</p>}

      {Object.entries(groups).map(([c, list]) => (
        <div key={c} className="mb-1">
          <p className="px-4 py-2 text-[11px] font-semibold text-stone-500 flex items-center gap-1.5">
            <span className="rounded-sm" style={{ width: 3, height: 11, background: "#B91C1C" }} />{c}
          </p>
          <div className="bg-white border-y border-stone-200/70">
            {list.map((p) => {
              const r = rows[p.sell_code] || {};
              const q = Number(r.qty) || 0;
              const done = !!r.done;
              return (
                <div key={p.sell_code} className="flex items-center gap-2.5 px-4 py-3 border-b border-stone-100 last:border-0"
                  style={done ? { background: "#FDFEFB" } : {}}>
                  <button onClick={() => toggleDone(p.sell_code)} aria-label={t("packed")}>
                    <FB.UI.CheckCircle on={done} size={40} square />
                  </button>
                  <div className="flex-1 min-w-0" onClick={() => setPhoto({ code: p.item_code, name: nm(p) })}>
                    <p className={"text-[15px] leading-tight truncate " + (done ? "text-stone-400 line-through" : "text-stone-900 font-medium")}>{nm(p)}</p>
                    <p className="text-[11px] text-stone-400 leading-tight mt-0.5">
                      {p.sell_code}{r.orig != null ? <span className="ml-1.5">· {t("ordered")} {r.orig}</span> : null}
                    </p>
                  </div>
                  {/* H1 数量可打字 (贴单先填一轮, 打字是微调) */}
                  <FB.UI.Qty value={q} unit={p.sell_unit.toLowerCase()}
                    onChange={(v) => setQty(p.sell_code, v)} />
                </div>
              );
            })}
          </div>
        </div>
      ))}

      {review && (
        <div className="fixed inset-0 z-40 flex items-end" style={{ background: "rgba(28,25,23,.45)" }}>
          <div className="bg-white w-full rounded-t-3xl max-h-[85vh] flex flex-col">
            <div className="px-4 pt-4 pb-2 border-b border-stone-100">
              <p className="text-[17px] font-semibold text-stone-900">
                {lang === "zh" ? "出货前核对" : lang === "vi" ? "Ki\u1ec3m tra tr\u01b0\u1edbc khi giao" : "Review before shipping"}
              </p>
              <p className="text-[12px] text-stone-400 mt-0.5">
                {FB.STORES.find((x) => x.id === store).name} · {review.length} {lang === "zh" ? "项" : "items"}
                {review.filter((r) => r.level !== "ok").length > 0 &&
                  <span className="text-amber-700"> · {review.filter((r) => r.level !== "ok").length} {lang === "zh" ? "项要看" : lang === "vi" ? "c\u1ea7n xem" : "to check"}</span>}
              </p>
            </div>
            <div className="overflow-y-auto flex-1 px-4 py-2">
              {review.map((r) => {
                const bg = r.level === "bad" ? "#FCEDEA" : r.level === "warn" ? "#FDF2E8" : "transparent";
                const tc = r.level === "bad" ? "#A81E12" : r.level === "warn" ? "#C2540A" : "#78716C";
                return (
                  <div key={r.p.sell_code} className="flex items-center gap-2.5 py-2 px-2.5 rounded-lg mb-0.5"
                    style={{ background: bg, borderLeft: "3px solid " + (r.level === "ok" ? "transparent" : tc) }}>
                    <div className="flex-1 min-w-0">
                      <p className="text-[14px] text-stone-800 truncate">{nm(r.p)}</p>
                      <p className="text-[11px]" style={{ color: r.msg ? tc : "#A8A29E" }}>
                        {r.p.sell_code}{r.msg ? " · " + r.msg : ""}
                      </p>
                    </div>
                    <span className="text-[17px] font-bold tabular-nums" style={{ color: r.level === "ok" ? "#1C1917" : tc }}>{r.qtySell}</span>
                    <span className="text-[10px] text-stone-400 w-8">{r.p.sell_unit.toLowerCase()}</span>
                  </div>
                );
              })}
            </div>
            <div className="px-4 py-3 pb-safe border-t border-stone-100 flex gap-2">
              <button onClick={() => setReview(null)}
                className="px-5 h-12 rounded-xl border border-stone-200 text-stone-500 text-sm">
                {lang === "zh" ? "返回改" : lang === "vi" ? "Quay l\u1ea1i" : "Back"}
              </button>
              <button onClick={() => ship(false)} disabled={state === "sending"}
                className="flex-1 h-12 rounded-xl bg-red-700 text-white font-medium active:scale-[0.98] disabled:opacity-40">
                {state === "sending" ? t("submitting") : (lang === "zh" ? "确认出货" : lang === "vi" ? "X\u00e1c nh\u1eadn giao" : "Confirm shipment")}
              </button>
            </div>
          </div>
        </div>
      )}

      {photo && photo.code && <FB.PhotoView code={photo.code} name={photo.name} lang={lang} onClose={() => setPhoto(null)} />}

      {/* 疑似重复出货 — submit_shipment v5 拦下来, 用户确认后才 force 重发 */}
      {dup && (
        <div className="fixed inset-0 z-50 flex items-end" style={{ background: "rgba(28,25,23,.45)" }}>
          <div className="bg-white w-full rounded-t-3xl p-4 pb-safe">
            <p className="text-[17px] font-semibold" style={{ color: "#A81E12" }}>
              {lang === "zh" ? "疑似重复出货" : lang === "vi" ? "Nghi trùng đơn giao" : "Possible duplicate shipment"}
            </p>
            <p className="text-[13px] text-stone-600 mt-2 leading-relaxed">
              {lang === "zh"
                ? `这单和 ${dup.duplicate_date} 已记的出货 ${dup.similarity}% 相同。已经记过的单不要再记一次。`
                : lang === "vi"
                ? `Đơn này giống ${dup.similarity}% với đơn đã ghi ngày ${dup.duplicate_date}. Đơn ghi rồi thì đừng ghi lại.`
                : `${dup.similarity}% identical to the shipment recorded on ${dup.duplicate_date}. Do not re-enter a recorded shipment.`}
            </p>
            <div className="flex gap-2 mt-4">
              <button onClick={() => setDup(null)}
                className="flex-1 h-12 rounded-xl bg-red-700 text-white text-sm font-semibold">
                {lang === "zh" ? "取消 (是重复)" : lang === "vi" ? "Huỷ (bị trùng)" : "Cancel (duplicate)"}
              </button>
              <button onClick={() => { setDup(null); ship(true); }}
                className="px-4 h-12 rounded-xl border border-stone-300 text-stone-600 text-sm">
                {lang === "zh" ? "不是重复, 照提交" : lang === "vi" ? "Không trùng, vẫn gửi" : "Not duplicate, submit"}
              </button>
            </div>
          </div>
        </div>
      )}

      <FB.UI.Sticky>
        <button onClick={openReview} disabled={state === "sending" || !chosen.length}
          className="w-full h-12 rounded-xl bg-red-700 text-white font-semibold active:scale-[0.98] transition-transform disabled:opacity-30">
          {state === "sending" ? t("submitting") : `${t("makeInvoice")} · ${chosen.length}`}
        </button>
        {!chosen.length && (
          <p className="text-[11px] text-stone-400 text-center mt-1.5">
            {lang === "zh" ? "打勾或用 + 设数量后才能生成" : lang === "vi" ? "Tick ho\u1eb7c b\u1ea5m + \u0111\u1ec3 nh\u1eadp s\u1ed1 l\u01b0\u1ee3ng" : "Tick an item or set a qty first"}
          </p>
        )}
      </FB.UI.Sticky>
    </div>
  );
};
