// ============================================================================
// ЗАЯВКИ — РОЗДІЛЕНІ ВКЛАДКИ · спільні примітиви + хром сторінки
// ============================================================================
const { useState, useEffect, useRef } = React;

function LsIcon({ name, size = 20, color, style }) {
  const ref = useRef(null);
  useEffect(() => {
    if (ref.current && window.lucide) {
      ref.current.innerHTML = "";
      const el = document.createElement("i");
      el.setAttribute("data-lucide", name);
      el.style.width = size + "px";
      el.style.height = size + "px";
      if (color) el.style.color = color;
      ref.current.appendChild(el);
      window.lucide.createIcons({ nameAttr: "data-lucide" });
    }
  }, [name, size, color]);
  return <span ref={ref} style={{ display: "inline-flex", lineHeight: 0, flexShrink: 0, ...style }}></span>;
}

function LsAvatar({ name, size = 26 }) {
  const initials = (name || "?").replace(/[«»]/g, "").split(" ").map(s => s[0]).slice(0, 2).join("");
  return (
    <div style={{
      width: size, height: size, borderRadius: "50%", flexShrink: 0,
      background: "var(--bg-raised)", color: "var(--fg-primary)",
      display: "flex", alignItems: "center", justifyContent: "center",
      fontSize: size * 0.38, fontWeight: 600, border: "1px solid var(--border-default)",
    }}>{initials}</div>
  );
}

