window.FB = window.FB || {};

// 「今天做什么」— 2026-07-30 建，同日加 V6(计时/时间轴/出货倒数/提前做明天)。
// 生产没人记的根因假设: app 从没告诉员工今天该做什么。
// 这页把「该做什么」和「做完记一笔」并成一步 —— 看到 → 开始 → 完成 → 生产流水+实测工时自动写。
//
// 排班来自 Shanqian 07-30 口述(资料清单 B 节):
//   面包日 = 周二/四/六 · 肉日 = 周一/三/五 · 周日休(她自己出货不生产)
//   Thi(team lead) = 面包 · 酱料 · 出货 · 点货 · 检查绞肉
//   Xuyen = 炸薯片 · 备菜 · 煮 topping · 打扫 · 备马铃薯
//   解冻提前 1–2 天 → 肉日前一天要移冷藏(鸡+牛一起, 羊单独)
//   出货: Kulai 15:00 前 · Austin 15:30 前 → 备货截止 14:30
// 优先级(B5): 🔴面包/肉饼/招牌酱/焦糖洋葱/MixCheese/CheeseSauce 🟠薯片/烤薯泥 🟢其他
FB.TODAY_PLAN = {
  // isoDay: 1=一 … 7=日
  1: { kind: "meat",  cn: "肉日",   vn: "Ngày thịt",  en: "Meat day" },
  2: { kind: "bread", cn: "面包日", vn: "Ngày bánh",  en: "Bread day" },
  3: { kind: "meat",  cn: "肉日",   vn: "Ngày thịt",  en: "Meat day" },
  4: { kind: "bread", cn: "面包日", vn: "Ngày bánh",  en: "Bread day" },
  5: { kind: "meat",  cn: "肉日",   vn: "Ngày thịt",  en: "Meat day" },
  6: { kind: "bread", cn: "面包日", vn: "Ngày bánh",  en: "Bread day" },
  7: { kind: "off",   cn: "休息",   vn: "Nghỉ",       en: "Rest" },
};
// 当日主角 (其余成品按缺货程度补进来)
FB.TODAY_FOCUS = { bread: ["FB001"], meat: ["FM001", "FM002", "FM003"], off: [] };
// 谁负责 (显示用, 不做权限)
FB.TODAY_WHO = {
  FB001: "Thi + Xuyen", FM001: "Thi", FM002: "Thi", FM003: "Thi",
  FP001: "Xuyen", FP003: "Xuyen", FT001: "Xuyen", FT004: "Xuyen",
};
// 建议开工时间 (B3 工时: 面包 30pack≈5h · 肉饼 1批≈5h · 酱≈1h · 薯片待实测)
// 只用来排时间轴顺序和「现在」线, 不是硬规定
FB.TODAY_TIME = { FB001: "09:00", FM001: "09:00", FM002: "09:00", FM003: "09:00", FP001: "11:00", FP003: "11:00" };
FB.TODAY_TIME_BY_PREFIX = [["FS", "10:30"], ["FT", "13:00"], ["FP", "11:00"], ["FM", "09:00"], ["FB", "09:00"]];
// 「一批」到底是多少 —— 07-30 肉饼改成「1 批 = 1 箱原料」后必须让员工看得到,
// 不然按旧习惯(1 包 = 1 批)报数, 扣料会差几十倍。写在卡上比发通知可靠: 通知会忘, 卡片天天在眼前。
FB.BATCH_NOTE = {
  FM001: { cn: "1 批 = 2 箱鸡肉(24kg)→ 20 包", vn: "1 mẻ = 2 thùng gà (24kg) → 20 gói", en: "1 batch = 2 ctn chicken (24kg) → 20 packs" },
  FM002: { cn: "1 批 = 1 箱牛肉 20kg + 5kg 牛油脂 → 25 包", vn: "1 mẻ = 1 thùng bò 20kg + 5kg mỡ bò → 25 gói", en: "1 batch = 1 ctn beef 20kg + 5kg fat → 25 packs" },
  FM003: { cn: "1 批 = 1 箱羊肉 27.2kg → 27 包", vn: "1 mẻ = 1 thùng cừu 27.2kg → 27 gói", en: "1 batch = 1 ctn lamb 27.2kg → 27 packs" },
};
FB.TODAY_DEADLINE = "14:30";     // 备货截止 (Kulai 15:00 / Austin 15:30)
FB.TODAY_ALERT_MIN = 30;         // 截止前几分钟开始报警
FB.TODAY_THAW_CODES = ["FM001", "FM002", "FM003"];  // 要提前解冻的, 不能当天临时做

