// ============================================================================
// Workboard.jsx — екран «Що зробити» (робоче місце менеджера)
//   function Workboard({ isMobile, currentManager, onOpenOrder, onOpenLead, onCallBack })
//   → window.Workboard
// Desktop + mobile в одному файлі (проп isMobile). Дані — GET /api/workboard.
// Дизайн з handoff_workboard (3 колонки/секції: Замовлення · Заявки · Не передзвонили).
// Адаптовано під CRM: глобальний <Icon> (перф), IIFE-скоуп, відповідальний менеджер на картках.
// ============================================================================
(function () {
  const { useState: wbUseState, useEffect: wbUseEffect, useRef: wbUseRef, useMemo: wbUseMemo } = React;
  const WbIcon = Icon;   // глобальна перф-іконка CRM (та сама сигнатура {name,size,color,style})

  // keyframes/скролбар для скелетонів і чипів — інжектимо один раз (self-contained).
  if (typeof document !== "undefined" && !document.getElementById("wb-keyframes")) {
    const st = document.createElement("style"); st.id = "wb-keyframes";
    st.textContent = "@keyframes wbspin{to{transform:rotate(360deg)}}@keyframes wbpulse{0%,100%{opacity:1}50%{opacity:.5}}.wb-no-bar{scrollbar-width:none}.wb-no-bar::-webkit-scrollbar{display:none}";
    document.head.appendChild(st);
  }

  // ── Конфіг стадій замовлення (stage → колір / іконка / дія / поріг «горить», год) ─
  const WB_STAGE = {
    pay:     { color: "#06B6D4", label: "Очікує оплату",          icon: "wallet",      action: "Уточнити в клієнта про оплату", thr: 6 },
    process: { color: "#6366F1", label: "Опрацювати",             icon: "list-checks", action: "Опрацювати замовлення",         thr: 2 },
    wait:    { color: "#F59E0B", label: "Чекаємо клієнта",        icon: "clock",       action: "Звʼязатися з клієнтом",         thr: 2 },
    awaiting_supplier: { color: "#6B7280", label: "Чекаємо постачальника", icon: "truck", action: "Просто чекаємо — дій не треба", thr: Infinity, muted: true },
  };
  const WB_STAGE_ORDER = ["pay", "process", "wait", "awaiting_supplier"];
  const WB_LEAD_COLOR = "#8B5CF6";

  // ── Утиліти ─────────────────────────────────────────────────────────────────
  function wbAge(hrs) {
    if (hrs < 1) return Math.max(1, Math.round(hrs * 60)) + " хв";
    return hrs + " год";
  }
  function wbAgo(min) {
    if (min < 60) return min + " хв тому";
    const h = Math.floor(min / 60), m = min % 60;
    return m ? `${h} год ${m} хв тому` : `${h} год тому`;
  }
  function wbAgeTone(o) {
    if (o.stage === "awaiting_supplier") return "var(--fg-muted)";
    const thr = WB_STAGE[o.stage].thr;
    if (o.urgent || o.ageHrs >= thr) return "#FB7185";
    if (o.ageHrs >= thr * 0.6) return "var(--warning)";
    return "var(--fg-secondary)";
  }
  function wbFmtPhone(p) {
    const d = (p || "").replace(/\D/g, "");
    if (d.length !== 12) return p;
    return `+38 ${d.slice(2, 5)} ${d.slice(5, 8)} ${d.slice(8, 10)} ${d.slice(10)}`;
  }
  function wbIsMine(m, me) { return m === me || m === "" || m === "—" || !m; }

  function WbAvatar({ name, size = 24 }) {
    if (!name) {
      return (
        <div title="Не призначено" style={{
          width: size, height: size, borderRadius: "50%", border: "1px dashed var(--border-strong)",
          display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-muted)", flexShrink: 0,
        }}><WbIcon name="user" size={size * 0.5} /></div>
      );
    }
    const initials = name.split(" ").map(s => s[0]).slice(0, 2).join("");
    return (
      <div title={name} style={{
        width: size, height: size, borderRadius: "50%", flexShrink: 0,
        background: "var(--bg-raised)", color: "var(--fg-primary)", border: "1px solid var(--border-default)",
        display: "flex", alignItems: "center", justifyContent: "center", fontSize: size * 0.4, fontWeight: 600,
      }}>{initials}</div>
    );
  }

  // Імʼя відповідального менеджера на картці (заявка/замовлення).
  function WbMgrTag({ manager }) {
    return (
      <span title={manager ? "Відповідальний менеджер" : "Не призначено"} style={{
        display: "inline-flex", alignItems: "center", gap: 4, flexShrink: 0, maxWidth: 96,
        fontSize: 11, fontWeight: 600, color: manager ? "var(--fg-secondary)" : "var(--fg-muted)",
      }}>
        <WbIcon name={manager ? "user-check" : "user"} size={11} color={manager ? "var(--accent)" : "var(--fg-muted)"} />
        <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{manager || "нічий"}</span>
      </span>
    );
  }

  function WbCountBadge({ n, color }) {
    return (
      <span style={{
        minWidth: 20, height: 20, padding: "0 6px", borderRadius: 999,
        display: "inline-flex", alignItems: "center", justifyContent: "center",
        fontFamily: "var(--font-mono)", fontSize: 12, fontWeight: 600, fontVariantNumeric: "tabular-nums",
        background: color ? "color-mix(in oklab, " + color + " 16%, transparent)" : "var(--bg-raised)",
        color: color || "var(--fg-secondary)",
      }}>{n}</span>
    );
  }

  function WbActBtn({ icon, children, href, onClick, tone }) {
    const styles = {
      display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6, height: 30, padding: "0 11px",
      borderRadius: 8, fontFamily: "inherit", fontSize: 12, fontWeight: 500, cursor: "pointer", whiteSpace: "nowrap",
      textDecoration: "none", flex: 1,
      background: tone === "primary" ? "var(--accent)" : "var(--bg-raised)",
      color: tone === "primary" ? "#fff" : "var(--fg-secondary)",
      border: "1px solid " + (tone === "primary" ? "transparent" : "var(--border-default)"),
    };
    const inner = <>{icon && <WbIcon name={icon} size={13} />}{children}</>;
    return href
      ? <a href={href} style={styles}>{inner}</a>
      : <button onClick={onClick} style={styles}>{inner}</button>;
  }

  // ── Картка ЗАМОВЛЕННЯ ───────────────────────────────────────────────────────
  function WbOrderCard({ o, onOpen }) {
    const s = WB_STAGE[o.stage] || WB_STAGE.process;
    const accent = o.urgent ? "var(--danger)" : s.color;
    const hot = o.urgent || (o.stage !== "awaiting_supplier" && o.ageHrs >= s.thr);
    return (
      <div style={{
        position: "relative", background: "var(--bg-raised)", borderRadius: 12, padding: "12px 13px 12px 15px",
        border: "1px solid " + (o.urgent ? "color-mix(in oklab, var(--danger) 45%, transparent)" : "var(--border-default)"),
        boxShadow: o.urgent ? "0 0 0 1px color-mix(in oklab, var(--danger) 20%, transparent)" : "none",
        opacity: s.muted ? 0.74 : 1, display: "flex", flexDirection: "column", gap: 9,
      }}>
        <div style={{ position: "absolute", left: 0, top: 12, bottom: 12, width: 3, borderRadius: 3, background: accent }}></div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums" }}>#{o.order_id}</span>
          {o.urgent === 1 && (
            <span style={{
              display: "inline-flex", alignItems: "center", gap: 4, height: 18, padding: "0 7px", borderRadius: 999,
              background: "color-mix(in oklab, var(--danger) 16%, transparent)", color: "#FB7185", fontSize: 10.5, fontWeight: 600,
            }}><WbIcon name="zap" size={10} />Термінова</span>
          )}
          <span style={{ flex: 1 }}></span>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 4, color: wbAgeTone(o), fontSize: 12, fontWeight: 600, fontVariantNumeric: "tabular-nums" }}>
            {hot && <WbIcon name="flame" size={12} color="#FB7185" />}{wbAge(o.ageHrs)}
          </span>
        </div>
        <div style={{ fontSize: 13.5, fontWeight: 500, color: "var(--fg-primary)", lineHeight: 1.3 }}>{o.product}</div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
          <WbAvatar name={o.manager || null} size={22} />
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 12.5, color: "var(--fg-secondary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{o.client}</div>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums" }}>{wbFmtPhone(o.phone)}</div>
          </div>
          <WbMgrTag manager={o.manager} />
        </div>
        <div style={{
          display: "flex", alignItems: "center", gap: 7, padding: "7px 9px", borderRadius: 8,
          background: "color-mix(in oklab, " + s.color + " 9%, transparent)",
          color: s.muted ? "var(--fg-muted)" : "var(--fg-secondary)", fontSize: 12, lineHeight: 1.3,
        }}>
          <WbIcon name={s.icon} size={13} color={s.muted ? "var(--fg-muted)" : s.color} />
          <span>{o.need || s.action}</span>
        </div>
        <div style={{ display: "flex", gap: 7 }}>
          <WbActBtn icon="phone" href={"tel:" + (o.phone || "").replace(/\s/g, "")} tone={s.muted ? "ghost" : "primary"}>Дзвінок</WbActBtn>
          <WbActBtn icon="external-link" onClick={() => onOpen && onOpen(o)}>Відкрити</WbActBtn>
        </div>
      </div>
    );
  }

  // ── Картка ЗАЯВКИ ───────────────────────────────────────────────────────────
  function WbLeadCard({ l, onOpen }) {
    const ready = l.supplierAnswered;
    const inStock = l.bot === "available";
    const outStock = l.bot === "out";
    // Вердикт наявності + сам текст відповіді постачальника (щоб було видно ЩО відповіли).
    const verdict = inStock ? "✅ В наявності" : outStock ? "❌ Немає у постачальника" : "";
    const answerColor = inStock ? "var(--success)" : outStock ? "var(--danger)" : WB_LEAD_COLOR;
    return (
      <div style={{
        position: "relative", background: "var(--bg-raised)", borderRadius: 12, padding: "12px 13px 12px 15px",
        border: "1px solid var(--border-default)", opacity: ready ? 1 : 0.78, display: "flex", flexDirection: "column", gap: 9,
      }}>
        <div style={{ position: "absolute", left: 0, top: 12, bottom: 12, width: 3, borderRadius: 3, background: ready ? WB_LEAD_COLOR : "var(--fg-muted)" }}></div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums" }}>#{l.id}</span>
          <span style={{
            display: "inline-flex", alignItems: "center", gap: 4, height: 18, padding: "0 7px", borderRadius: 999,
            background: "color-mix(in oklab, " + WB_LEAD_COLOR + " 15%, transparent)", color: "#C4B5FD", fontSize: 10.5, fontWeight: 600,
          }}>Заявка</span>
          <span style={{ flex: 1 }}></span>
          <span style={{ color: l.ageHrs >= 4 && ready ? "var(--warning)" : "var(--fg-muted)", fontSize: 12, fontWeight: 600, fontVariantNumeric: "tabular-nums" }}>{wbAge(l.ageHrs)}</span>
        </div>
        <div style={{ fontSize: 13.5, fontWeight: 500, color: "var(--fg-primary)", lineHeight: 1.3 }}>{l.product}</div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
          <WbAvatar name={l.manager || null} size={22} />
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 12.5, color: "var(--fg-secondary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{l.client}</div>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums" }}>{wbFmtPhone(l.phone)}</div>
          </div>
          <WbMgrTag manager={l.manager} />
        </div>
        <div style={{
          display: "flex", flexDirection: "column", gap: 4, padding: "7px 9px", borderRadius: 8,
          background: ready ? "color-mix(in oklab, " + answerColor + " 10%, transparent)" : "var(--bg-hover)",
          color: ready ? "var(--fg-secondary)" : "var(--fg-muted)", fontSize: 12, lineHeight: 1.35,
        }}>
          <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
            <WbIcon name={ready ? "user-check" : "truck"} size={13} color={ready ? answerColor : "var(--fg-muted)"} />
            <span style={{ fontWeight: ready ? 600 : 400, color: ready ? answerColor : "var(--fg-muted)" }}>
              {ready ? (verdict || "Постачальник відповів") : "Чекаємо відповідь постачальника"}
            </span>
          </div>
          {ready && l.supplierText && (
            <div style={{ color: "var(--fg-secondary)", paddingLeft: 20, whiteSpace: "pre-wrap", wordBreak: "break-word" }}>{l.supplierText}</div>
          )}
          {ready && <div style={{ color: "var(--fg-muted)", paddingLeft: 20, fontSize: 11 }}>Звʼязатися з клієнтом</div>}
        </div>
        <div style={{ display: "flex", gap: 7 }}>
          <WbActBtn icon="phone" href={"tel:" + (l.phone || "").replace(/\s/g, "")} tone={ready ? "primary" : "ghost"}>Дзвінок</WbActBtn>
          <WbActBtn icon="external-link" onClick={() => onOpen && onOpen(l)}>Відкрити заявку</WbActBtn>
        </div>
      </div>
    );
  }

  // ── Картка ПРОПУЩЕНОГО ──────────────────────────────────────────────────────
  function WbMissedCard({ m, onDone }) {
    return (
      <div style={{
        position: "relative", background: "color-mix(in oklab, var(--danger) 7%, var(--bg-raised))", borderRadius: 12, padding: "11px 13px 11px 15px",
        border: "1px solid color-mix(in oklab, var(--danger) 32%, transparent)", display: "flex", alignItems: "center", gap: 11,
      }}>
        <div style={{ position: "absolute", left: 0, top: 11, bottom: 11, width: 3, borderRadius: 3, background: "var(--danger)" }}></div>
        <div style={{
          width: 34, height: 34, borderRadius: 9, flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center",
          background: "color-mix(in oklab, var(--danger) 16%, transparent)", color: "#FB7185",
        }}><WbIcon name="phone-missed" size={16} /></div>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 13, fontWeight: 600, color: "var(--fg-primary)", fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{m.phone}</div>
          <div style={{ fontSize: 11, color: "var(--fg-muted)", whiteSpace: "nowrap" }}>{wbAgo(m.agoMin)}</div>
        </div>
        <a href={"tel:+380" + String(m.phone10 || "").slice(-9)} title="Подзвонити" style={{
          width: 32, height: 32, borderRadius: 8, flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center",
          background: "var(--accent)", color: "#fff", textDecoration: "none",
        }}><WbIcon name="phone" size={14} /></a>
        <button onClick={onDone} title="Передзвонив" style={{
          width: 32, height: 32, borderRadius: 8, flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center",
          background: "var(--bg-raised)", color: "var(--success)", border: "1px solid var(--border-default)", cursor: "pointer",
        }}><WbIcon name="check" size={15} /></button>
      </div>
    );
  }

  function WbGroupHead({ color, icon, label, count, muted }) {
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "2px 2px 0" }}>
        <WbIcon name={icon} size={14} color={muted ? "var(--fg-muted)" : color} />
        <span style={{ fontSize: 11.5, fontWeight: 600, letterSpacing: "0.02em", color: muted ? "var(--fg-muted)" : "var(--fg-secondary)", textTransform: "uppercase" }}>{label}</span>
        <WbCountBadge n={count} color={muted ? null : color} />
      </div>
    );
  }

  function WbColumn({ icon, title, color, total, children, empty }) {
    return (
      <section style={{ flex: 1, minWidth: 0, minHeight: 0, overflow: "hidden", display: "flex", flexDirection: "column", gap: 12, background: "var(--bg-panel)", border: "1px solid var(--border-subtle)", borderRadius: 14, padding: 14 }}>
        <header style={{ flexShrink: 0, display: "flex", alignItems: "center", gap: 9, paddingBottom: 12, borderBottom: "1px solid var(--border-subtle)" }}>
          <span style={{ width: 28, height: 28, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", background: "color-mix(in oklab, " + color + " 16%, transparent)", color }}>
            <WbIcon name={icon} size={15} />
          </span>
          <h3 style={{ fontSize: 14.5, fontWeight: 600, color: "var(--fg-primary)", margin: 0 }}>{title}</h3>
          <span style={{ flex: 1 }}></span>
          <WbCountBadge n={total} color={total ? color : null} />
        </header>
        <div className="wb-no-bar" style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column", gap: 18, overflowY: "auto", paddingRight: 2 }}>
          {total === 0 ? empty : children}
        </div>
      </section>
    );
  }

  function WbColumnEmpty({ text }) {
    return (
      <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 8, padding: "28px 12px", color: "var(--fg-muted)", textAlign: "center" }}>
        <WbIcon name="check-circle-2" size={22} color="var(--success)" />
        <span style={{ fontSize: 12 }}>{text}</span>
      </div>
    );
  }

  function WbSegmented({ value, onChange, options }) {
    return (
      <div style={{ display: "inline-flex", background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 9, padding: 2 }}>
        {options.map(o => {
          const active = value === o.key;
          return (
            <button key={o.key} onClick={() => onChange(o.key)} style={{
              display: "inline-flex", alignItems: "center", gap: 6, height: 28, padding: "0 12px", borderRadius: 7,
              border: "none", cursor: "pointer", fontFamily: "inherit", fontSize: 12.5, fontWeight: 500,
              background: active ? "var(--accent)" : "transparent", color: active ? "#fff" : "var(--fg-secondary)",
            }}>
              {o.icon && <WbIcon name={o.icon} size={13} />}{o.label}
            </button>
          );
        })}
      </div>
    );
  }

  function WbTypeChips({ value, onChange, counts, big }) {
    const opts = [
      { key: "all", label: "Усі" },
      { key: "orders", label: "Замовлення", c: counts.orders },
      { key: "leads", label: "Заявки", c: counts.leads },
      { key: "missed", label: "Дзвінки", c: counts.missed },
    ];
    return (
      <div className="wb-no-bar" style={{ display: "flex", gap: big ? 7 : 8, overflowX: big ? "auto" : "visible" }}>
        {opts.map(o => {
          const active = value === o.key;
          return (
            <button key={o.key} onClick={() => onChange(o.key)} style={{
              display: "inline-flex", alignItems: "center", gap: 7, height: big ? 30 : 28, padding: big ? "0 13px" : "0 11px",
              borderRadius: 999, flexShrink: 0,
              border: "1px solid " + (active ? "var(--accent-ring)" : "var(--border-default)"),
              background: active ? "var(--accent-soft)" : "var(--bg-raised)",
              color: active ? "var(--fg-primary)" : "var(--fg-secondary)", cursor: "pointer", fontFamily: "inherit", fontSize: 12, fontWeight: 500,
            }}>
              {o.label}{o.c != null && <span style={{ fontFamily: "var(--font-mono)", color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums" }}>{o.c}</span>}
            </button>
          );
        })}
      </div>
    );
  }

  function WbSearch({ value, onChange }) {
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 6, height: 30, padding: "0 10px", background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 999, minWidth: 0 }}>
        <WbIcon name="search" size={13} color="var(--fg-muted)" />
        <input value={value} onChange={e => onChange(e.target.value)} placeholder="Пошук: клієнт, телефон, №…"
          style={{ border: 0, background: "transparent", color: "var(--fg-primary)", fontFamily: "inherit", fontSize: 12.5, outline: "none", width: "100%", minWidth: 0 }} />
        {value && <button onClick={() => onChange("")} title="Очистити" style={{ border: 0, background: "transparent", color: "var(--fg-muted)", cursor: "pointer", display: "flex", padding: 0 }}><WbIcon name="x" size={13} /></button>}
      </div>
    );
  }

  function WbSortSelect({ value, onChange }) {
    return (
      <select value={value} onChange={e => onChange(e.target.value)} title="Сортування" style={{ height: 30, padding: "0 8px", background: "var(--bg-raised)", color: "var(--fg-secondary)", border: "1px solid var(--border-default)", borderRadius: 8, fontSize: 12, fontFamily: "inherit", cursor: "pointer", outline: "none", flexShrink: 0 }}>
        <option value="old">↓ Спершу найстаріші</option>
        <option value="new">↑ Спершу найновіші</option>
      </select>
    );
  }

  function WbHotToggle({ on, onToggle }) {
    return (
      <button onClick={onToggle} title="Показати лише те, що горить (прострочене / термінове)" style={{
        display: "inline-flex", alignItems: "center", gap: 6, height: 30, padding: "0 12px", borderRadius: 999, cursor: "pointer", fontFamily: "inherit", fontSize: 12, fontWeight: 500, flexShrink: 0,
        border: "1px solid " + (on ? "color-mix(in oklab, var(--danger) 50%, transparent)" : "var(--border-default)"),
        background: on ? "color-mix(in oklab, var(--danger) 14%, transparent)" : "var(--bg-raised)",
        color: on ? "#FB7185" : "var(--fg-secondary)",
      }}>
        <WbIcon name="flame" size={13} color={on ? "#FB7185" : "var(--fg-muted)"} />Горить
      </button>
    );
  }

  function WbSkel({ h = 150 }) {
    return <div style={{ height: h, borderRadius: 12, background: "var(--bg-raised)", border: "1px solid var(--border-subtle)", animation: "wbpulse 1.3s ease-in-out infinite" }}></div>;
  }

  function WbBigEmpty({ filtered, onReset }) {
    const c = filtered ? "var(--fg-muted)" : "var(--success)";
    return (
      <div style={{ height: "100%", minHeight: 280, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 14 }}>
        <div style={{ width: 64, height: 64, borderRadius: 18, display: "flex", alignItems: "center", justifyContent: "center", background: "color-mix(in oklab, " + c + " 14%, transparent)", color: c }}>
          <WbIcon name={filtered ? "search-x" : "party-popper"} size={30} />
        </div>
        <div style={{ fontSize: 17, fontWeight: 600, color: "var(--fg-primary)" }}>{filtered ? "Нічого не знайдено" : "Нічого не висить"}</div>
        <div style={{ fontSize: 13, color: "var(--fg-muted)" }}>{filtered ? "Спробуй змінити фільтри або пошук." : "Усе опрацьовано. Можна видихнути."}</div>
        {filtered && onReset && <button onClick={onReset} style={{ height: 32, padding: "0 14px", borderRadius: 8, border: "1px solid var(--border-default)", background: "var(--bg-raised)", color: "var(--fg-secondary)", fontSize: 12.5, fontWeight: 500, cursor: "pointer", fontFamily: "inherit" }}>Скинути фільтри</button>}
      </div>
    );
  }

  // ── Добір/групування даних ──────────────────────────────────────────────────
  // «Горить» = термінове АБО прострочене (вік ≥ поріг стадії; awaiting_supplier ніколи).
  function wbOrderHot(o) { return o.urgent === 1 || (o.stage !== "awaiting_supplier" && WB_STAGE[o.stage] && o.ageHrs >= WB_STAGE[o.stage].thr); }
  function wbBuildBoard(scope, typeFilter, data, me, opts) {
    const o2 = opts || {};
    const q = String(o2.query || "").trim().toLowerCase();
    const qd = q.replace(/\D/g, "");
    const txt = (...xs) => xs.join(" ").toLowerCase();
    const hitOrder = o => !q || txt(o.client, o.product, "#" + o.order_id).includes(q) || (qd && String(o.phone || "").replace(/\D/g, "").includes(qd));
    const hitLead  = l => !q || txt(l.client, l.product, "#" + l.id).includes(q) || (qd && String(l.phone || "").replace(/\D/g, "").includes(qd));
    const hitMissed = m => !q || (m.phone || "").toLowerCase().includes(q) || (qd && String(m.phone10 || m.phone || "").replace(/\D/g, "").includes(qd));
    const matchMgr = m => scope === "all" || wbIsMine(m, me);

    let orders = (data.orders || []).filter(o => matchMgr(o.manager) && hitOrder(o));
    let leads = (data.leads || []).filter(l => matchMgr(l.manager) && hitLead(l));
    let missed = (data.missed || []).filter(hitMissed);
    if (o2.hotOnly) { orders = orders.filter(wbOrderHot); leads = leads.filter(l => l.supplierAnswered && l.ageHrs >= 4); }
    if (typeFilter === "orders") { leads = []; missed = []; }
    if (typeFilter === "leads") { orders = []; missed = []; }
    if (typeFilter === "missed") { orders = []; leads = []; }

    const cmp = o2.sortMode === "new" ? (a, b) => a.ageHrs - b.ageHrs : (a, b) => b.ageHrs - a.ageHrs;
    const urgent = orders.filter(o => o.urgent === 1).sort(cmp);
    const byStage = {};
    WB_STAGE_ORDER.forEach(k => { byStage[k] = orders.filter(o => o.stage === k && o.urgent !== 1).sort(cmp); });

    const leadsReady = leads.filter(l => l.supplierAnswered).sort(cmp);
    const leadsWait = leads.filter(l => !l.supplierAnswered).sort(cmp);
    const mcmp = o2.sortMode === "new" ? (a, b) => (a.at || 0) - (b.at || 0) : (a, b) => (b.at || 0) - (a.at || 0);
    missed = missed.slice().sort(mcmp);

    const hot = urgent.length + missed.length + orders.filter(o => o.urgent !== 1 && wbOrderHot(o)).length;

    return { orders, leads, missed, urgent, byStage, leadsReady, leadsWait, hot,
      counts: { orders: orders.length, leads: leads.length, missed: missed.length } };
  }

  // ── DESKTOP-розкладка (3 колонки сутностей) ─────────────────────────────────
  function WbDesktopView({ b, scope, setScope, typeFilter, setTypeFilter, loading, onRefresh, onOpenOrder, onOpenLead, onCallBack, sortMode, setSortMode, hotOnly, setHotOnly, query, setQuery, anyRaw, onResetFilters }) {
    const allEmpty = b.counts.orders + b.counts.leads + b.counts.missed === 0;
    const total = b.counts.orders + b.counts.leads + b.counts.missed;
    return (
      <div style={{ flex: 1, minHeight: 0, display: "flex", flexDirection: "column", minWidth: 0, background: "var(--bg-base)" }}>
        <div style={{ flexShrink: 0, background: "var(--bg-panel)", borderBottom: "1px solid var(--border-subtle)" }}>
          <div style={{ height: 56, display: "flex", alignItems: "center", gap: 14, padding: "0 20px" }}>
            <div style={{ display: "flex", flexDirection: "column" }}>
              <span style={{ fontSize: 16, fontWeight: 600, color: "var(--fg-primary)", lineHeight: 1.1 }}>Що зробити</span>
              <span style={{ fontSize: 11.5, color: "var(--fg-muted)" }}>
                {b.hot > 0
                  ? <>Горить: <span style={{ color: "#FB7185", fontWeight: 600 }}>{b.hot}</span> · усього в роботі {total}</>
                  : <>Усе під контролем · {total} у роботі</>}
              </span>
            </div>
            <span style={{ flex: 1 }}></span>
            <WbSegmented value={scope} onChange={setScope} options={[{ key: "mine", label: "Мої", icon: "user" }, { key: "all", label: "Всі", icon: "users" }]} />
            <button onClick={onRefresh} title="Оновити" style={{ width: 34, height: 34, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", background: "var(--bg-raised)", border: "1px solid var(--border-default)", color: "var(--fg-secondary)", cursor: "pointer" }}>
              <WbIcon name="refresh-cw" size={14} style={loading ? { animation: "wbspin 0.8s linear infinite" } : undefined} />
            </button>
          </div>
          <div style={{ padding: "0 20px 12px", display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
            <WbTypeChips value={typeFilter} onChange={setTypeFilter} counts={b.counts} />
            <span style={{ flex: 1, minWidth: 12 }}></span>
            <WbHotToggle on={hotOnly} onToggle={() => setHotOnly(!hotOnly)} />
            <div style={{ width: 230 }}><WbSearch value={query} onChange={setQuery} /></div>
            <WbSortSelect value={sortMode} onChange={setSortMode} />
          </div>
        </div>

        <div style={{ flex: 1, minHeight: 0, padding: "16px 20px 20px", overflow: "hidden" }}>
          {loading ? (
            <div style={{ display: "grid", gridTemplateColumns: "1.25fr 1fr 0.85fr", gridTemplateRows: "minmax(0, 1fr)", gap: 16, height: "100%", minHeight: 0 }}>
              {[0, 1, 2].map(c => (
                <div key={c} style={{ background: "var(--bg-panel)", border: "1px solid var(--border-subtle)", borderRadius: 14, padding: 14, display: "flex", flexDirection: "column", gap: 14 }}>
                  <WbSkel h={20} /><WbSkel /><WbSkel h={120} />
                </div>
              ))}
            </div>
          ) : allEmpty ? (
            <WbBigEmpty filtered={anyRaw} onReset={onResetFilters} />
          ) : (
            <div style={{ display: "grid", gridTemplateColumns: "1.25fr 1fr 0.85fr", gridTemplateRows: "minmax(0, 1fr)", gap: 16, height: "100%", minHeight: 0 }}>
              <WbColumn icon="package" title="Замовлення" color="var(--accent)" total={b.counts.orders} empty={<WbColumnEmpty text="Жодне замовлення не застрягло" />}>
                {b.urgent.length > 0 && (
                  <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
                    <WbGroupHead color="var(--danger)" icon="zap" label="Термінові" count={b.urgent.length} />
                    {b.urgent.map(o => <WbOrderCard key={o.order_id} o={o} onOpen={onOpenOrder} />)}
                  </div>
                )}
                {WB_STAGE_ORDER.map(k => b.byStage[k].length > 0 && (
                  <div key={k} style={{ display: "flex", flexDirection: "column", gap: 9 }}>
                    <WbGroupHead color={WB_STAGE[k].color} icon={WB_STAGE[k].icon} label={WB_STAGE[k].label} count={b.byStage[k].length} muted={WB_STAGE[k].muted} />
                    {b.byStage[k].map(o => <WbOrderCard key={o.order_id} o={o} onOpen={onOpenOrder} />)}
                  </div>
                ))}
              </WbColumn>

              <WbColumn icon="inbox" title="Заявки" color={WB_LEAD_COLOR} total={b.counts.leads} empty={<WbColumnEmpty text="Нових заявок немає" />}>
                {b.leadsReady.length > 0 && (
                  <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
                    <WbGroupHead color={WB_LEAD_COLOR} icon="user-check" label="Можна рухати" count={b.leadsReady.length} />
                    {b.leadsReady.map(l => <WbLeadCard key={l.id} l={l} onOpen={onOpenLead} />)}
                  </div>
                )}
                {b.leadsWait.length > 0 && (
                  <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
                    <WbGroupHead color="#6B7280" icon="truck" label="Чекаємо постачальника" count={b.leadsWait.length} muted />
                    {b.leadsWait.map(l => <WbLeadCard key={l.id} l={l} onOpen={onOpenLead} />)}
                  </div>
                )}
              </WbColumn>

              <WbColumn icon="phone-missed" title="Не передзвонили" color="var(--danger)" total={b.counts.missed} empty={<WbColumnEmpty text="Усім передзвонили" />}>
                <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
                  {b.missed.map((m, i) => <WbMissedCard key={(m.phone10 || m.phone) + i} m={m} onDone={() => onCallBack(m, i)} />)}
                </div>
              </WbColumn>
            </div>
          )}
        </div>
      </div>
    );
  }

  // ── MOBILE-розкладка (вертикальні секції з липкими заголовками) ─────────────
  function WbMobileView({ b, scope, setScope, typeFilter, setTypeFilter, loading, onOpenOrder, onOpenLead, onCallBack, sortMode, setSortMode, hotOnly, setHotOnly, query, setQuery, anyRaw, onResetFilters }) {
    const allEmpty = b.counts.orders + b.counts.leads + b.counts.missed === 0;
    const total = b.counts.orders + b.counts.leads + b.counts.missed;

    const Section = ({ icon, title, color, count, children }) => (
      <section style={{ display: "flex", flexDirection: "column" }}>
        <header style={{
          position: "sticky", top: 0, zIndex: 2, display: "flex", alignItems: "center", gap: 9, padding: "10px 16px",
          background: "color-mix(in oklab, var(--bg-base) 88%, transparent)", backdropFilter: "blur(8px)", WebkitBackdropFilter: "blur(8px)",
          borderBottom: "1px solid var(--border-subtle)",
        }}>
          <span style={{ width: 24, height: 24, borderRadius: 7, display: "flex", alignItems: "center", justifyContent: "center", background: "color-mix(in oklab, " + color + " 16%, transparent)", color }}>
            <WbIcon name={icon} size={13} />
          </span>
          <span style={{ fontSize: 13.5, fontWeight: 600, color: "var(--fg-primary)" }}>{title}</span>
          <span style={{ flex: 1 }}></span>
          <WbCountBadge n={count} color={count ? color : null} />
        </header>
        <div style={{ display: "flex", flexDirection: "column", gap: 14, padding: "12px 16px 18px" }}>{children}</div>
      </section>
    );
    const SubHead = ({ color, icon, label, count, muted }) => (
      <div style={{ display: "flex", alignItems: "center", gap: 7, paddingTop: 2 }}>
        <WbIcon name={icon} size={13} color={muted ? "var(--fg-muted)" : color} />
        <span style={{ fontSize: 11, fontWeight: 600, letterSpacing: "0.02em", textTransform: "uppercase", color: muted ? "var(--fg-muted)" : "var(--fg-secondary)" }}>{label}</span>
        <WbCountBadge n={count} color={muted ? null : color} />
      </div>
    );

    return (
      <div style={{ width: "100%", height: "100%", display: "flex", flexDirection: "column", background: "var(--bg-base)", minHeight: 0 }}>
        <div style={{ flexShrink: 0, background: "var(--bg-panel)", borderBottom: "1px solid var(--border-subtle)", padding: "calc(12px + env(safe-area-inset-top, 0px)) 16px 12px" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 17, fontWeight: 600, color: "var(--fg-primary)" }}>Що зробити</div>
              <div style={{ fontSize: 11.5, color: "var(--fg-muted)" }}>
                {b.hot > 0 ? <>Горить: <span style={{ color: "#FB7185", fontWeight: 600 }}>{b.hot}</span> · у роботі {total}</> : "Усе під контролем"}
              </div>
            </div>
            <WbSegmented value={scope} onChange={setScope} options={[{ key: "mine", label: "Мої" }, { key: "all", label: "Всі" }]} />
          </div>
          <div style={{ marginTop: 11 }}>
            <WbTypeChips value={typeFilter} onChange={setTypeFilter} counts={b.counts} big />
          </div>
          <div style={{ marginTop: 9, display: "flex", alignItems: "center", gap: 8 }}>
            <div style={{ flex: 1, minWidth: 0 }}><WbSearch value={query} onChange={setQuery} /></div>
            <WbHotToggle on={hotOnly} onToggle={() => setHotOnly(!hotOnly)} />
            <WbSortSelect value={sortMode} onChange={setSortMode} />
          </div>
        </div>

        <div className="wb-no-bar" style={{ flex: 1, overflowY: "auto", overflowX: "hidden" }}>
          {loading ? (
            <div style={{ display: "flex", flexDirection: "column", gap: 14, padding: 16 }}>
              <WbSkel h={20} /><WbSkel h={170} /><WbSkel h={170} />
            </div>
          ) : allEmpty ? (
            <WbBigEmpty filtered={anyRaw} onReset={onResetFilters} />
          ) : (
            <>
              {b.counts.missed > 0 && (
                <Section icon="phone-missed" title="Не передзвонили" color="var(--danger)" count={b.counts.missed}>
                  {b.missed.map((m, i) => <WbMissedCard key={(m.phone10 || m.phone) + i} m={m} onDone={() => onCallBack(m, i)} />)}
                </Section>
              )}
              {b.counts.orders > 0 && (
                <Section icon="package" title="Замовлення" color="var(--accent)" count={b.counts.orders}>
                  {b.urgent.length > 0 && <><SubHead color="var(--danger)" icon="zap" label="Термінові" count={b.urgent.length} />{b.urgent.map(o => <WbOrderCard key={o.order_id} o={o} onOpen={onOpenOrder} />)}</>}
                  {WB_STAGE_ORDER.map(k => b.byStage[k].length > 0 && (
                    <React.Fragment key={k}>
                      <SubHead color={WB_STAGE[k].color} icon={WB_STAGE[k].icon} label={WB_STAGE[k].label} count={b.byStage[k].length} muted={WB_STAGE[k].muted} />
                      {b.byStage[k].map(o => <WbOrderCard key={o.order_id} o={o} onOpen={onOpenOrder} />)}
                    </React.Fragment>
                  ))}
                </Section>
              )}
              {b.counts.leads > 0 && (
                <Section icon="inbox" title="Заявки" color={WB_LEAD_COLOR} count={b.counts.leads}>
                  {b.leadsReady.length > 0 && <><SubHead color={WB_LEAD_COLOR} icon="user-check" label="Можна рухати" count={b.leadsReady.length} />{b.leadsReady.map(l => <WbLeadCard key={l.id} l={l} onOpen={onOpenLead} />)}</>}
                  {b.leadsWait.length > 0 && <><SubHead color="#6B7280" icon="truck" label="Чекаємо постачальника" count={b.leadsWait.length} muted />{b.leadsWait.map(l => <WbLeadCard key={l.id} l={l} onOpen={onOpenLead} />)}</>}
                </Section>
              )}
            </>
          )}
        </div>
      </div>
    );
  }

  // ── ТОЧКА ВХОДУ ─────────────────────────────────────────────────────────────
  function Workboard({ isMobile = false, currentManager = "", onOpenOrder, onOpenLead, onCallBack }) {
    const [data, setData] = wbUseState({ orders: [], leads: [], missed: [] });
    const [loading, setLoading] = wbUseState(true);
    const [scope, setScope] = wbUseState(() => localStorage.getItem("wb_scope") || "mine");
    const [typeFilter, setTypeFilter] = wbUseState("all");
    const [sortMode, setSortMode] = wbUseState(() => localStorage.getItem("wb_sort") || "old");
    const [hotOnly, setHotOnly] = wbUseState(false);
    const [query, setQuery] = wbUseState("");

    const load = wbUseRef(() => {});
    load.current = () => {
      setLoading(true);
      fetch("/api/workboard").then(r => r.json()).then(d => {
        const now = Date.now();
        // missed з /api/workboard: {phone10, display, at} → {phone, phone10, at, agoMin}
        const missed = (d.missed || []).map(m => ({
          phone: m.display || m.phone || "",
          phone10: m.phone10 || String(m.phone || "").replace(/\D/g, "").slice(-10),
          at: m.at,
          agoMin: m.at ? Math.max(0, Math.round((now - m.at) / 60000)) : (m.agoMin || 0),
        }));
        const nd = { orders: d.orders || [], leads: d.leads || [], missed };
        setData(nd); setLoading(false);
        if (window._setWorkboardCount) window._setWorkboardCount(nd.orders.length + nd.leads.length);
      }).catch(() => { setData({ orders: [], leads: [], missed: [] }); setLoading(false); });
    };
    wbUseEffect(() => { load.current(); const t = setInterval(() => load.current(), 45000); return () => clearInterval(t); }, []);
    wbUseEffect(() => { localStorage.setItem("wb_scope", scope); }, [scope]);
    wbUseEffect(() => { localStorage.setItem("wb_sort", sortMode); }, [sortMode]);

    const b = wbUseMemo(() => wbBuildBoard(scope, typeFilter, data, currentManager, { sortMode, hotOnly, query }),
      [scope, typeFilter, data, currentManager, sortMode, hotOnly, query]);

    const anyRaw = (data.orders.length + data.leads.length + data.missed.length) > 0;
    const onResetFilters = () => { setTypeFilter("all"); setHotOnly(false); setQuery(""); setScope("all"); };

    // «Передзвонив» — закрити пропущений (локально + проп для бекенда)
    const handleCallBack = (m, i) => {
      setData(d => ({ ...d, missed: d.missed.filter((_, idx) => idx !== i) }));
      if (onCallBack) onCallBack(m);
    };

    const shared = { b, scope, setScope, typeFilter, setTypeFilter, loading,
      sortMode, setSortMode, hotOnly, setHotOnly, query, setQuery, anyRaw, onResetFilters,
      onRefresh: () => load.current(), onOpenOrder, onOpenLead, onCallBack: handleCallBack };

    return isMobile ? <WbMobileView {...shared} /> : <WbDesktopView {...shared} />;
  }

  window.Workboard = Workboard;
})();