function lsFmtAge(min) {
  if (min < 60) return `${min} хв`;
  if (min < 1440) return `${Math.floor(min / 60)} год`;
  return `${Math.floor(min / 1440)} д`;
}
function lsAgeTone(min, done) {
  if (done) return "var(--fg-muted)";
  if (min < 15) return "#10B981";
  if (min < 60) return "var(--fg-secondary)";
  if (min < 240) return "#F59E0B";
  return "#EF4444";
}
function lsFmtPhone(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 lsFmtUah(n) {
  if (n == null || n === "" || isNaN(Number(n))) return "—";
  return Number(n).toLocaleString("uk-UA").replace(/\u00a0/g, " ") + " ₴";
}

// ── Активність дзвінків по телефону заявки ──────────────────────────────────
// Бере дзвінки з глобального кешу (window._crmCalls, ~7 днів з Ringostat) і каже:
// дзвонив клієнт? передзвонив менеджер? чи лишилось «не передзвонили».
// Поля дзвінка: caller/dst (телефони), call_type ('in'/'transitin'=вхідний),
// employee_fio (менеджер), billsec (сек розмови; >0 = додзвонились), calldate.
function lsCallTs(c) { if (c.calldateTs) return Number(c.calldateTs); const d = new Date(String(c.calldate || "").replace(" ", "T")); return isNaN(d) ? 0 : d.getTime(); }
// sinceTs — рахуємо активність ЛИШЕ з моменту створення заявки (дзвінки ДО неї —
// це той вхідний, через який заявку й створили, він не означає «відпрацювали»).
function lsCallActivity(phone, sinceTs) {
  const op = String(phone || "").replace(/\D/g, "").slice(-9);
  if (op.length < 9) return null;
  const all = (window._crmCalls && window._crmCalls.data) || [];
  const m = p => String(p || "").replace(/\D/g, "").slice(-9);
  let calls = all.filter(c => m(c.caller) === op || m(c.dst) === op).sort((a, b) => lsCallTs(a) - lsCallTs(b));
  if (sinceTs) calls = calls.filter(c => lsCallTs(c) >= Number(sinceTs));
  if (!calls.length) return { total: 0, state: "none" };
  const isIn  = c => c.call_type === "in" || c.call_type === "transitin";
  const ans   = c => Number(c.billsec) > 0;
  const hadInbound = calls.some(isIn);
  const lastOutAns = [...calls].reverse().find(c => !isIn(c) && ans(c));
  const anyAns = calls.some(ans);
  // «не передзвонили»: був вхідний і ПІСЛЯ нього жодного успішного контакту
  let notCalledBack = false;
  if (hadInbound) {
    const lastInTs = Math.max(...calls.filter(isIn).map(lsCallTs));
    notCalledBack = !calls.some(c => ans(c) && lsCallTs(c) >= lastInTs);
  }
  const ref = lastOutAns || calls[calls.length - 1];
  return {
    total: calls.length, hadInbound, anyAns, calledBack: !!lastOutAns, notCalledBack,
    lastManager: ref.employee_fio || "", lastDur: Number(ref.billsec) || 0, lastDate: ref.calldate || "",
    state: notCalledBack ? "missed" : (lastOutAns ? "ok" : (anyAns ? "in_only" : "tried")),
  };
}
function lsFmtDur(s) { s = Number(s) || 0; const m = Math.floor(s / 60); return m + ":" + String(s % 60).padStart(2, "0"); }
// Компактний бейдж активності дзвінків для рядка/картки заявки.
function LsCallBadge({ phone, since, compact }) {
  const a = lsCallActivity(phone, since);
  if (!a) return null;
  const first = (a.lastManager || "").split(" ")[0];
  let icon, color, text;
  if (a.state === "none")        { icon = "phone-off";      color = "var(--fg-muted)"; text = "немає дзвінків"; }
  else if (a.state === "missed") { icon = "phone-missed";   color = "#EF4444";         text = "не передзвонили"; }
  else if (a.state === "ok")     { icon = "phone-outgoing"; color = "#10B981";         text = (first ? first + " · " : "") + lsFmtDur(a.lastDur); }
  else if (a.state === "in_only"){ icon = "phone-incoming"; color = "#F59E0B";         text = "клієнт дзвонив"; }
  else                           { icon = "phone";          color = "var(--fg-muted)"; text = a.total + " дзвін."; }
  return (
    <span title={"Дзвінків: " + a.total + (a.lastDate ? " · ост. " + a.lastDate : "")} style={{
      display: "inline-flex", alignItems: "center", gap: 4, color, fontSize: compact ? 10 : 10.5,
      fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0,
    }}>
      <LsIcon name={icon} size={11} color={color}/>{text}
    </span>
  );
}

// ── Канали комунікації (менеджер відмічає, що списався з клієнтом) ──────────
// Зберігається у data.comm = ['viber','telegram',...]. Дає видимість навіть коли
// дзвінка не було: «не передзвонив, але списався у Viber».
const LS_COMM = [
  { k: "viber", label: "Viber", icon: "message-circle", color: "#7B519D" },
  { k: "telegram", label: "Telegram", icon: "send", color: "#229ED9" },
];
function lsToggleArr(arr, k) { const a = Array.isArray(arr) ? arr.slice() : []; const i = a.indexOf(k); if (i >= 0) a.splice(i, 1); else a.push(k); return a; }
// Редагування — чіпи-перемикачі + посилання відкрити чат (через window.MessengerBtn).
function LsCommMarkers({ value, onChange, phone }) {
  const v = Array.isArray(value) ? value : [];
  const digits = String(phone || "").replace(/\D/g, "");
  return (
    <div>
      <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: "0.04em", textTransform: "uppercase", color: "var(--fg-muted)", marginBottom: 6 }}>Списався з клієнтом</div>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center" }}>
        {LS_COMM.map(c => {
          const on = v.includes(c.k);
          return (
            <button key={c.k} type="button" onClick={() => onChange(lsToggleArr(v, c.k))} style={{
              display: "inline-flex", alignItems: "center", gap: 6, height: 30, padding: "0 11px", borderRadius: 8, cursor: "pointer", fontFamily: "inherit", fontSize: 12.5, fontWeight: 500,
              border: "1px solid " + (on ? c.color : "var(--border-default)"),
              background: on ? "color-mix(in oklab, " + c.color + " 16%, transparent)" : "var(--bg-raised)",
              color: on ? "#fff" : "var(--fg-secondary)",
            }}>
              <LsIcon name={on ? "check" : c.icon} size={13} color={on ? c.color : undefined}/>{c.label}
            </button>
          );
        })}
        {digits.length >= 9 && window.MessengerBtn && (
          <span style={{ display: "inline-flex", gap: 6, marginLeft: 4 }}>
            <window.MessengerBtn kind="viber" phone={phone}/>
            <window.MessengerBtn kind="telegram" phone={phone}/>
          </span>
        )}
      </div>
    </div>
  );
}
// Дрібний бейдж для рядка/картки: показує, у яких каналах списались.
function LsCommBadge({ comm }) {
  const v = Array.isArray(comm) ? comm : [];
  if (!v.length) return null;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }} title={"Списався: " + v.join(", ")}>
      {LS_COMM.filter(c => v.includes(c.k)).map(c => <LsIcon key={c.k} name={c.icon} size={11} color={c.color}/>)}
    </span>
  );
}