FB.TodayTab = function TodayTab({ lang, user }) {
  const { useState, useEffect, useRef } = React;
  const t = FB.makeT(lang);
  const L = (zh, vi, en) => (lang === "zh" ? zh : lang === "vi" ? vi : en);

  const [runway, setRunway] = useState(null);
  const [sug, setSug] = useState(null);
  const [goods, setGoods] = useState(null);
  const [done, setDone] = useState({});        // {code: batch数}
  const [busy, setBusy] = useState(false);
  const [okMsg, setOkMsg] = useState(null);
  const [photo, setPhoto] = useState(null);
  const [logged, setLogged] = useState(null);  // 今天已记的生产
  const [timer, setTimer] = useState({});      // {code: {startedAt, acc, done, workers}}
  const [extra, setExtra] = useState([]);      // 从「明天」提前拉上来做的
  const [, setTick] = useState(0);             // 只用来触发重画; 时间一律现读 Date.now()
  const alerted = useRef(false);

  const isoDay = (() => { const d = new Date().getDay(); return d === 0 ? 7 : d; })();
  const plan = FB.TODAY_PLAN[isoDay] || FB.TODAY_PLAN[7];
  const tomorrow = FB.TODAY_PLAN[isoDay === 7 ? 1 : isoDay + 1] || {};
  const today10 = FB.todayLocal();
  const TKEY = "fb_today_timer_v1";

  // 计时状态存本地: 面包一批要 9 小时, 中间刷新/关页面不能丢
  useEffect(() => {
    try {
      const raw = JSON.parse(localStorage.getItem(TKEY) || "null");
      if (raw && raw.day === today10 && raw.t) setTimer(raw.t);
    } catch (e) { /* 坏数据就当没有 */ }
  }, []);
  function saveTimer(next) {
    setTimer(next);
    try { localStorage.setItem(TKEY, JSON.stringify({ day: today10, t: next })); } catch (e) {}
  }

  function load() {
    FB.api.stockRunway().then(setRunway);
    FB.api.productionSuggest().then(setSug);
    FB.api.finishedForProd().then(setGoods);
    if (FB.api.todayProduction) FB.api.todayProduction().then(setLogged);
  }
  useEffect(() => { load(); }, []);
  // 1 秒一跳只为重画。⚠️ 别把这个 tick 当时间用: 手机锁屏/切后台时浏览器会把 setInterval
  // 节流到 1 分钟一次, 存进 state 的时间就变旧了 —— 曾因此让已开始的计时显示负数(-1:-34)。
  // 所有时间在 render 里现读 Date.now(), 回到前台再补一次重画。
  useEffect(() => {
    const iv = setInterval(() => setTick((n) => n + 1), 1000);
    const wake = () => setTick((n) => n + 1);
    document.addEventListener("visibilitychange", wake);
    return () => { clearInterval(iv); document.removeEventListener("visibilitychange", wake); };
  }, []);

  const num = (x) => Number(x) || 0;
  const nmOf = (r) => FB.nm(r, lang);
  const hhmm = (d) => String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
  const toMin = (s) => { const p = String(s).split(":"); return num(p[0]) * 60 + num(p[1]); };
  const fmtSec = (s0) => {
    const s = Math.max(0, Math.floor(num(s0)));   // 永不显示负数
    const m = Math.floor(s / 60);
    return m >= 60 ? Math.floor(m / 60) + "h" + String(m % 60).padStart(2, "0") : m + ":" + String(s % 60).padStart(2, "0");
  };
  const elapsed = (st) =>
    num(st && st.acc) + (st && st.startedAt ? Math.max(0, Math.floor((Date.now() - st.startedAt) / 1000)) : 0);
  const timeOf = (code) => {
    if (FB.TODAY_TIME[code]) return FB.TODAY_TIME[code];
    const hit = FB.TODAY_TIME_BY_PREFIX.find(([p]) => String(code).startsWith(p));
    return hit ? hit[1] : "11:00";
  };

  // ── 今天该做的成品 ──
  // 只看成品线(没供应商=自己做), 三档: 已断 → 快断 → 当日主角
  const rw = runway || [];
  const madeHere = rw.filter((r) => !r.supplier_name);
  const focus = FB.TODAY_FOCUS[plan.kind] || [];
  const sugMap = {}; (sug || []).forEach((s) => { sugMap[s.output_code] = s; });
  const goodsMap = {}; (goods || []).forEach((g) => { goodsMap[g.code] = g; });
  const loggedMap = {}; (logged || []).forEach((l) => { loggedMap[l.item_code] = num(l.batch_qty); });
  const planKey = lang === "vi" ? "vn" : lang === "zh" ? "cn" : "en";

  const seen = {};
  const jobs = [];
  function push(code, why, rank) {
    if (seen[code]) return;
    const r = madeHere.find((x) => x.code === code);
    const g = goodsMap[code];
    if (!r && !g) return;
    seen[code] = 1;
    jobs.push({
      code,
      name: r ? nmOf(r) : (g ? FB.nm(g, lang) : code),
      qty: r ? num(r.qty) : null,
      unit: (r && r.unit) || (g && g.unit) || "",
      runway: r ? num(r.runway_days) : null,
      suggest: sugMap[code] ? num(sugMap[code].suggest_batches) : null,
      perBatch: g && g["一批几包"] ? num(g["一批几包"]) : null,
      who: FB.TODAY_WHO[code] || null,
      at: timeOf(code),
      why, rank,
    });
  }
  // 1 已断的成品 (最急)
  madeHere.filter((r) => num(r.qty) <= 0).sort((a, b) => num(a.qty) - num(b.qty))
    .forEach((r) => push(r.code, L("已经断了", "Đã hết", "out of stock"), 1));
  // 2 当日主角
  focus.forEach((c) => push(c, plan[planKey], 2));
  // 3 快断的成品
  madeHere.filter((r) => num(r.qty) > 0).sort((a, b) => num(a.runway_days) - num(b.runway_days))
    .forEach((r) => push(r.code, L("撑不了几天", "Sắp hết", "running low"), 3));
  // 4 从明天提前拉上来的
  extra.forEach((c) => push(c, L("提前做", "Làm trước", "ahead"), 4));
  // 按建议时间排 (时间相同再按急迫度) —— 这样「现在」线才有意义
  jobs.sort((a, b) => (toMin(a.at) - toMin(b.at)) || (a.rank - b.rank));

  // ── 明天可以提前做的 (要解冻的锁住) ──
  const tmrFocus = (FB.TODAY_FOCUS[tomorrow.kind] || []).filter((c) => !seen[c]);

  // ── 出货倒数 ──
  const nowD = new Date();                      // 现读, 不用 tick 的值
  const nowMin = nowD.getHours() * 60 + nowD.getMinutes();
  const leftMin = toMin(FB.TODAY_DEADLINE) - nowMin;
  const anyUnfinished = jobs.some((j) => !loggedMap[j.code] && (timer[j.code] || {}).done == null);
  const hot = leftMin > 0 && leftMin <= FB.TODAY_ALERT_MIN && anyUnfinished;
  useEffect(() => {
    if (hot && !alerted.current) { alerted.current = true; beep(); }
    if (!hot) alerted.current = false;
  }, [hot]);
  function beep() {
    // 页面自己响 —— 不靠系统通知(手机上不给权限也能响)
    try {
      const Ctx = window.AudioContext || window.webkitAudioContext; if (!Ctx) return;
      const ctx = new Ctx();
      [0, 0.5, 1].forEach((off) => {
        const o = ctx.createOscillator(), g = ctx.createGain();
        o.connect(g); g.connect(ctx.destination); o.frequency.value = 1200;
        g.gain.setValueAtTime(0.3, ctx.currentTime + off);
        g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + off + 0.4);
        o.start(ctx.currentTime + off); o.stop(ctx.currentTime + off + 0.45);
      });
    } catch (e) {}
  }

  // ── 计时 ──
  function start(code) {
    const st = timer[code] || {};
    saveTimer({ ...timer, [code]: { startedAt: Date.now(), acc: num(st.acc), workers: st.workers || 1 } });
  }
  function finish(code, suggest) {
    const st = timer[code] || {};
    const secs = elapsed(st) || 1;
    saveTimer({ ...timer, [code]: { startedAt: null, acc: secs, done: secs, workers: st.workers || 1, finishedAt: Date.now(), firstStart: st.firstStart || st.startedAt } });
    // 顺手把批数填上(建议值), 省得再点步进器
    setDone((d) => (num(d[code]) > 0 ? d : { ...d, [code]: String(suggest && suggest > 0 ? suggest : 1) }));
  }
  // 误按完成 → 回到计时(时间接着走) · 误按开始 → 暂停但保留时间(再按开始续计)
  function undo(code) {
    const st = timer[code]; if (!st) return;
    if (st.done != null) { const n = { ...st }; delete n.done; delete n.finishedAt; n.startedAt = Date.now(); saveTimer({ ...timer, [code]: n }); return; }
    if (st.startedAt) { saveTimer({ ...timer, [code]: { ...st, acc: elapsed(st), startedAt: null } }); }
  }
  function cycleWorkers(code) {
    const st = timer[code] || {};
    const w = (st.workers || 1) % 3 + 1;
    saveTimer({ ...timer, [code]: { ...st, workers: w } });
  }

  const picked = Object.entries(done).filter(([, n]) => num(n) > 0);
  useEffect(() => {
    if (runway && FB.setPageInfo)
      FB.setPageInfo({ text: plan[planKey] + " · " + jobs.length + L(" 项", " mục", " jobs"), num: picked.length, den: jobs.length });
  }, [runway, jobs.length, picked.length, lang]);

  async function submit() {
    if (!picked.length) return;
    setBusy(true); setOkMsg(null);
    const lines = picked.map(([output_code, n]) => {
      const st = timer[output_code] || {};
      const mins = st.done != null ? Math.max(1, Math.round(st.done / 60)) : null;
      return {
        output_code, batch: num(n),
        minutes: mins,
        workers: mins ? (st.workers || 1) : null,
        started_at: mins && st.firstStart ? new Date(st.firstStart).toISOString() : null,
        finished_at: mins && st.finishedAt ? new Date(st.finishedAt).toISOString() : null,
      };
    });
    const r = await FB.api.submitProduction({ lines, produced_by: user.name });
    setBusy(false);
    if (!r || r.error || !r.ok) { setOkMsg({ ok: false, text: String((r && r.error) || "failed").slice(0, 120) }); return; }
    setOkMsg({ ok: true, text: L("记好了", "Đã ghi", "Logged") + " · " + r.results.map((x) => x.output_code + "×" + x.batch + (x.minutes ? " " + x.minutes + "min" : "")).join(", ") });
    // 交过的清掉计时, 没交的留着
    const nt = { ...timer }; picked.forEach(([c]) => delete nt[c]); saveTimer(nt);
    setDone({});
    load();
  }

  // ── 休息日 ──
  if (plan.kind === "off") return (
    <div className="px-3 py-3 max-w-md mx-auto">
      <div className="rounded-2xl border border-stone-200 bg-white p-8 text-center">
        <p className="text-[20px] font-semibold text-stone-800">{L("今天休息", "Hôm nay nghỉ", "Rest day")}</p>
        <p className="text-[13px] text-stone-400 mt-2">{L("礼拜天不生产", "Chủ nhật không sản xuất", "No production on Sunday")}</p>
      </div>
    </div>
  );

  // 一张任务卡 —— 按钮固定宽固定位(不跳位), 撤销固定右上角
  function Card({ j }) {
    const st = timer[j.code] || {};
    const isDone = st.done != null, running = !!st.startedAt && !isDone, paused = !running && !isDone && num(st.acc) > 0;
    const n = done[j.code] || "";
    const already = loggedMap[j.code];
    const col = j.rank === 1 ? "#A81E12" : j.rank === 2 ? "#C2540A" : j.rank === 4 ? "#4A7A1C" : "#A07A06";
    return (
      <div className="relative rounded-xl border border-stone-200 bg-white p-3 ml-4"
        style={{ borderLeft: "3px solid " + col, background: isDone ? "#F7FDF9" : "#fff" }}>
        {/* 时间轴圆点 */}
        <span className="absolute rounded-full" style={{
          left: "-22px", top: "18px", width: "8px", height: "8px",
          background: isDone ? "#4A7A1C" : "#D6D3D1",
        }} />
        {/* 撤销: 固定右上角, 离主按钮远 */}
        {(running || isDone || paused) ? (
          <button onClick={() => undo(j.code)} title={L("撤销", "Hoàn tác", "Undo")}
            className="absolute top-1.5 right-2 w-7 h-7 rounded-md bg-stone-100 text-stone-500 text-[14px] leading-none active:scale-95">↩</button>
        ) : null}

        <div className="flex items-center gap-2 pr-8">
          <span className="text-[11px] text-stone-400 tabular-nums shrink-0">{j.at}</span>
          <span className="text-[14.5px] font-semibold text-stone-900 truncate min-w-0">{j.name}</span>
          {j.who ? <FB.UI.Chip>{j.who}</FB.UI.Chip> : null}
        </div>
        <div className="flex items-center gap-1.5 mt-0.5 pr-8">
          <span className="text-[12px] font-bold" style={{ color: col }}>{j.why}</span>
        </div>

        {/* 「一批」是多少 —— 改了口径就必须写在卡上, 员工不会去翻通知 */}
        {FB.BATCH_NOTE[j.code] ? (
          <p className="text-[11.5px] mt-1.5 px-2 py-1 rounded-md"
            style={{ background: "#FBF6E5", color: "#7A5E06" }}>
            ⚖️ {FB.BATCH_NOTE[j.code][lang === "vi" ? "vn" : lang === "zh" ? "cn" : "en"]}
          </p>
        ) : null}

        <div className="flex items-center gap-2 mt-1.5 text-[11px] text-stone-500 flex-wrap">
          {j.qty != null ? <span>{L("现存", "Tồn", "have")} {j.qty} {j.unit}</span> : null}
          {j.runway != null ? <span>· {L("撑", "còn", "lasts")} {j.runway}{L("天", "n", "d")}</span> : null}
          {j.suggest ? <span>· {L("建议", "đề xuất", "suggest")} {j.suggest} {t("batch")}</span> : null}
          {j.perBatch ? <span>· {j.perBatch}/{t("batch")}</span> : null}
          <FB.PhotoBtn onClick={() => setPhoto({ code: j.code, name: j.name })} />
        </div>

        {already ? (
          <p className="text-[11px] mt-1.5 font-semibold" style={{ color: "#4A7A1C" }}>
            ✓ {L("今天已记", "Hôm nay đã ghi", "logged today")} {already} {t("batch")}
          </p>
        ) : null}

        {/* 计时行: 开始 → 完成 → ✓时间 (按钮宽度固定, 不跳) */}
        <div className="flex items-center gap-2 mt-2 pt-2 border-t border-stone-100">
          {isDone ? (
            <span className="text-[12px] font-semibold" style={{ color: "#4A7A1C" }}>✓ {fmtSec(st.done)}</span>
          ) : running ? (
            <span className="text-[12.5px] font-bold tabular-nums" style={{ color: "#C2540A" }}>{fmtSec(elapsed(st))}</span>
          ) : paused ? (
            <span className="text-[11.5px] tabular-nums text-stone-500">⏸ {fmtSec(num(st.acc))} {L("再按开始接着计", "bấm tiếp tục", "resume")}</span>
          ) : (
            <span className="text-[11.5px] text-stone-400">{L("开工按开始 → 计工时", "Bấm bắt đầu để tính giờ", "Start to time it")}</span>
          )}
          {(running || isDone) ? (
            <button onClick={() => cycleWorkers(j.code)}
              className="text-[11px] px-2 py-0.5 rounded-md bg-stone-100 text-stone-600 active:scale-95">
              {st.workers || 1}{L(" 人", " ng", "p")}
            </button>
          ) : null}
          <div className="ml-auto shrink-0">
            {isDone ? (
              <div style={{ width: "76px" }} className="text-center text-[11.5px] text-stone-400">{L("填批数 ↓", "Nhập mẻ ↓", "batches ↓")}</div>
            ) : running ? (
              <button onClick={() => finish(j.code, j.suggest)} style={{ width: "76px" }}
                className="h-9 rounded-lg bg-stone-200 text-stone-800 text-[13.5px] font-semibold active:scale-95">
                {L("完成", "Xong", "Done")}
              </button>
            ) : (
              <button onClick={() => start(j.code)} style={{ width: "76px" }}
                className="h-9 rounded-lg bg-red-700 text-white text-[13.5px] font-semibold active:scale-95">
                {paused ? L("继续", "Tiếp", "Resume") : L("开始", "Bắt đầu", "Start")}
              </button>
            )}
          </div>
        </div>

        <div className="flex items-center gap-2 mt-2">
          <span className="text-[11.5px] text-stone-500">{L("做了几批?", "Làm mấy mẻ?", "How many batches?")}</span>
          <div className="ml-auto">
            <FB.UI.Qty value={num(n)} unit={t("batch")}
              onChange={(v) => setDone((d) => ({ ...d, [j.code]: v ? String(v) : "" }))} />
          </div>
        </div>
      </div>
    );
  }

  let nowPlaced = false;

  return (
    <div className="px-3 py-3 max-w-md mx-auto pb-28">
      {/* 今天是什么日子 */}
      <div className="rounded-2xl p-3 mb-2" style={{ background: "#FCEDEA", borderLeft: "3px solid #A81E12" }}>
        <div className="flex items-center gap-2">
          <p className="text-[17px] font-semibold" style={{ color: "#791F1F" }}>{plan[planKey]}</p>
          <span className="ml-auto text-[13px] font-semibold tabular-nums px-2 py-0.5 rounded-md"
            style={{ background: "#fff", color: "#791F1F" }}>{hhmm(nowD)}</span>
        </div>
        <p className="text-[12px] mt-0.5" style={{ color: "#791F1F", opacity: 0.75 }}>
          {jobs.length} {L("项要做", "việc cần làm", "to make")}
        </p>
      </div>

      {/* 出货倒数 — 截止前 30 分钟还有没做完的就变红 + 响 */}
      <div className="rounded-xl p-2.5 mb-2 text-[12.5px] flex items-center gap-2"
        style={hot ? { background: "#FCEDEA", borderLeft: "3px solid #A81E12", color: "#791F1F", fontWeight: 600 }
                   : { background: "#fff", borderLeft: "3px solid " + (leftMin > 60 ? "#4A7A1C" : "#C2540A"), color: "#57534E" }}>
        <span>🚚</span>
        <span>
          {leftMin > 0
            ? L("备货截止 14:30 · 还有 ", "Còn ", "Prep by 14:30 · ") +
              (Math.floor(leftMin / 60) + "h" + String(leftMin % 60).padStart(2, "0")) +
              L("", " đến 14:30", " left")
            : L("已过备货时间", "Đã qua giờ", "Past prep time")}
        </span>
        <span className="ml-auto text-[11px] opacity-70">Kulai 15:00 · Austin 15:30</span>
      </div>

      {/* 解冻提醒 */}
      {tomorrow.kind === "meat" ? (
        <div className="rounded-xl p-2.5 mb-3 text-[12.5px]"
          style={{ background: "#fff", borderLeft: "3px solid #A07A06", color: "#57534E" }}>
          🧊 {L("明天肉日 → 今晚把鸡+牛移冷藏(羊肉单独)", "Mai ngày thịt → tối nay rã đông gà + bò", "Meat day tomorrow → thaw chicken + beef tonight")}
        </div>
      ) : null}

      {!runway && <p className="text-sm text-stone-400 px-1">{t("loading")}</p>}
      {runway && jobs.length === 0 && (
        <div className="rounded-2xl border border-stone-200 bg-white p-6 text-center text-sm text-stone-500">
          ✓ {L("今天没有要补的成品", "Hôm nay không cần làm gì", "Nothing to make today")}
        </div>
      )}

      {/* 时间轴: 左边一条线, 「现在」横线随时间往下走 */}
      <div className="relative flex flex-col gap-2" style={jobs.length ? { paddingLeft: "2px" } : null}>
        {jobs.length ? (
          <span className="absolute rounded" style={{ left: "5px", top: "6px", bottom: "6px", width: "2px", background: "#E7E5E4" }} />
        ) : null}
        {jobs.map((j) => {
          const showNow = !nowPlaced && toMin(j.at) > nowMin;
          if (showNow) nowPlaced = true;
          return (
            <React.Fragment key={j.code}>
              {showNow ? (
                <div className="relative flex items-center gap-2 ml-4">
                  <span className="absolute rounded-full" style={{ left: "-23px", width: "10px", height: "10px", background: "#C2540A", boxShadow: "0 0 0 3px #fff" }} />
                  <span className="text-[11px] font-bold tabular-nums" style={{ color: "#C2540A" }}>{L("现在", "Bây giờ", "now")} {hhmm(nowD)}</span>
                  <span className="flex-1 h-0.5" style={{ background: "#C2540A" }} />
                </div>
              ) : null}
              <Card j={j} />
            </React.Fragment>
          );
        })}
        {jobs.length && !nowPlaced ? (
          <div className="relative flex items-center gap-2 ml-4">
            <span className="absolute rounded-full" style={{ left: "-23px", width: "10px", height: "10px", background: "#C2540A", boxShadow: "0 0 0 3px #fff" }} />
            <span className="text-[11px] font-bold tabular-nums" style={{ color: "#C2540A" }}>{L("现在", "Bây giờ", "now")} {hhmm(nowD)}</span>
            <span className="flex-1 h-0.5" style={{ background: "#C2540A" }} />
          </div>
        ) : null}
      </div>

      {/* 明天的可以提前做 (要解冻的锁住) */}
      {tmrFocus.length ? (
        <div className="mt-4">
          <p className="text-[12px] font-semibold text-stone-500 px-1 mb-1.5">
            ⏩ {L("今天有空?明天的可以先做", "Rảnh thì làm trước cho mai", "Free? do tomorrow's early")}
          </p>
          <div className="flex flex-col gap-2">
            {tmrFocus.map((c) => {
              const g = goodsMap[c];
              const locked = FB.TODAY_THAW_CODES.indexOf(c) >= 0;
              return (
                <div key={c} className="rounded-xl border border-stone-200 bg-white p-2.5 flex items-center gap-2"
                  style={{ borderLeft: "3px solid " + (locked ? "#D6D3D1" : "#4A7A1C") }}>
                  <div className="min-w-0">
                    <p className="text-[13.5px] font-semibold text-stone-800 truncate">{g ? FB.nm(g, lang) : c}</p>
                    <p className="text-[11px] text-stone-400">
                      {locked ? L("要等解冻,明天才能做", "Chờ rã đông, mai mới làm được", "needs thawing first")
                              : L("材料都在,可以先做", "Có sẵn nguyên liệu", "materials ready")}
                    </p>
                  </div>
                  <div className="ml-auto shrink-0">
                    {locked ? (
                      <span className="text-[15px] text-stone-300">🔒</span>
                    ) : (
                      <button onClick={() => setExtra((x) => (x.indexOf(c) >= 0 ? x : x.concat([c])))}
                        className="h-8 px-3 rounded-lg bg-stone-100 text-stone-700 text-[12.5px] font-semibold active:scale-95">
                        {L("加进今天", "Thêm vào hôm nay", "add to today")}
                      </button>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      ) : null}

      {okMsg && (
        <div className="rounded-xl p-3 mt-3 text-[12.5px]"
          style={okMsg.ok ? { background: "#EAF3DE", color: "#27500A" } : { background: "#FCEDEA", color: "#A81E12" }}>
          {okMsg.ok ? "✓ " : ""}{okMsg.text}
        </div>
      )}

      <p className="text-[11px] text-stone-400 mt-3 px-1">
        {L("开始/完成只是计工时(可以按 ↩ 撤销)。填批数 → 提交 = 成品入库 + 按配方扣原料",
           "Bắt đầu/Xong = tính giờ (↩ để hoàn tác). Nhập số mẻ → Gửi = nhập kho + trừ nguyên liệu",
           "Start/Done times the job (↩ to undo). Enter batches → submit = yield in + materials out")}
      </p>

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

      {jobs.length > 0 && (
        <FB.UI.Sticky>
          <button onClick={submit} disabled={busy || !picked.length}
            className="w-full h-12 rounded-xl bg-red-700 text-white font-semibold active:scale-[0.98] disabled:opacity-30">
            {busy ? t("submitting") : L("做完了 · 记 " + picked.length + " 项", "Xong · ghi " + picked.length, "Done · log " + picked.length)}
          </button>
        </FB.UI.Sticky>
      )}
    </div>
  );
};