// Вбудований програвач запису дзвінка (без переходу в нове вікно).
// Пауза НЕ згортає плеер — кнопка й прогрес лишаються (фікс попередньої поведінки).
function LsAudioPlayer({ src, size = 30 }) {
  const [playing, setPlaying] = useState(false);
  const [progress, setProgress] = useState(0);
  const audioRef = useRef(null);
  useEffect(() => () => { if (audioRef.current) { audioRef.current.pause(); audioRef.current = null; } }, []);
  const toggle = (e) => {
    if (e) e.stopPropagation();
    if (!src) return;
    if (playing && audioRef.current) { audioRef.current.pause(); setPlaying(false); return; }
    if (!audioRef.current) {
      const a = new Audio(src);
      a.ontimeupdate = () => { if (a.duration) setProgress(Math.round((a.currentTime / a.duration) * 100)); };
      a.onended = () => { setPlaying(false); setProgress(0); };
      audioRef.current = a;
    }
    audioRef.current.play().then(() => setPlaying(true)).catch(() => setPlaying(false));
  };
  if (!src) return null;
  return (
    <div onClick={e => e.stopPropagation()} style={{ display: "inline-flex", alignItems: "center", gap: 7, flexShrink: 0 }}>
      <button onClick={toggle} title={playing ? "Пауза" : "Слухати запис"} style={{
        width: size, height: size, borderRadius: "50%", border: "1px solid var(--accent-ring)", background: "var(--accent-soft)",
        color: "var(--accent)", cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
      }}><LsIcon name={playing ? "pause" : "play"} size={Math.round(size * 0.5)}/></button>
      {(playing || progress > 0) && (
        <div style={{ width: 54, height: 4, borderRadius: 2, background: "var(--bg-raised)", overflow: "hidden" }}>
          <div style={{ width: progress + "%", height: "100%", background: "var(--accent)", borderRadius: 2 }}></div>
        </div>
      )}
    </div>
  );
}

// Повна історія дзвінків з номером (з персистентної БД /api/calls/by-phone).
// Показуємо в картці заявки — щоб бачити всю комунікацію з клієнтом.
function LsCallTimeline({ phone, since }) {
  const [calls, setCalls] = useState(null);
  useEffect(() => {
    let alive = true;
    const op = String(phone || "").replace(/\D/g, "");
    if (op.length < 9 || !window.API || !window.API.get) { setCalls([]); return; }
    window.API.get("/api/calls/by-phone?phone=" + encodeURIComponent(phone) + "&days=365")
      .then(d => { if (alive) setCalls((d && d.calls) || []); })
      .catch(() => { if (alive) setCalls([]); });
    return () => { alive = false; };
  }, [phone]);
  const lbl = { fontSize: 11, fontWeight: 600, letterSpacing: "0.04em", textTransform: "uppercase", color: "var(--fg-muted)", marginBottom: 8 };
  if (calls === null) return <div style={{ fontSize: 12, color: "var(--fg-muted)" }}>Завантаження історії дзвінків…</div>;
  if (!calls.length) return <div><div style={lbl}>Комунікація</div><div style={{ fontSize: 12, color: "var(--fg-muted)" }}>Дзвінків з цим номером не знайдено (за 12 міс).</div></div>;
  return (
    <div>
      <div style={lbl}>Комунікація · {calls.length} дзвінк.</div>
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        {calls.map(c => {
          const inc = c.direction === "in";
          const ans = Number(c.billsec) > 0;
          const before = since && lsCallTs(c) < Number(since); // дзвінок ДО створення заявки
          const color = inc ? (ans ? "#10B981" : "#EF4444") : (ans ? "var(--fg-secondary)" : "#F59E0B");
          return (
            <div key={c.uniqueid} style={{ display: "flex", alignItems: "center", gap: 9, background: "var(--bg-raised)", border: "1px solid var(--border-subtle)", borderRadius: 8, padding: "8px 11px", opacity: before ? 0.6 : 1 }}>
              <LsIcon name={inc ? "phone-incoming" : "phone-outgoing"} size={14} color={color}/>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 12.5, color: "var(--fg-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {inc ? "Вхідний від клієнта" : "Вихідний"}{c.employee_fio ? " · " + c.employee_fio : ""}
                  {before && <span style={{ fontSize: 10, color: "var(--fg-muted)", marginLeft: 6, fontWeight: 500 }}>· до заявки</span>}
                </div>
                <div style={{ fontSize: 11, color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums" }}>
                  {c.calldate}{ans ? " · розмова " + lsFmtDur(c.billsec) : " · " + (c.disposition || "без відповіді")}
                </div>
              </div>
              {c.recording && (window.CrmCallPlayBtn ? <window.CrmCallPlayBtn call={c} size={30}/> : <LsAudioPlayer src={c.recording}/>)}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── Пігулки ────────────────────────────────────────────────────────────────
function LsSource({ source, withLabel = false }) {
  const s = LS_SOURCES[source] || LS_SOURCES.site;
  return (
    <span title={s.label} style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      color: s.color, flexShrink: 0,
    }}>
      <span style={{
        display: "inline-flex", alignItems: "center", justifyContent: "center",
        width: 20, height: 20, borderRadius: 5,
        background: "color-mix(in oklab, " + s.color + " 16%, transparent)",
      }}><LsIcon name={s.icon} size={11}/></span>
      {withLabel && <span style={{ fontSize: 11, fontWeight: 500, color: "var(--fg-secondary)" }}>{s.label}</span>}
    </span>
  );
}

function LsChip({ map, value }) {
  const s = map[value];
  if (!s) return null;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      height: 22, padding: "0 9px 0 8px", borderRadius: 999,
      background: s.bg, color: s.fg, whiteSpace: "nowrap",
      fontSize: 11, fontWeight: 500,
    }}>
      <span style={{ width: 6, height: 6, borderRadius: "50%", background: s.dot }}></span>
      {s.label}
    </span>
  );
}

// Клікабельний чіп статусу з випадайкою — швидка зміна статусу заявки.
function LsStatusSelect({ map, value, onChange }) {
  const [open, setOpen] = useState(false);
  const s = map[value];
  return (
    <span style={{ position: "relative", display: "inline-flex", maxWidth: "100%", minWidth: 0 }} onClick={e => e.stopPropagation()}>
      <button title={s ? s.label : ""} onClick={() => setOpen(o => !o)} style={{
        display: "inline-flex", alignItems: "center", gap: 6, height: 22, padding: "0 7px 0 8px", borderRadius: 999,
        maxWidth: "100%", minWidth: 0,
        background: s ? s.bg : "var(--bg-raised)", color: s ? s.fg : "var(--fg-muted)",
        border: "1px solid " + (open ? "var(--border-strong)" : "transparent"),
        fontFamily: "inherit", fontSize: 11, fontWeight: 500, cursor: "pointer",
      }}>
        <span style={{ width: 6, height: 6, borderRadius: "50%", background: s ? s.dot : "var(--fg-muted)", flexShrink: 0 }}></span>
        <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 }}>{s ? s.label : "— статус —"}</span>
        <LsIcon name="chevron-down" size={11} style={{ flexShrink: 0 }}/>
      </button>
      {open && (<React.Fragment>
        <div onClick={() => setOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 60 }}></div>
        <div style={{
          position: "absolute", top: "calc(100% + 4px)", left: 0, zIndex: 61, minWidth: 190,
          background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 8,
          padding: 4, boxShadow: "0 8px 24px rgba(0,0,0,.5)",
        }}>
          {Object.entries(map).map(([k, v]) => (
            <button key={k} onClick={() => { setOpen(false); if (k !== value && onChange) onChange(k); }} style={{
              display: "flex", alignItems: "center", gap: 8, width: "100%", padding: "7px 9px", borderRadius: 6,
              background: k === value ? "var(--bg-active)" : "transparent", border: 0, cursor: "pointer",
              color: "var(--fg-secondary)", fontSize: 12, fontFamily: "inherit", textAlign: "left", whiteSpace: "nowrap",
            }}>
              <span style={{ width: 7, height: 7, borderRadius: "50%", background: v.dot, flexShrink: 0 }}></span>{v.label}
            </button>
          ))}
        </div>
      </React.Fragment>)}
    </span>
  );
}

function LsBotPill({ reply }) {
  const r = LS_BOT[reply];
  if (!r) return <span style={{ color: "var(--fg-muted)", fontSize: 11 }}>—</span>;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 5,
      height: 22, padding: "0 7px", borderRadius: 6,
      background: r.bg, color: r.color, whiteSpace: "nowrap",
      fontSize: 11, fontWeight: 500,
    }}>
      <LsIcon name={r.icon} size={11}/>
      {r.label}
    </span>
  );
}

function LsAge({ min, done }) {
  const tone = lsAgeTone(min, done);
  return (
    <span style={{ fontSize: 12.5, fontWeight: 600, color: tone, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" }}>
      {lsFmtAge(min)}
    </span>
  );
}

function LsManager({ name }) {
  if (!name || name === "—") {
    return (
      <div title="Не призначено" style={{
        width: 26, height: 26, borderRadius: "50%", border: "1px dashed var(--border-strong)",
        display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fg-muted)", flexShrink: 0,
      }}><LsIcon name="user" size={12}/></div>
    );
  }
  return <span title={name}><LsAvatar name={name} size={26}/></span>;
}

function LsClientCell({ client, phone }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 2, minWidth: 0 }}>
      <span style={{ fontSize: 13, color: "var(--fg-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{client}</span>
      <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{lsFmtPhone(phone)}</span>
    </div>
  );
}

// Заголовок-рядок таблиці
function LsTHead({ cols, grid }) {
  return (
    <div style={{
      display: "grid", gridTemplateColumns: grid, gap: 12, alignItems: "center",
      padding: "9px 18px 9px 15px", borderBottom: "1px solid var(--border-subtle)",
      position: "sticky", top: 0, background: "var(--bg-base)", zIndex: 1,
    }}>
      {cols.map((c, i) => (
        <span key={i} style={{
          fontSize: 10.5, fontWeight: 500, letterSpacing: "0.05em", textTransform: "uppercase",
          color: "var(--fg-muted)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
          textAlign: c.startsWith(">") ? "right" : "left",
        }}>{c.replace(/^>/, "")}</span>
      ))}
    </div>
  );
}

// ── Хром: сайдбар + топбар ─────────────────────────────────────────────────
function LsSidebar() {
  const items = [
    { key: "dashboard", label: "Дашборд",      icon: "layout-dashboard" },
    { key: "orders",    label: "Замовлення",   icon: "package" },
    { key: "leads",     label: "Заявки",       icon: "inbox" },
    { key: "monitoring",label: "Моніторинг",   icon: "line-chart" },
    { key: "prices",    label: "Прайси",       icon: "tags" },
    { key: "calls",     label: "Дзвінки",      icon: "phone-call" },
    { key: "banking",   label: "Банки",        icon: "landmark" },
    { key: "suppliers", label: "Постачальники",icon: "truck" },
    { key: "settings",  label: "Налаштування", icon: "settings" },
  ];
  return (
    <aside style={{
      width: 200, flexShrink: 0, background: "var(--bg-panel)", borderRight: "1px solid var(--border-subtle)",
      display: "flex", flexDirection: "column", padding: "14px 10px",
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "2px 8px 16px" }}>
        <div style={{ width: 28, height: 28, borderRadius: 7, background: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff" }}>
          <LsIcon name="zap" size={15}/>
        </div>
        <span style={{ fontSize: 14, fontWeight: 600, color: "var(--fg-primary)" }}>Digitalshop</span>
      </div>
      <nav style={{ display: "flex", flexDirection: "column", gap: 2 }}>
        {items.map(it => {
          const active = it.key === "leads";
          return (
            <div key={it.key} style={{
              display: "flex", alignItems: "center", gap: 10, height: 34, padding: "0 10px",
              borderRadius: 7, fontSize: 13, fontWeight: 500, cursor: "pointer",
              background: active ? "var(--accent-soft)" : "transparent",
              color: active ? "var(--fg-primary)" : "var(--fg-secondary)",
            }}>
              <LsIcon name={it.icon} size={16} color={active ? "var(--accent)" : undefined}/>
              {it.label}
            </div>
          );
        })}
      </nav>
      <div style={{ flex: 1 }}></div>
      <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "10px 8px 0", borderTop: "1px solid var(--border-subtle)" }}>
        <LsAvatar name="Олена Коваленко" size={28}/>
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 12, fontWeight: 500, color: "var(--fg-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>Олена Коваленко</div>
          <div style={{ fontSize: 10.5, color: "var(--fg-muted)" }}>Менеджер</div>
        </div>
      </div>
    </aside>
  );
}

function LsTopBar({ right }) {
  return (
    <div style={{
      height: 52, flexShrink: 0, display: "flex", alignItems: "center", gap: 14,
      padding: "0 20px", background: "var(--bg-panel)", borderBottom: "1px solid var(--border-subtle)",
    }}>
      <span style={{ fontSize: 15, fontWeight: 600, color: "var(--fg-primary)" }}>Заявки</span>
      <div style={{ flex: 1 }}></div>
      {right}
    </div>
  );
}

function LsSearch({ placeholder, width = 240 }) {
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 8, height: 32, padding: "0 10px",
      width, background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 8,
      color: "var(--fg-muted)", fontSize: 12.5,
    }}>
      <LsIcon name="search" size={13}/>
      <span style={{ overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}>{placeholder}</span>
    </div>
  );
}

function LsButton({ variant = "primary", icon, children, style, onClick, title, disabled }) {
  const variants = {
    primary:   { background: "var(--accent)", color: "#fff", border: "1px solid transparent" },
    secondary: { background: "var(--bg-raised)", color: "var(--fg-primary)", border: "1px solid var(--border-default)" },
    ghost:     { background: "transparent", color: "var(--fg-secondary)", border: "1px solid transparent" },
    danger:    { background: "rgba(244,63,94,.12)", color: "#FCA5A5", border: "1px solid rgba(244,63,94,.4)" },
  };
  return (
    <button onClick={onClick} title={title} disabled={disabled} style={{
      display: "inline-flex", alignItems: "center", gap: 7, height: 32, padding: "0 13px",
      borderRadius: 8, fontFamily: "inherit", fontSize: 12.5, fontWeight: 500, cursor: disabled ? "default" : "pointer",
      whiteSpace: "nowrap", opacity: disabled ? 0.6 : 1, ...variants[variant], ...style,
    }}>
      {icon && <LsIcon name={icon} size={14}/>}
      {children}
    </button>
  );
}

// Статус-фільтри в тулбарі вкладки
function LsStatusChips({ map, leads, field = "status" }) {
  const [active, setActive] = useState("all");
  const counts = { all: leads.length };
  Object.keys(map).forEach(k => { counts[k] = leads.filter(l => l[field] === k).length; });
  const chips = [{ key: "all", label: "Усі" }, ...Object.entries(map).map(([k, v]) => ({ key: k, label: v.label, dot: v.dot }))];
  return (
    <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
      {chips.filter(c => c.key === "all" || counts[c.key] > 0).map(c => {
        const isActive = active === c.key;
        return (
          <button key={c.key} onClick={() => setActive(c.key)} style={{
            display: "inline-flex", alignItems: "center", gap: 7, height: 28, padding: "0 11px",
            border: "1px solid " + (isActive ? "var(--accent-ring)" : "var(--border-default)"),
            background: isActive ? "var(--accent-soft)" : "var(--bg-raised)",
            color: isActive ? "var(--fg-primary)" : "var(--fg-secondary)",
            borderRadius: 999, fontFamily: "inherit", fontSize: 12, fontWeight: 500, cursor: "pointer",
          }}>
            {c.dot && <span style={{ width: 6, height: 6, borderRadius: "50%", background: c.dot }}></span>}
            {c.label}
            <span style={{ color: "var(--fg-muted)", fontWeight: 400, fontVariantNumeric: "tabular-nums" }}>{counts[c.key]}</span>
          </button>
        );
      })}
    </div>
  );
}

Object.assign(window, {
  LsIcon, LsAvatar, LsSource, LsChip, LsStatusSelect, LsBotPill, LsAge, LsManager, LsClientCell,
  LsTHead, LsSidebar, LsTopBar, LsSearch, LsButton, LsStatusChips, LsCallBadge, LsCallTimeline,
  LsAudioPlayer, LsCommMarkers, LsCommBadge,
  lsFmtAge, lsAgeTone, lsFmtPhone, lsFmtUah, lsCallActivity, lsFmtDur,
});
