// ============================================================================
// ЗАЯВКИ v2 · внутрішні вкладки
//   Документи — менеджер прикріплює документ + дані клієнта, керівник надсилає
//   Питання менеджерів — внутрішній інбокс «питання до керівника», не губиться в Telegram
// ============================================================================
const { useState: lsUseState } = React;

function LsChannel({ channel, value }) {
  const c = LS_SEND_CHANNELS[channel] || LS_SEND_CHANNELS.email;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6, minWidth: 0 }}>
      <span style={{
        display: "inline-flex", alignItems: "center", justifyContent: "center",
        width: 20, height: 20, borderRadius: 5, flexShrink: 0,
        background: "color-mix(in oklab, " + c.color + " 16%, transparent)", color: c.color,
      }}><LsIcon name={c.icon} size={11}/></span>
      <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-secondary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{value}</span>
    </span>
  );
}

// ── Звʼязок із клієнтом по заявці «Запит товару» ─────────────────────────────
// Дзвінок / Viber / Telegram + шаблони повідомлень (копіюються, тост «Скопійовано»).
// Використовується в desktop-модалі заявки і mobile-шторці. hideCall — коли кнопка
// «Подзвонити» вже є поруч (mobile-футер).
const LS_PRODUCT_TEMPLATES = [
  { name: "Є в наявності", build: (product, client) =>
      `Доброго дня${client ? ", " + client : ""}! Уточнили по вашому запиту — «${product}» є в наявності ✅\nПідкажіть, чи актуально для вас оформити замовлення?` },
  { name: "Немає — аналог?", build: (product, client) =>
      `Доброго дня${client ? ", " + client : ""}! На жаль, «${product}» зараз немає в наявності. Можемо підібрати аналог зі схожими характеристиками — підкажіть, чи було б цікаво?` },
  { name: "Немає в наявності", build: (product, client) =>
      `Доброго дня${client ? ", " + client : ""}! На жаль, «${product}» зараз немає в наявності, і найближчим часом постачання не очікується. Вибачте за незручності 🙏` },
];
function LsClientContact({ phone, client, product, hideCall }) {
  const digits = String(phone || "").replace(/\D/g, "");
  const tel = digits ? "tel:+" + (digits.length === 10 ? "38" + digits : digits) : null;
  const clientName = String(client || "").trim() === "Без імені" ? "" : String(client || "").trim();
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      {/* hideCall: ряд контактів уже є поруч (mobile-шторка) — лишаємо тільки шаблони */}
      {!hideCall && (
        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
          {tel ? (
            <a href={tel} style={{ height: 28, padding: "0 12px", borderRadius: 7, border: "1px solid var(--border-default)", background: "var(--bg-raised)", color: "#10B981", fontSize: 12, fontWeight: 500, fontFamily: "inherit", textDecoration: "none", display: "inline-flex", alignItems: "center", gap: 6 }}>
              <LsIcon name="phone-call" size={12}/> Подзвонити
            </a>
          ) : <span style={{ fontSize: 11.5, color: "var(--fg-muted)" }}>Телефон не вказано</span>}
          {digits && window.MessengerBtn && <MessengerBtn kind="viber" phone={phone}/>}
          {digits && window.MessengerBtn && <MessengerBtn kind="telegram" phone={phone}/>}
        </div>
      )}
      <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
        {LS_PRODUCT_TEMPLATES.map(t => (
          <button key={t.name} onClick={() => copyText(t.build(product || "товар", clientName))} style={{ fontSize: 11.5, padding: "4px 11px", border: "1px solid var(--border-default)", borderRadius: 999, background: "transparent", color: "var(--fg-secondary)", cursor: "pointer", fontFamily: "inherit" }}>
            {t.name}
          </button>
        ))}
      </div>
    </div>
  );
}

// ── Файли/фото заявки (компактна зона: гарантія — фото проблеми) ─────────────
// Той самий механізм, що в документах: нові у f._files (заллються після збереження),
// збережені — список із перегляд/видалити. Фото гарантії дублюються в TG-топік.
function LsLeadFiles({ f, setF, accept }) {
  const ref = React.useRef(null);
  const [drag, setDrag] = React.useState(0);
  const addFiles = (list) => {
    for (const file of list) {
      const reader = new FileReader();
      reader.onload = () => setF(p => ({ ...p, _files: [...(p._files || []), { name: file.name || "photo.png", mime: file.type || "application/octet-stream", dataB64: reader.result, sizeLabel: lsHumanSize(file.size) }] }));
      reader.readAsDataURL(file);
    }
  };
  // Ctrl+V: поки форма відкрита — вставка зображення з буфера одразу додає фото
  React.useEffect(() => {
    const onPaste = (e) => {
      const items = (e.clipboardData && e.clipboardData.items) || [];
      const files = [];
      for (const it of items) if (it.type && it.type.startsWith("image/")) { const fl = it.getAsFile(); if (fl) files.push(fl); }
      if (files.length) { e.preventDefault(); addFiles(files); }
    };
    window.addEventListener("paste", onPaste);
    return () => window.removeEventListener("paste", onPaste);
  }, []);
  const [saved, setSaved] = React.useState(null);
  const [err, setErr] = React.useState("");
  const reload = React.useCallback(() => {
    if (!f.id) { setSaved(null); return; }
    lsApi.files(f.id).then(setSaved).catch(() => setSaved([]));
  }, [f.id]);
  React.useEffect(reload, [reload]);
  const row = { display: "flex", alignItems: "center", gap: 8, padding: "7px 10px", borderRadius: 8, background: "var(--bg-raised)", border: "1px solid var(--border-subtle)", fontSize: 12 };
  const btn = { width: 24, height: 24, border: "1px solid var(--border-default)", borderRadius: 6, background: "transparent", cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0 };
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <input ref={ref} type="file" multiple accept={accept || "image/*"} onChange={e => { addFiles(Array.from(e.target.files || [])); e.target.value = ""; }} style={{ display: "none" }}/>
      {(saved || []).map(sf => (
        <div key={"s" + sf.id} style={row}>
          <LsIcon name="image" size={13} style={{ color: sf.expired ? "var(--fg-disabled)" : "#22D3EE", flexShrink: 0 }}/>
          <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: sf.expired ? "var(--fg-disabled)" : "var(--fg-secondary)" }}>{sf.name}{sf.expired ? " · прострочений" : ""}</span>
          {!sf.expired && <button onClick={() => { setErr(""); lsApi.openFile(sf.id).catch(e => setErr(e.message)); }} title="Переглянути" style={{ ...btn, color: "var(--fg-secondary)" }}><LsIcon name="eye" size={12}/></button>}
          <button onClick={() => { if (window.confirm("Видалити файл «" + sf.name + "»?")) lsApi.deleteFile(sf.id).then(reload).catch(e => setErr(e.message)); }} title="Видалити" style={{ ...btn, color: "#FCA5A5" }}><LsIcon name="trash-2" size={12}/></button>
        </div>
      ))}
      {(f._files || []).map((file, i) => (
        <div key={"n" + i} style={row}>
          <LsIcon name="file-plus" size={13} style={{ color: "#6EE7B7", flexShrink: 0 }}/>
          <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: "var(--fg-secondary)" }}>{file.name} · {file.sizeLabel}</span>
          <span style={{ fontSize: 10, color: "var(--fg-muted)", flexShrink: 0 }}>буде завантажено</span>
          <button onClick={() => setF(p => ({ ...p, _files: (p._files || []).filter((_, j) => j !== i) }))} title="Прибрати" style={{ ...btn, color: "#FCA5A5" }}><LsIcon name="x" size={12}/></button>
        </div>
      ))}
      <div onClick={() => ref.current && ref.current.click()}
        onDragEnter={(e) => { e.preventDefault(); setDrag(n => n + 1); }}
        onDragOver={(e) => e.preventDefault()}
        onDragLeave={() => setDrag(n => Math.max(0, n - 1))}
        onDrop={(e) => { e.preventDefault(); setDrag(0); addFiles(Array.from((e.dataTransfer && e.dataTransfer.files) || [])); }}
        style={{
          border: "1px dashed " + (drag ? "rgba(34,211,238,.7)" : "var(--border-strong)"), borderRadius: 10, padding: "10px 14px",
          background: drag ? "rgba(34,211,238,.08)" : "transparent",
          display: "flex", alignItems: "center", gap: 9, fontSize: 12.5, cursor: "pointer",
          color: drag ? "#67E8F9" : "var(--fg-muted)", fontFamily: "inherit",
        }}>
        <LsIcon name="camera" size={14}/>
        <span>{drag ? "Відпустіть, щоб додати" : "Додати фото: Ctrl+V з буфера, перетягніть або оберіть — потраплять і в Telegram-топік"}</span>
      </div>
      {err && <div style={{ fontSize: 11.5, color: "#FCA5A5" }}>{err}</div>}
    </div>
  );
}

// ── Документи — стіл черги відправки ───────────────────────────────────────
function LsDocsTable({ leads, onSend, onStatus, onEdit }) {
  const grid = "60px 56px minmax(0,1.9fr) 92px minmax(0,1.6fr) 40px 150px 122px";
  return (
    <div>
      <LsTHead grid={grid} cols={["ID", "Час", "Документ", "Замовлення", "Клієнт · куди надіслати", "Від", "Статус", ""]}/>
      {leads.map(l => (
        <div key={l.id} onClick={() => onEdit && onEdit(l)} className="ls-row" style={{
          display: "grid", gridTemplateColumns: grid, gap: 12, alignItems: "center",
          padding: "13px 18px 13px 15px", borderBottom: "1px solid var(--border-subtle)", cursor: "pointer",
        }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--fg-muted)" }}>#{l.id}</span>
          <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
            <LsAge min={l.ageMin} done={l.status === "sent"}/>
            <span style={{ fontSize: 10, color: "var(--fg-muted)", fontVariantNumeric: "tabular-nums" }}>{l.ts}</span>
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
              <span style={{
                display: "inline-flex", alignItems: "center", justifyContent: "center",
                width: 20, height: 20, borderRadius: 5, flexShrink: 0,
                background: "rgba(34,211,238,.13)", color: "#22D3EE",
              }}><LsIcon name="file-text" size={11}/></span>
              <span style={{ fontSize: 13.5, fontWeight: 600, color: "var(--fg-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                {l.docType} {l.docNo}
              </span>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11, color: "var(--fg-muted)", marginTop: 3, marginLeft: 28, minWidth: 0 }}>
              <LsIcon name="paperclip" size={10}/>
              <span style={{ fontFamily: "var(--font-mono)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                {(l.file && l.file.name) || l.fileName || "без файлу"}{((l.file && l.file.size) || l.fileSize) ? " · " + ((l.file && l.file.size) || l.fileSize) : ""}
              </span>
              {Array.isArray(l.invoiceRefs) && l.invoiceRefs.length > 0 && <span style={{ color: "#22D3EE", whiteSpace: "nowrap", flexShrink: 0 }}>· <LsIcon name="receipt" size={10} style={{ verticalAlign: "-1px" }}/> №{l.invoiceRefs.map(a => a.number).join(", ")}</span>}
              {l.note && <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>· {l.note}</span>}
            </div>
          </div>
          {l.orderId ? (
            <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12, fontWeight: 500, color: "var(--accent)", fontFamily: "var(--font-mono)" }}>
              <LsIcon name="package" size={12}/>№{l.orderId}
            </span>
          ) : <span style={{ color: "var(--fg-muted)", fontSize: 12 }}>—</span>}
          <div style={{ display: "flex", flexDirection: "column", gap: 3, minWidth: 0 }}>
            <span style={{ fontSize: 13, color: "var(--fg-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{l.client}</span>
            <LsChannel channel={l.channel} value={l.channel === "nova_poshta"
              ? [l.npCity, l.npDelivery === "address" ? [l.npStreet, l.npHouse].filter(Boolean).join(" ") : l.npBranch].filter(Boolean).join(", ")
              : l.channelValue}/>
            {l.ttn && <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "#6EE7B7" }}>ТТН {l.ttn}</span>}
          </div>
          <LsManager name={l.manager}/>
          <div style={{ display: "flex", flexDirection: "column", gap: 3, alignItems: "flex-start" }}>
            <LsStatusSelect map={LS_DOC_STATUSES} value={l.status} onChange={s => onStatus && onStatus(l.id, s)}/>
            {l.sentAt && <span style={{ fontSize: 10.5, color: "var(--fg-muted)" }}>{l.sentAt}</span>}
          </div>
          {l.status === "pending" ? (
            <button onClick={(e) => { e.stopPropagation(); onSend(l.id); }} className="ls-cta" style={{
              display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6, height: 28,
              border: "1px solid var(--accent-ring)", borderRadius: 7, background: "var(--accent-soft)",
              color: "#C7D2FE", fontFamily: "inherit", fontSize: 11.5, fontWeight: 500, cursor: "pointer", whiteSpace: "nowrap",
            }}>
              <LsIcon name="send" size={12}/> Надіслати
            </button>
          ) : <span></span>}
        </div>
      ))}
    </div>
  );
}

// ── Модал: менеджер додає документ у чергу ─────────────────────────────────
function LsField({ label, children }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <span style={{ fontSize: 11, fontWeight: 500, letterSpacing: "0.04em", textTransform: "uppercase", color: "var(--fg-muted)" }}>{label}</span>
      {children}
    </div>
  );
}

function LsInput({ value, onChange, placeholder, mono }) {
  return (
    <input value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder} style={{
      height: 34, padding: "0 12px", borderRadius: 8, border: "1px solid var(--border-default)",
      background: "var(--bg-raised)", color: "var(--fg-primary)", fontFamily: mono ? "var(--font-mono)" : "inherit",
      fontSize: 12.5, outline: "none", width: "100%", boxSizing: "border-box",
    }}/>
  );
}

// Універсальний автокомпліт (Нова Пошта міста/відділення тощо). fetcher(q) → [{label,value}].
// minChars=1 для відділень (щоб «1» одразу знаходило Відділення №1).
function LsAutocomplete({ value, onChange, fetcher, placeholder, mono, minChars = 2 }) {
  const [open, setOpen] = React.useState(false);
  const [items, setItems] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const tRef = React.useRef(null);
  const onType = (v) => {
    onChange(v); setOpen(true);
    clearTimeout(tRef.current);
    if (!v || v.length < minChars) { setItems([]); return; }
    tRef.current = setTimeout(() => {
      setLoading(true);
      Promise.resolve(fetcher(v)).then(r => { setItems(r || []); setLoading(false); }).catch(() => { setItems([]); setLoading(false); });
    }, 300);
  };
  // Клік/фокус на полі з префілом (місто/відділення з замовлення) — одразу показуємо
  // список варіантів за поточним значенням, щоб можна було вибрати точний запис НП.
  const onFocus = () => { if (value && String(value).length >= minChars && !open) onType(value); };
  return (
    <div style={{ position: "relative" }} onFocus={onFocus}>
      <LsInput value={value} onChange={onType} placeholder={placeholder} mono={mono}/>
      {open && (items.length > 0 || loading) && (<React.Fragment>
        <div onClick={() => setOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 69 }}></div>
        <div style={{ position: "absolute", top: "calc(100% + 4px)", left: 0, right: 0, zIndex: 70, background: "var(--bg-raised)", border: "1px solid var(--border-default)", borderRadius: 8, maxHeight: 220, overflowY: "auto", boxShadow: "0 8px 24px rgba(0,0,0,.5)" }}>
          {loading && <div style={{ padding: "8px 10px", fontSize: 12, color: "var(--fg-muted)" }}>Пошук…</div>}
          {items.map((it, i) => (
            <button key={i} onClick={() => { onChange(it.value); setItems([]); setOpen(false); }} style={{ display: "block", width: "100%", textAlign: "left", padding: "8px 10px", border: 0, background: "transparent", color: "var(--fg-secondary)", fontSize: 12.5, cursor: "pointer", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{it.label}</button>
          ))}
        </div>
      </React.Fragment>)}
    </div>
  );
}

function lsHumanSize(n) {
  if (n == null) return "";
  return n < 1024 ? n + " Б" : n < 1048576 ? (n / 1024).toFixed(0) + " КБ" : (n / 1048576).toFixed(1) + " МБ";
}

// Поля документа (тип, отримувач ФІЗ/ЮР, канал з умовними полями, файл) — спільні для
// «Додати документ» і «Нова заявка → Документ». Працює на одному об'єкті стану f + set/setF.
function LsDocFields({ f, set, setF }) {
  const fileRef = React.useRef(null);
  // Кілька файлів: накопичуємо в f._files (нові, ще не збережені) — і з провідника,
  // і drag&drop; можна докидати по одному за кілька заходів, список не замінюється
  const addFiles = (list) => {
    for (const file of list) {
      const reader = new FileReader();
      reader.onload = () => setF(p => ({ ...p, _files: [...(p._files || []), { name: file.name, mime: file.type || "application/octet-stream", dataB64: reader.result, sizeLabel: lsHumanSize(file.size) }] }));
      reader.readAsDataURL(file);
    }
  };
  const onPick = (e) => {
    addFiles(Array.from(e.target.files || []));
    e.target.value = ""; // дозволяє вибрати той самий файл повторно
  };
  // Drag&drop на зону файлів (ПК): підсвічуємо при наведенні, dragenter/leave вкладені — рахуємо
  const [dragOver, setDragOver] = React.useState(0);
  const onDrop = (e) => {
    e.preventDefault(); e.stopPropagation(); setDragOver(0);
    addFiles(Array.from((e.dataTransfer && e.dataTransfer.files) || []));
  };
  const delStaged = (i) => setF(p => ({ ...p, _files: (p._files || []).filter((_, j) => j !== i) }));
  // Збережені файли заявки (режим редагування): список з перегляд/видалити
  const [saved, setSaved] = React.useState(null);
  const [fileErr, setFileErr] = React.useState("");
  const reloadSaved = React.useCallback(() => {
    if (!f.id) { setSaved(null); return; }
    lsApi.files(f.id).then(setSaved).catch(() => setSaved([]));
  }, [f.id]);
  React.useEffect(reloadSaved, [reloadSaved]);
  const openSaved = (sf) => { setFileErr(""); lsApi.openFile(sf.id).catch(e => setFileErr(e.message)); };
  const delSaved = (sf) => {
    if (!window.confirm(`Видалити файл «${sf.name}»?`)) return;
    setFileErr("");
    lsApi.deleteFile(sf.id).then(reloadSaved).catch(e => setFileErr(e.message));
  };
  const fileRow = { display: "flex", alignItems: "center", gap: 8, padding: "7px 10px", borderRadius: 8, background: "var(--bg-raised)", border: "1px solid var(--border-subtle)", fontSize: 12 };
  const fileBtn = { width: 24, height: 24, border: "1px solid var(--border-default)", borderRadius: 6, background: "transparent", cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0 };

  // ── Прикріплення рахунку з нашої бази (без повторного завантаження) ──
  // Зберігаємо лише посилання (invoiceId+знімок номера/суми) у f.invoiceRefs;
  // PDF резолвимо на льоту за invoiceId (fileId протухає, invoiceId — вічний).
  const attachedInv = f.invoiceRefs || [];
  const [invOpen, setInvOpen] = React.useState(false);
  const [invMode, setInvMode] = React.useState("order"); // order | no
  const [invQ, setInvQ] = React.useState("");
  const [invResults, setInvResults] = React.useState(null);
  const [invBusy, setInvBusy] = React.useState(false);
  const [invErr, setInvErr] = React.useState("");
  const openInvPicker = () => {
    setInvOpen(true); setInvResults(null); setInvErr("");
    if (f.orderId) { setInvMode("order"); setInvQ(String(f.orderId)); }
  };
  const doInvSearch = () => {
    const q = String(invQ || "").trim();
    if (!q) { setInvErr("Введіть номер"); return; }
    setInvBusy(true); setInvErr("");
    lsApi.searchInvoices(invMode === "order" ? { orderId: q } : { no: q })
      .then(rows => { setInvResults(rows); setInvBusy(false); })
      .catch(e => { setInvBusy(false); setInvErr(e.message); });
  };
  const attachInv = (inv) => {
    if (attachedInv.some(a => a.invoiceId === inv.id)) return;
    setF(p => ({ ...p, invoiceRefs: [...(p.invoiceRefs || []), { invoiceId: inv.id, number: inv.invoice_no, sellerName: inv.seller_name, total: inv.total, orderId: inv.order_id }] }));
  };
  const detachInv = (id) => setF(p => ({ ...p, invoiceRefs: (p.invoiceRefs || []).filter(a => a.invoiceId !== id) }));
  const openInvFile = (id, kind) => { setInvErr(""); lsApi.openInvoiceFile(id, kind).catch(e => setInvErr(e.message)); };
  const lsMoney = (n) => (Number(n) || 0).toLocaleString("uk-UA");
  const ch = f.channel || "email";
  const isUr = f.recipient === "ur";
  const pill = (active, accent) => ({
    height: 30, padding: "0 11px", borderRadius: 999, fontFamily: "inherit", fontSize: 12, fontWeight: 500, cursor: "pointer",
    display: "inline-flex", alignItems: "center", gap: 6,
    border: "1px solid " + (active ? (accent || "rgba(34,211,238,.5)") : "var(--border-default)"),
    background: active ? (accent ? "color-mix(in oklab, " + accent + " 14%, transparent)" : "rgba(34,211,238,.13)") : "var(--bg-raised)",
    color: active ? (accent || "#67E8F9") : "var(--fg-secondary)",
  });
  return (
    <React.Fragment>
      <LsField label="Тип документа">
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {LS_DOC_TYPES.map(t => <button key={t} onClick={() => set("docType")(t)} style={pill(f.docType === t)}>{t}</button>)}
        </div>
      </LsField>

      <LsField label="Отримувач">
        <div style={{ display: "flex", gap: 6 }}>
          {Object.entries(LS_RECIPIENTS).map(([k, r]) => <button key={k} onClick={() => set("recipient")(k)} style={pill((f.recipient || "fiz") === k, "var(--accent)")}>{r.label}</button>)}
        </div>
      </LsField>

      <div style={{ display: "grid", gridTemplateColumns: isUr ? "110px 1fr 150px" : "110px 1fr", gap: 12 }}>
        <LsField label="Замовлення №"><LsInput value={f.orderId || ""} onChange={set("orderId")} placeholder="1251" mono/></LsField>
        <LsField label={isUr ? "Компанія" : "Клієнт"}><LsInput value={f.client || ""} onChange={set("client")} placeholder={isUr ? "ТОВ «…»" : "Ім'я"}/></LsField>
        {isUr && <LsField label="ЄДРПОУ"><LsInput value={f.edrpou || ""} onChange={set("edrpou")} placeholder="12345678" mono/></LsField>}
      </div>

      <LsField label="Канал відправки">
        <div style={{ display: "flex", gap: 5, flexWrap: "wrap" }}>
          {Object.entries(LS_SEND_CHANNELS).map(([k, c]) => (
            <button key={k} onClick={() => set("channel")(k)} style={pill(ch === k, c.color)}><LsIcon name={c.icon} size={13}/>{c.label}</button>
          ))}
        </div>
      </LsField>

      {ch === "email" && <LsField label="Email"><LsInput value={f.channelValue || ""} onChange={set("channelValue")} placeholder="email@клієнта.ua" mono/></LsField>}
      {ch === "vchasno" && <LsField label="Email або ЄДРПОУ в «Вчасно»"><LsInput value={f.channelValue || ""} onChange={set("channelValue")} placeholder="email або ЄДРПОУ контрагента" mono/></LsField>}
      {ch === "nova_poshta" && (<React.Fragment>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <LsField label="ПІБ отримувача"><LsInput value={f.npName || ""} onChange={set("npName")} placeholder="Прізвище Ім'я По батькові"/></LsField>
          <LsField label="Телефон"><LsInput value={f.npPhone || ""} onChange={set("npPhone")} placeholder="+38 0XX XXX XX XX" mono/></LsField>
        </div>
        <LsField label="Доставка">
          <div style={{ display: "flex", gap: 6 }}>
            <button onClick={() => set("npDelivery")("branch")} style={pill((f.npDelivery || "branch") === "branch", "#FB7185")}>На відділення</button>
            <button onClick={() => set("npDelivery")("address")} style={pill(f.npDelivery === "address", "#FB7185")}>Адресна (кур'єр)</button>
          </div>
        </LsField>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <LsField label="Місто"><LsAutocomplete value={f.npCity || ""} onChange={set("npCity")} placeholder="Почніть вводити місто…" fetcher={lsNpCities}/></LsField>
          {f.npDelivery === "address"
            ? <LsField label="Вулиця"><LsAutocomplete value={f.npStreet || ""} onChange={set("npStreet")} placeholder="Почніть вводити вулицю…" fetcher={(q) => lsNpStreets(f.npCity, q)}/></LsField>
            : <LsField label="Відділення"><LsAutocomplete value={f.npBranch || ""} onChange={set("npBranch")} placeholder="№ або адреса" minChars={1} fetcher={(q) => lsNpWarehouses(f.npCity, q)}/></LsField>}
        </div>
        {f.npDelivery === "address" && (
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <LsField label="Будинок"><LsInput value={f.npHouse || ""} onChange={set("npHouse")} placeholder="12А" mono/></LsField>
            <LsField label="Квартира / офіс (необов'язково)"><LsInput value={f.npFlat || ""} onChange={set("npFlat")} placeholder="5" mono/></LsField>
          </div>
        )}
      </React.Fragment>)}

      <LsField label="Файли документа">
        <input ref={fileRef} type="file" multiple onChange={onPick} style={{ display: "none" }}/>
        <div onDragEnter={(e) => { e.preventDefault(); setDragOver(n => n + 1); }}
             onDragOver={(e) => e.preventDefault()}
             onDragLeave={() => setDragOver(n => Math.max(0, n - 1))}
             onDrop={onDrop}
             style={{ display: "flex", flexDirection: "column", gap: 6 }}>
          {/* збережені (режим редагування) */}
          {(saved || []).map(sf => (
            <div key={"s" + sf.id} style={fileRow}>
              <LsIcon name="paperclip" size={13} style={{ color: sf.expired ? "var(--fg-disabled)" : "#22D3EE", flexShrink: 0 }}/>
              <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: sf.expired ? "var(--fg-disabled)" : "var(--fg-secondary)" }}>
                {sf.name} · {lsHumanSize(sf.size)}{sf.expired ? " · прострочений" : ""}
              </span>
              {!sf.expired && <button onClick={() => openSaved(sf)} title="Переглянути / скачати" style={{ ...fileBtn, color: "var(--fg-secondary)" }}><LsIcon name="eye" size={12}/></button>}
              <button onClick={() => delSaved(sf)} title="Видалити файл" style={{ ...fileBtn, color: "#FCA5A5" }}><LsIcon name="trash-2" size={12}/></button>
            </div>
          ))}
          {/* нові, ще не збережені */}
          {(f._files || []).map((file, i) => (
            <div key={"n" + i} style={fileRow}>
              <LsIcon name="file-plus" size={13} style={{ color: "#6EE7B7", flexShrink: 0 }}/>
              <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: "var(--fg-secondary)" }}>{file.name} · {file.sizeLabel}</span>
              <span style={{ fontSize: 10, color: "var(--fg-muted)", flexShrink: 0 }}>буде завантажено</span>
              <button onClick={() => delStaged(i)} title="Прибрати" style={{ ...fileBtn, color: "#FCA5A5" }}><LsIcon name="x" size={12}/></button>
            </div>
          ))}
          <div onClick={() => fileRef.current && fileRef.current.click()} style={{
            border: "1px dashed " + (dragOver ? "rgba(34,211,238,.7)" : "var(--border-strong)"), borderRadius: 10, padding: "12px 14px",
            display: "flex", alignItems: "center", gap: 10, fontSize: 12.5, cursor: "pointer",
            color: dragOver ? "#67E8F9" : "var(--fg-muted)",
            background: dragOver ? "rgba(34,211,238,.08)" : "transparent",
          }}>
            <LsIcon name="paperclip" size={15}/>
            <span>{dragOver ? "Відпустіть, щоб додати файл(и)"
              : ((saved && saved.length) || (f._files && f._files.length) ? "Додати ще файл(и) — або перетягніть сюди" : "Оберіть чи перетягніть сюди файл(и) — PDF, фото…") + " · зберігаються ~3 дні"}</span>
          </div>
          {fileErr && <div style={{ fontSize: 11.5, color: "#FCA5A5" }}>{fileErr}</div>}
        </div>
      </LsField>

      <LsField label="Рахунок з бази (прикріпити без повторного завантаження)">
        <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
          {attachedInv.map(a => (
            <div key={a.invoiceId} style={fileRow}>
              <LsIcon name="receipt" size={13} style={{ color: "#22D3EE", flexShrink: 0 }}/>
              <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: "var(--fg-secondary)" }}>
                Рахунок №{a.number}{a.sellerName ? " · " + a.sellerName : ""}{a.total ? " · " + lsMoney(a.total) + " ₴" : ""}{a.orderId ? " · замовл. №" + a.orderId : ""}
              </span>
              <button onClick={() => openInvFile(a.invoiceId, "invoice")} title="Рахунок (PDF)" style={{ ...fileBtn, color: "var(--fg-secondary)" }}><LsIcon name="file-text" size={12}/></button>
              <button onClick={() => openInvFile(a.invoiceId, "vydatkova")} title="Видаткова (PDF)" style={{ ...fileBtn, color: "var(--fg-secondary)" }}><LsIcon name="file-check" size={12}/></button>
              <button onClick={() => detachInv(a.invoiceId)} title="Прибрати" style={{ ...fileBtn, color: "#FCA5A5" }}><LsIcon name="x" size={12}/></button>
            </div>
          ))}
          {!invOpen ? (
            <button onClick={openInvPicker} style={{ alignSelf: "flex-start", height: 30, padding: "0 12px", borderRadius: 8, border: "1px dashed var(--border-strong)", background: "transparent", color: "var(--fg-secondary)", fontFamily: "inherit", fontSize: 12, cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 6 }}>
              <LsIcon name="search" size={13}/> Знайти рахунок у базі
            </button>
          ) : (
            <div style={{ border: "1px solid var(--border-default)", borderRadius: 10, padding: 10, display: "flex", flexDirection: "column", gap: 8, background: "var(--bg-raised)" }}>
              <div style={{ display: "flex", gap: 6, alignItems: "center", flexWrap: "wrap" }}>
                <button onClick={() => setInvMode("order")} style={pill(invMode === "order")}>За № замовлення</button>
                <button onClick={() => setInvMode("no")} style={pill(invMode === "no")}>За № рахунку</button>
                <span style={{ flex: 1 }}/>
                <button onClick={() => { setInvOpen(false); setInvResults(null); }} title="Закрити" style={{ ...fileBtn, border: 0, color: "var(--fg-muted)" }}><LsIcon name="x" size={14}/></button>
              </div>
              <div style={{ display: "flex", gap: 6 }}>
                <LsInput value={invQ} onChange={setInvQ} placeholder={invMode === "order" ? "№ замовлення" : "№ рахунку"} mono/>
                <button onClick={doInvSearch} disabled={invBusy} style={{ height: 34, padding: "0 14px", borderRadius: 8, border: "1px solid rgba(34,211,238,.5)", background: "rgba(34,211,238,.13)", color: "#67E8F9", fontFamily: "inherit", fontSize: 12, fontWeight: 500, cursor: "pointer", flexShrink: 0 }}>{invBusy ? "Шукаю…" : "Знайти"}</button>
              </div>
              {invErr && <div style={{ fontSize: 11.5, color: "#FCA5A5" }}>{invErr}</div>}
              {invResults && invResults.length === 0 && <div style={{ fontSize: 12, color: "var(--fg-muted)" }}>Нічого не знайдено.</div>}
              {(invResults || []).map(inv => {
                const already = attachedInv.some(a => a.invoiceId === inv.id);
                const alive = (inv.files || []).some(x => x.alive);
                return (
                  <div key={inv.id} style={fileRow}>
                    <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                      №{inv.invoice_no} · {inv.seller_name} · {lsMoney(inv.total)} ₴{inv.order_id ? " · замовл. №" + inv.order_id : ""}{!alive ? " · файли прострочені" : ""}
                    </span>
                    <button onClick={() => attachInv(inv)} disabled={already} style={{ height: 26, padding: "0 10px", borderRadius: 7, border: "1px solid " + (already ? "var(--border-default)" : "rgba(34,211,238,.5)"), background: already ? "transparent" : "rgba(34,211,238,.13)", color: already ? "var(--fg-muted)" : "#67E8F9", fontFamily: "inherit", fontSize: 11.5, cursor: already ? "default" : "pointer", flexShrink: 0 }}>{already ? "Додано" : "Додати"}</button>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </LsField>

      <LsField label="Коментар (необов'язково)"><LsInput value={f.note || ""} onChange={set("note")} placeholder="Напр.: терміново, до обіду"/></LsField>
    </React.Fragment>
  );
}

// ── ТТН: власник створює накладну за даними, які вніс менеджер ──────────────
// Показується в модалі редагування docs-заявки (канал = Нова Пошта) і в модалі
// замовлення (через OrderTtnModal), лише owner.
// Флоу: «Перевірити дані» (превʼю — що піде в які поля НП, юрособу тягне за
// ЄДРПОУ з реєстру НП) → «Підтвердити і створити».
// props: leadId (заявка) АБО orderId (замовлення); descr — готовий опис відправлення;
// defaults — {cargoType, weight, cost, codAmount, codOn} префіл параметрів.
// Шаблони габаритів: обʼємна вага (Д×Ш×В/4000) → готові розміри. Вага не чіпається.
const LS_VOL_PRESETS = { 2: [20, 20, 20], 5: [25, 20, 40], 10: [40, 25, 40], 15: [50, 40, 30] };

// ── Пікер відправника: картки з живою статистикою (сьогодні + календарний місяць) ──
const LS_MONTHS_LOC = ["за січень", "за лютий", "за березень", "за квітень", "за травень", "за червень", "за липень", "за серпень", "за вересень", "за жовтень", "за листопад", "за грудень"];
function LsSenderPicker({ senders, value, onChange }) {
  const [open, setOpen] = React.useState(false);
  const fmtUah = (n) => Math.round(Number(n) || 0).toLocaleString("uk-UA");
  const monthLabel = LS_MONTHS_LOC[new Date().getMonth()];
  const cur = (senders || []).find(s => s.id === value) || null;
  const typeChip = (s) => (
    <span style={{ fontSize: 9.5, fontWeight: 600, padding: "1px 6px", borderRadius: 999, flexShrink: 0,
      border: "1px solid " + (s.type === "fiz" ? "rgba(96,165,250,.4)" : "rgba(110,231,183,.4)"),
      color: s.type === "fiz" ? "#93C5FD" : "#6EE7B7",
      background: s.type === "fiz" ? "rgba(96,165,250,.10)" : "rgba(110,231,183,.10)" }}>
      {s.type === "fiz" ? "Фізособа" : "ФОП"}
    </span>
  );
  const statsLine = (s) => (
    <span>
      Сьогодні: <b style={{ color: "var(--fg-secondary)" }}>{s.today ?? 0}{s.dailyLimit ? "/" + s.dailyLimit : ""} ЕН</b>
      {Number(s.todayCod) > 0 ? <> · <b style={{ color: "var(--fg-secondary)" }}>{fmtUah(s.todayCod)} ₴</b> накладених</> : null}
      <span style={{ margin: "0 6px", opacity: 0.5 }}>|</span>
      {monthLabel}: <b style={{ color: "var(--fg-secondary)" }}>{s.monthCount ?? 0} ЕН</b>
      {Number(s.monthCod) > 0 ? <> · <b style={{ color: "var(--fg-secondary)" }}>{fmtUah(s.monthCod)} ₴</b>{s.monthCodLimit ? " із " + fmtUah(s.monthCodLimit) : ""}</> : null}
      {s.monoIncome != null ? <> <span style={{ margin: "0 6px", opacity: 0.5 }}>|</span> Mono ФОП: <b style={{ color: s.monthCodLimit > 0 && s.monoIncome >= s.monthCodLimit ? "#FCA5A5" : "#6EE7B7" }} title="Надходження на ФОП-рахунок Monobank за місяць">{s.monoTruncated ? "≥" : ""}{fmtUah(s.monoIncome)} ₴</b></> : null}
    </span>
  );
  if (senders === null) return <div style={{ height: 44, display: "flex", alignItems: "center", padding: "0 12px", borderRadius: 10, border: "1px solid var(--border-default)", background: "var(--bg-raised)", fontSize: 12, color: "var(--fg-muted)" }}>Завантажую відправників…</div>;
  return (
    <div style={{ position: "relative" }}>
      <button onClick={() => setOpen(o => !o)} style={{
        width: "100%", minHeight: 44, padding: "7px 12px", borderRadius: 10, cursor: "pointer", textAlign: "left",
        border: "1px solid " + (open ? "rgba(110,231,183,.45)" : "var(--border-default)"),
        background: "var(--bg-raised)", fontFamily: "inherit", display: "flex", alignItems: "center", gap: 10,
      }}>
        {cur ? (
          <span style={{ flex: 1, minWidth: 0 }}>
            <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{cur.label}</span>
              {typeChip(cur)}
              {cur.recommended && <span title="Рекомендований (найменше навантаження)" style={{ color: "#FBBF24", fontSize: 12 }}>★</span>}
            </span>
            <span style={{ display: "block", fontSize: 10.5, color: "var(--fg-muted)", marginTop: 2 }}>{statsLine(cur)}</span>
          </span>
        ) : (
          <span style={{ flex: 1, fontSize: 12.5, color: "var(--fg-muted)" }}>Оберіть відправника…</span>
        )}
        <LsIcon name={open ? "chevron-up" : "chevron-down"} size={14} style={{ color: "var(--fg-muted)", flexShrink: 0 }}/>
      </button>
      {open && <>
        <div onClick={() => setOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 95 }}/>
        <div style={{ position: "absolute", top: "calc(100% + 5px)", left: 0, right: 0, zIndex: 96, maxHeight: 320, overflowY: "auto",
          background: "var(--bg-panel)", border: "1px solid var(--border-default)", borderRadius: 12, boxShadow: "0 18px 48px rgba(0,0,0,.5)" }}>
          {(senders || []).map(s => {
            const off = !s.hasKey || s.active === false;
            const overDay = s.dailyLimit > 0 && (s.today ?? 0) >= s.dailyLimit;
            return (
              <div key={s.id}
                   onClick={() => { if (off) return; onChange(s.id); setOpen(false); }}
                   style={{ padding: "9px 12px", cursor: off ? "not-allowed" : "pointer", opacity: off ? 0.45 : 1,
                            background: s.id === value ? "rgba(110,231,183,.07)" : "transparent",
                            borderBottom: "1px solid var(--border-subtle)" }}
                   onMouseEnter={e => { if (!off) e.currentTarget.style.background = "rgba(255,255,255,.04)"; }}
                   onMouseLeave={e => { e.currentTarget.style.background = s.id === value ? "rgba(110,231,183,.07)" : "transparent"; }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-primary)", flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{s.label}</span>
                  {typeChip(s)}
                  {s.recommended && !off && <span title="Рекомендований" style={{ color: "#FBBF24", fontSize: 12 }}>★</span>}
                  {off && <span style={{ fontSize: 10, color: "#FCA5A5", flexShrink: 0 }}>{!s.hasKey ? "немає ключа" : "вимкнений"}</span>}
                  {!off && overDay && <span style={{ fontSize: 10, color: "#FBBF24", flexShrink: 0 }}>ліміт дня</span>}
                </div>
                <div style={{ fontSize: 10.5, color: "var(--fg-muted)", marginTop: 3 }}>{statsLine(s)}</div>
              </div>
            );
          })}
        </div>
      </>}
    </div>
  );
}

function LsTtnPanel({ f, setF, leadId, orderId, descr, defaults, productsText, products }) {
  const [senders, setSenders] = React.useState(null);
  const [t, setT] = React.useState({
    senderId: "", senderCity: "Новоселиця", senderBranch: "1",
    cargoType: (defaults && defaults.cargoType) || "Documents",
    weight: (defaults && defaults.weight) || "0.5",
    // місця посилки: вага + габарити (см, необовʼязкові) на кожне; вага ЕН = сума.
    // defaults.volume — автопідбір шаблону за назвою товару (з OrderTtn)
    seatsArr: [(() => {
      const d = (defaults && LS_VOL_PRESETS[defaults.volume]) || null;
      return { weight: (defaults && defaults.weight) || "1", length: d ? String(d[0]) : "", width: d ? String(d[1]) : "", height: d ? String(d[2]) : "" };
    })()],
    cost: (defaults && defaults.cost) || "300",
    payerType: "Recipient", paymentMethod: "Cash",
    codMode: (defaults && defaults.codOn) ? "afterpayment" : "none",  // режим уточниться від типу відправника
    codAmount: (defaults && defaults.codAmount) || "",
  });
  const [busy, setBusy] = React.useState("");   // "" | "preview" | "create"
  const [err, setErr] = React.useState("");
  const [pv, setPv] = React.useState(null);     // відповідь превʼю
  const setTk = (k) => (v) => { setT(p => ({ ...p, [k]: v })); setPv(null); }; // зміна параметрів → превʼю застаріло
  React.useEffect(() => {
    lsApi.npSenders().then(list => {
      setSenders(list);
      // дефолт = рекомендований системою (найменше навантаження відносно лімітів)
      const rec = list.find(s => s.recommended && s.hasKey) || list.find(s => s.hasKey && s.active !== false);
      if (rec) setT(p => ({ ...p, senderId: p.senderId || rec.id }));
    }).catch(() => setSenders([]));
  }, []);
  const isUr = f.recipient === "ur";
  const isAddr = f.npDelivery === "address";
  // Обрали іншого відправника → підставляємо ЙОГО дефолтне відділення з конфігу
  // + режим післяплати від типу: ФОП = контроль оплати, фізособа = наложений платіж
  React.useEffect(() => {
    const s = (senders || []).find(x => x.id === t.senderId);
    if (!s) return;
    setT(p => ({
      ...p,
      ...(s.defaultCity ? { senderCity: s.defaultCity, senderBranch: s.defaultBranch || "1" } : {}),
      ...(p.codMode !== "none" ? { codMode: s.type === "fiz" ? "redelivery" : "afterpayment" } : {}),
    }));
  }, [t.senderId, senders]);
  // Поміняли дані отримувача у формі вище — превʼю більше не відповідає дійсності
  React.useEffect(() => { setPv(null); }, [f.npName, f.npPhone, f.npCity, f.npBranch, f.edrpou, f.recipient, f.npDelivery, f.npStreet, f.npHouse, f.npFlat]);
  const missing = !f.npName ? "ПІБ отримувача (контактна особа)" : !f.npPhone ? "телефон" : !f.npCity ? "місто"
    : (isAddr ? (!f.npStreet ? "вулицю" : !f.npHouse ? "будинок" : "") : (!f.npBranch ? "відділення" : ""))
    || ((isUr && !f.edrpou) ? "ЄДРПОУ (поле «Отримувач» вище)" : "");
  const body = () => ({
    requestId: leadId, orderId,
    senderId: t.senderId,
    sender: { city: t.senderCity, branch: t.senderBranch },
    recipient: {
      name: f.npName, phone: f.npPhone, city: f.npCity, branch: f.npBranch,
      type: f.recipient || "fiz", edrpou: f.edrpou,
      delivery: isAddr ? "address" : "branch", street: f.npStreet, house: f.npHouse, flat: f.npFlat,
    },
    products: products && products.length ? products : undefined,  // товари замовлення в ЦІЙ ЕН
    params: {
      cargoType: t.cargoType,
      weight: t.cargoType === "Parcel" ? String(seatsTotalW || t.weight) : t.weight,
      cost: t.cost,
      seatsList: t.cargoType === "Parcel" ? t.seatsArr : undefined,
      payerType: t.payerType, paymentMethod: t.paymentMethod,
      description: descr || ((f.docType || "Документи") + (f.orderId ? " (зам. №" + f.orderId + ")" : "")),
      productsText: productsText || "",
      cod: { mode: t.codMode, amount: Number(t.codAmount) || 0 },
    },
  });
  // Обʼємна вага НП = Д×Ш×В(см)/4000 на місце; НП тарифікує за більшою з фактичною
  const seatVolW = (s) => (Number(s.length) > 0 && Number(s.width) > 0 && Number(s.height) > 0)
    ? (Number(s.length) * Number(s.width) * Number(s.height)) / 4000 : 0;
  const seatsTotalW = t.seatsArr.reduce((a, s) => a + (Number(s.weight) || 0), 0);
  const setSeat = (i, k) => (v) => { setT(p => ({ ...p, seatsArr: p.seatsArr.map((s, j) => j === i ? { ...s, [k]: v } : s) })); setPv(null); };
  const addSeat = () => { setT(p => ({ ...p, seatsArr: [...p.seatsArr, { weight: "", length: "", width: "", height: "" }] })); setPv(null); };
  const delSeat = (i) => { setT(p => ({ ...p, seatsArr: p.seatsArr.filter((_, j) => j !== i) })); setPv(null); };
  // Дублювати ОСТАННЄ місце N разів (відправки на 20-30 однакових місць)
  const [dupN, setDupN] = React.useState("5");
  const dupSeat = () => {
    const n = Math.max(1, Math.min(99, parseInt(dupN, 10) || 1));
    setT(p => {
      const last = p.seatsArr[p.seatsArr.length - 1] || { weight: "", length: "", width: "", height: "" };
      return { ...p, seatsArr: [...p.seatsArr, ...Array.from({ length: n }, () => ({ ...last }))] };
    });
    setPv(null);
  };
  // Шаблон обʼєму → габарити ОСТАННЬОГО місця (вага лишається як є)
  const applyPreset = (vol) => {
    const d = LS_VOL_PRESETS[vol];
    if (!d) return;
    setT(p => ({ ...p, seatsArr: p.seatsArr.map((s, j) => j === p.seatsArr.length - 1
      ? { ...s, length: String(d[0]), width: String(d[1]), height: String(d[2]) } : s) }));
    setPv(null);
  };
  const preview = () => {
    if (busy) return;
    setErr(""); setPv(null); setBusy("preview");
    lsApi.npPreviewTtn(body())
      .then(r => { setBusy(""); setPv(r); })
      .catch(e => { setBusy(""); setErr(e.message || "Помилка"); });
  };
  const create = () => {
    if (busy) return;
    setErr(""); setBusy("create");
    lsApi.npCreateTtn(body()).then(r => {
      setBusy(""); setPv(null);
      // у локальну форму — щоб подальше «Зберегти» не загубило, і одразу видно номер
      setF(p => ({ ...p, ttn: r.number, ttnSender: r.senderLabel, ttnCost: r.cost, ttnEta: r.estimatedDelivery, ...(r.orgName ? { ttnOrg: r.orgName } : {}) }));
    }).catch(e => { setBusy(""); setErr(e.message || "Помилка"); });
  };
  const pill = (active) => ({
    height: 28, padding: "0 10px", borderRadius: 999, fontFamily: "inherit", fontSize: 11.5, fontWeight: 500, cursor: "pointer",
    whiteSpace: "nowrap", flexShrink: 0, // текст не вилазить за межі пілюлі при стисканні flex-рядка
    border: "1px solid " + (active ? "rgba(110,231,183,.5)" : "var(--border-default)"),
    background: active ? "rgba(110,231,183,.12)" : "var(--bg-raised)",
    color: active ? "#6EE7B7" : "var(--fg-secondary)",
  });
  // Вузький екран (телефон): одна колонка міст/відділення, компактний грид місць
  const narrow = typeof window !== "undefined" && window.innerWidth <= 768;
  // Превʼю: згортання + «запамʼятати» (localStorage) — досвідчений юзер ховає таблицю
  const [pvRemember, setPvRemember] = React.useState(() => { try { return localStorage.getItem("np_pv_collapsed") === "1"; } catch { return false; } });
  const [pvOpen, setPvOpen] = React.useState(!pvRemember);
  const toggleRemember = (v) => {
    setPvRemember(v); setPvOpen(!v);
    try { if (v) localStorage.setItem("np_pv_collapsed", "1"); else localStorage.removeItem("np_pv_collapsed"); } catch {}
  };
  return (
    // flexShrink:0 ОБОВʼЯЗКОВО: overflowX:hidden дає min-height:0 → у скрол-тілі модала
    // (flex-колонка) панель стискалась у смужку ~26px замість прокрутки
    <div style={{ border: "1px solid var(--border-default)", borderRadius: 10, padding: narrow ? 12 : 14, display: "flex", flexDirection: "column", gap: 12, background: "var(--bg-raised)", overflowX: "hidden", minWidth: 0, flexShrink: 0 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
        <span style={{ width: 24, height: 24, borderRadius: 6, display: "inline-flex", alignItems: "center", justifyContent: "center", background: "rgba(225,29,72,.14)", color: "#FB7185" }}><LsIcon name="truck" size={13}/></span>
        <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-primary)" }}>Експрес-накладна Нової Пошти</span>
      </div>

      {f.ttn && (
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 12px", borderRadius: 8, background: "rgba(110,231,183,.08)", border: "1px solid rgba(110,231,183,.3)", flexWrap: "wrap" }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 15, fontWeight: 700, color: "#6EE7B7" }}>{f.ttn}</span>
          <button type="button" onClick={() => copyText(f.ttn)} title="Скопіювати номер" style={{ height: 24, width: 24, display: "inline-flex", alignItems: "center", justifyContent: "center", background: "transparent", border: "1px solid rgba(110,231,183,.3)", borderRadius: 5, cursor: "pointer", color: "#6EE7B7", flexShrink: 0 }}>
            <LsIcon name="copy" size={12}/>
          </button>
          <span style={{ fontSize: 11, color: "var(--fg-muted)" }}>
            {f.ttnSender ? f.ttnSender + " · " : ""}{f.ttnCost ? "доставка " + f.ttnCost + " ₴ · " : ""}{f.ttnEta ? "орієнтовно " + f.ttnEta : ""}
          </span>
        </div>
      )}

      <LsField label="Відправник">
        <LsSenderPicker senders={senders} value={t.senderId} onChange={(id) => setTk("senderId")(id)}/>
      </LsField>
      <div style={{ display: "grid", gridTemplateColumns: narrow ? "1fr" : "1fr 1fr", gap: 12 }}>
        <LsField label="Місто відправки"><LsAutocomplete value={t.senderCity} onChange={setTk("senderCity")} placeholder="Новоселиця" fetcher={lsNpCities}/></LsField>
        <LsField label="Відділення (№ або назва)"><LsAutocomplete value={t.senderBranch} onChange={setTk("senderBranch")} placeholder="1" minChars={1} fetcher={(q) => lsNpWarehouses(t.senderCity, q)}/></LsField>
      </div>

      <div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
        <LsField label="Вантаж">
          <div style={{ display: "flex", gap: 5 }}>
            <button onClick={() => setTk("cargoType")("Documents")} style={pill(t.cargoType === "Documents")}>Документи</button>
            <button onClick={() => setTk("cargoType")("Parcel")} style={pill(t.cargoType === "Parcel")}>Посилка</button>
          </div>
        </LsField>
        {t.cargoType === "Documents" && (
          <LsField label="Вага, кг">
            <div style={{ display: "flex", gap: 5 }}>
              {["0.1", "0.5", "1"].map(w => <button key={w} onClick={() => setTk("weight")(w)} style={pill(t.weight === w)}>{w}</button>)}
            </div>
          </LsField>
        )}
        <LsField label="Оцінка, ₴"><div style={{ width: 90 }}><LsInput value={t.cost} onChange={setTk("cost")} placeholder="300" mono/></div></LsField>
      </div>
      {t.cargoType === "Parcel" && (
        <LsField label={"Місця (" + t.seatsArr.length + ") · вага ЕН = " + (seatsTotalW || 0).toFixed(2).replace(/\.00$/, "") + " кг"}>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {/* Шаблони обʼєму: підставляють габарити останнього місця, вага не змінюється */}
            <div style={{ display: "flex", gap: 6, alignItems: "center", flexWrap: "wrap" }}>
              <span style={{ fontSize: 10.5, color: "var(--fg-muted)" }}>Шаблон обʼєму:</span>
              {Object.keys(LS_VOL_PRESETS).map(v => {
                const d = LS_VOL_PRESETS[v];
                const last = t.seatsArr[t.seatsArr.length - 1] || {};
                const active = String(last.length) === String(d[0]) && String(last.width) === String(d[1]) && String(last.height) === String(d[2]);
                return <button key={v} onClick={() => applyPreset(Number(v))} title={d[0] + "×" + d[1] + "×" + d[2] + " см"} style={pill(active)}>{v} кг</button>;
              })}
            </div>
            {/* Вузький екран: 4 інпути тягнуться на 1fr, обʼємна вага — окремим рядком
                під місцем (інакше грид ~440px ширший за телефон і весь модал «їздив»). */}
            <div style={{ display: "grid", gridTemplateColumns: narrow ? "14px repeat(4, minmax(0, 1fr)) 24px" : "16px 76px 60px 60px 60px minmax(110px, 1fr) 24px", gap: 6, alignItems: "center" }}>
              <span/>
              <span style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: ".03em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Вага, кг</span>
              <span style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: ".03em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Довж.</span>
              <span style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: ".03em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Шир.</span>
              <span style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: ".03em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Вис.</span>
              {!narrow && <span/>}<span/>
              {t.seatsArr.map((s, i) => {
                const vw = seatVolW(s);
                const volLabel = (
                  <span style={{ fontSize: narrow ? 10.5 : 11, color: vw > (Number(s.weight) || 0) ? "#FBBF24" : "var(--fg-muted)", whiteSpace: narrow ? "normal" : "nowrap", ...(narrow ? { gridColumn: "2 / 6", marginTop: -2, marginBottom: 2 } : {}) }}>
                    {vw > 0 ? "обʼємна " + vw.toFixed(2) + " кг" + (vw > (Number(s.weight) || 0) ? " ←тариф" : "") : "без габаритів"}
                  </span>
                );
                return (
                  <React.Fragment key={i}>
                    <span style={{ fontSize: 11, color: "var(--fg-muted)" }}>{i + 1}.</span>
                    <LsInput value={s.weight} onChange={setSeat(i, "weight")} placeholder="—" mono/>
                    <LsInput value={s.length} onChange={setSeat(i, "length")} placeholder="—" mono/>
                    <LsInput value={s.width} onChange={setSeat(i, "width")} placeholder="—" mono/>
                    <LsInput value={s.height} onChange={setSeat(i, "height")} placeholder="—" mono/>
                    {!narrow && volLabel}
                    {t.seatsArr.length > 1
                      ? <button onClick={() => delSeat(i)} title="Прибрати місце" style={{ width: 22, height: 22, border: "1px solid var(--border-default)", borderRadius: 6, background: "transparent", color: "#FCA5A5", cursor: "pointer", fontSize: 12, lineHeight: 1 }}>×</button>
                      : <span/>}
                    {narrow && volLabel}
                  </React.Fragment>
                );
              })}
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
              <button onClick={addSeat} style={{ height: 26, padding: "0 10px", borderRadius: 999, border: "1px dashed var(--border-default)", background: "transparent", color: "var(--fg-secondary)", fontFamily: "inherit", fontSize: 11.5, cursor: "pointer" }}>+ Місце</button>
              <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}>
                <button onClick={dupSeat} title="Додати копії останнього місця" style={{ height: 26, padding: "0 10px", borderRadius: 999, border: "1px dashed var(--border-default)", background: "transparent", color: "var(--fg-secondary)", fontFamily: "inherit", fontSize: 11.5, cursor: "pointer" }}>⧉ Дублювати останнє ×</button>
                <input value={dupN} onChange={e => setDupN(e.target.value.replace(/\D/g, "").slice(0, 2))} inputMode="numeric" style={{ width: 38, height: 26, padding: "0 6px", borderRadius: 7, border: "1px solid var(--border-default)", background: "var(--bg-raised)", color: "var(--fg-primary)", fontFamily: "var(--font-mono)", fontSize: 12, textAlign: "center", outline: "none", boxSizing: "border-box" }}/>
              </span>
            </div>
          </div>
        </LsField>
      )}
      <div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
        <LsField label="Платник доставки">
          <div style={{ display: "flex", gap: 5 }}>
            <button onClick={() => setTk("payerType")("Recipient")} style={pill(t.payerType === "Recipient")}>Отримувач</button>
            <button onClick={() => setTk("payerType")("Sender")} style={pill(t.payerType === "Sender")}>Відправник</button>
          </div>
        </LsField>
        <LsField label="Оплата">
          <div style={{ display: "flex", gap: 5 }}>
            <button onClick={() => setTk("paymentMethod")("Cash")} style={pill(t.paymentMethod === "Cash")}>Готівка</button>
            <button onClick={() => setTk("paymentMethod")("NonCash")} style={pill(t.paymentMethod === "NonCash")}>Безготівка</button>
          </div>
        </LsField>
        <LsField label="Післяплата">
          <div style={{ display: "flex", gap: 5, alignItems: "center", flexWrap: "wrap" }}>
            <button onClick={() => setTk("codMode")("none")} style={pill(t.codMode === "none")}>Немає</button>
            <button onClick={() => setTk("codMode")("redelivery")} style={pill(t.codMode === "redelivery")}>Гроші назад</button>
            <button onClick={() => setTk("codMode")("afterpayment")} style={pill(t.codMode === "afterpayment")}>Контроль оплати</button>
            {t.codMode !== "none" && <div style={{ width: 90 }}><LsInput value={t.codAmount} onChange={setTk("codAmount")} placeholder="сума ₴" mono/></div>}
          </div>
        </LsField>
      </div>

      {/* Превʼю: що саме піде в які поля НП (props — точний payload InternetDocument/save) */}
      {pv && (() => {
        const P = pv.props || {};
        const row = (npField, label, value, hi) => (
          <div key={npField + label} style={{ display: "grid", gridTemplateColumns: "150px 1fr", gap: 8, padding: "4px 0", borderBottom: "1px solid var(--border-subtle)" }}>
            <span style={{ minWidth: 0 }}>
              <span style={{ display: "block", fontSize: 11.5, color: "var(--fg-secondary)" }}>{label}</span>
              <span style={{ display: "block", fontFamily: "var(--font-mono)", fontSize: 9.5, color: "var(--fg-muted)" }}>{npField}</span>
            </span>
            <span style={{ fontSize: 12, color: hi ? "#6EE7B7" : "var(--fg-primary)", fontWeight: hi ? 600 : 400, overflowWrap: "anywhere" }}>{value || "—"}</span>
          </div>
        );
        const payer = P.PayerType === "Sender" ? "Відправник" : P.PayerType === "Recipient" ? "Отримувач" : P.PayerType;
        return (
          <div style={{ border: "1px solid var(--border-default)", borderRadius: 8, padding: "8px 12px", background: "var(--bg-panel)", minWidth: 0 }}>
            <div onClick={() => setPvOpen(o => !o)} style={{ display: "flex", alignItems: "center", gap: 8, margin: "4px 0 6px", cursor: "pointer" }}>
              <span style={{ fontSize: 11, fontWeight: 600, letterSpacing: "0.04em", textTransform: "uppercase", color: "var(--fg-muted)" }}>Перевірте — це піде в Нову Пошту</span>
              {!pvOpen && <span style={{ fontSize: 10.5, color: "#6EE7B7" }}>дані сформовані</span>}
              <span style={{ flex: 1 }}/>
              <LsIcon name={pvOpen ? "chevron-up" : "chevron-down"} size={14} style={{ color: "var(--fg-muted)" }}/>
            </div>
            {pvOpen && <React.Fragment>
            {row("Sender / ContactSender", "Відправник (контрагент НП)", pv.senderCounterparty)}
            {row("SendersPhone", "Телефон відправника", pv.senderContactPhone)}
            {row("CitySender / SenderAddress", "Звідки", pv.senderWarehouse)}
            {isUr
              ? row("Recipient (Organization)", "Отримувач — юр.особа за ЄДРПОУ " + (pv.orgEdrpou || f.edrpou), pv.orgName ? pv.orgName : "не знайдено", true)
              : row("Recipient (PrivatePerson)", "Отримувач — фіз.особа", f.npName, true)}
            {row("ContactRecipient", "Контактна особа отримувача", f.npName + (isUr ? " (буде додана до компанії)" : ""))}
            {row("RecipientsPhone", "Телефон отримувача", P.RecipientsPhone)}
            {row("CityRecipient / RecipientAddress", "Куди", pv.recipientWarehouse + (pv.postomat ? " · ПОШТОМАТ (габарити дод. автоматично)" : ""))}
            {pv.streetMatched && row("StreetRef → Address/save", "Вулиця у базі НП (точний збіг)", pv.streetMatched, true)}
            {row("CargoType / Weight / SeatsAmount", "Вантаж", (P.CargoType === "Documents" ? "Документи" : "Посилка") + " · " + P.Weight + " кг · " + P.SeatsAmount + " місце")}
            {P.OptionsSeat && P.OptionsSeat[0] && P.OptionsSeat[0].volumetricLength &&
              row("OptionsSeat", "Місця (Д×Ш×В, см)", P.OptionsSeat.map((s, i) =>
                (P.OptionsSeat.length > 1 ? (i + 1) + ") " : "") + s.volumetricLength + "×" + s.volumetricWidth + "×" + s.volumetricHeight +
                " · " + s.weight + " кг · обʼємна " + ((Number(s.volumetricLength) * Number(s.volumetricWidth) * Number(s.volumetricHeight)) / 4000).toFixed(2) + " кг"
              ).join("  ·  "))}
            {row("Cost", "Оціночна вартість", P.Cost + " ₴")}
            {P.AfterpaymentOnGoodsCost && row("AfterpaymentOnGoodsCost", "Післяплата — контроль оплати", P.AfterpaymentOnGoodsCost + " ₴", true)}
            {P.BackwardDeliveryData && row("BackwardDeliveryData (Money)", "Післяплата — зворотна доставка грошей", (P.BackwardDeliveryData[0] && P.BackwardDeliveryData[0].RedeliveryString) + " ₴", true)}
            {row("PayerType / PaymentMethod", "Доставку платить", payer + " · " + (P.PaymentMethod === "Cash" ? "готівка" : "безготівка"))}
            {row("Description", "Опис відправлення", P.Description)}
            {P.AdditionalInformation && row("AdditionalInformation", "Додаткова інформація", P.AdditionalInformation)}
            {row("DateTime / ServiceType", "Дата відправки · технологія", P.DateTime + " · " + (P.ServiceType === "WarehouseDoors" ? "відділення→двері (адресна)" : "відділення→відділення"))}
            </React.Fragment>}
            <label style={{ display: "flex", alignItems: "center", gap: 7, padding: "7px 0 3px", fontSize: 11, color: "var(--fg-muted)", cursor: "pointer" }}>
              <input type="checkbox" checked={pvRemember} onChange={e => toggleRemember(e.target.checked)} style={{ accentColor: "var(--accent)", width: 14, height: 14 }}/>
              Згортати превʼю автоматично (запамʼятати — перевіряю сам)
            </label>
          </div>
        );
      })()}

      <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
        <span onClick={() => !missing && t.senderId && preview()} style={{ display: "inline-flex" }}>
          <LsButton variant="secondary" icon="list-checks" style={{ height: 34, opacity: (missing || !t.senderId || busy) ? 0.5 : 1 }}>
            {busy === "preview" ? "Перевіряю…" : pv ? "Перевірити ще раз" : "Перевірити дані"}
          </LsButton>
        </span>
        {pv && (
          <span onClick={() => create()} style={{ display: "inline-flex" }}>
            <LsButton variant="primary" icon="truck" style={{ height: 34, opacity: busy ? 0.5 : 1 }}>
              {busy === "create" ? "Створюю…" : f.ttn ? "Підтвердити (ще одна ТТН)" : "Підтвердити і створити ТТН"}
            </LsButton>
          </span>
        )}
        {missing && <span style={{ fontSize: 11.5, color: "#FBBF24" }}>Заповніть вище: {missing}</span>}
        {err && <span style={{ fontSize: 11.5, color: "#FCA5A5" }}>{err}</span>}
      </div>
      <div style={{ fontSize: 10.5, color: "var(--fg-muted)" }}>
        {isUr ? "Отримувач — юр.особа: компанію НП тягне зі свого реєстру за ЄДРПОУ з форми вище; ПІБ — контактна особа." : "Отримувач — з полів «Нова Пошта» вище."} Накладна зʼявиться в кабінеті обраного ФОПа.
      </div>
    </div>
  );
}

function LsAddDocModal({ onClose, onAdd }) {
  const [f, setF] = lsUseState({ docType: LS_DOC_TYPES[0], recipient: "fiz", channel: "email" });
  const set = (k) => (v) => setF(p => ({ ...p, [k]: v }));
  const save = () => { onAdd(f); onClose(); };
  // Телефон: на весь екран (плаваюче віконце було нечитабельне)
  const narrow = typeof window !== "undefined" && window.innerWidth <= 768;
  return (
    <div style={{
      position: "absolute", inset: 0, background: "rgba(0,0,0,0.6)", zIndex: 50,
      display: "flex", alignItems: "center", justifyContent: "center",
    }}>
      <div style={narrow ? {
        width: "100%", height: "100%", maxHeight: "100%", background: "var(--bg-panel)", borderRadius: 0,
        display: "flex", flexDirection: "column",
      } : {
        width: "min(600px, 96vw)", maxHeight: "92%", background: "var(--bg-panel)", borderRadius: 12, border: "1px solid var(--border-default)",
        boxShadow: "0 8px 24px rgba(0,0,0,.5), 0 24px 64px rgba(0,0,0,.4)", display: "flex", flexDirection: "column",
      }}>
        <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--border-subtle)", display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
          <span style={{
            width: 30, height: 30, borderRadius: 8, display: "inline-flex", alignItems: "center", justifyContent: "center",
            background: "rgba(34,211,238,.13)", color: "#22D3EE",
          }}><LsIcon name="file-plus" size={15}/></span>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 15, fontWeight: 600, color: "var(--fg-primary)" }}>Документ на відправку</div>
            <div style={{ fontSize: 11.5, color: "var(--fg-muted)" }}>Керівник надішле клієнту вказаним каналом</div>
          </div>
          <button onClick={onClose} style={{ width: 28, height: 28, border: 0, background: "transparent", color: "var(--fg-muted)", borderRadius: 6, cursor: "pointer" }}>
            <LsIcon name="x" size={16}/>
          </button>
        </div>
        <div style={{ padding: "18px 20px", overflowY: "auto", display: "flex", flexDirection: "column", gap: 14 }}>
          <LsDocFields f={f} set={set} setF={setF}/>
        </div>
        <div style={{ padding: narrow ? "14px 16px calc(14px + env(safe-area-inset-bottom, 0px))" : "14px 20px", borderTop: "1px solid var(--border-subtle)", display: "flex", justifyContent: "flex-end", gap: 8, flexShrink: 0 }}>
          <LsButton variant="secondary" style={{ height: 34 }} onClick={onClose}>Скасувати</LsButton>
          <span onClick={save} style={{ display: "inline-flex" }}><LsButton variant="primary" icon="check" style={{ height: 34 }}>Додати в чергу</LsButton></span>
        </div>
      </div>
    </div>
  );
}

// ── Питання менеджерів — інбокс керівника ──────────────────────────────────
function LsMgrInbox({ leads, onAnswer, onStatus, onEdit }) {
  const [openId, setOpenId] = lsUseState(leads.find(l => l.status === "open")?.id ?? null);
  const [draft, setDraft] = lsUseState("");
  const canned = ["Погоджую", "Ні, тримаємо стандартні умови", "Зателефоную тобі через 10 хв"];
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      {leads.map(l => {
        const open = openId === l.id;
        const answered = l.status === "answered";
        return (
          <div key={l.id} onClick={() => { setOpenId(open ? null : l.id); setDraft(""); }} className={open ? "" : "ls-row"} style={{
            padding: "14px 18px 14px 15px", borderBottom: "1px solid var(--border-subtle)", cursor: "pointer",
            background: open ? "var(--bg-active)" : "transparent",
            borderLeft: "3px solid " + (open ? "#EC4899" : "transparent"),
          }}>
            <div style={{ display: "flex", alignItems: "flex-start", gap: 12 }}>
              <LsAvatar name={l.manager} size={28}/>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
                  <span style={{ fontSize: 12, fontWeight: 600, color: "var(--fg-secondary)" }}>{l.manager}</span>
                  {l.orderId && (
                    <span style={{ display: "inline-flex", alignItems: "center", gap: 4, height: 18, padding: "0 7px", borderRadius: 999, background: "var(--accent-soft)", color: "var(--accent)", fontSize: 10.5, fontWeight: 600, fontFamily: "var(--font-mono)" }}>
                      <LsIcon name="package" size={10}/>№{l.orderId}
                    </span>
                  )}
                  <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--fg-muted)" }}>#{l.id}</span>
                </div>
                <div style={{ fontSize: 14.5, fontWeight: 500, color: "var(--fg-primary)", lineHeight: 1.4 }}>{l.question}</div>
                {answered && l.reply && (
                  <div style={{ display: "flex", alignItems: "center", gap: 7, marginTop: 7, fontSize: 12, color: "#6EE7B7" }}>
                    <LsIcon name="corner-down-right" size={12}/>
                    <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{l.reply}</span>
                    <span style={{ color: "var(--fg-muted)" }}>— {l.replyBy}</span>
                  </div>
                )}
              </div>
              <div onClick={e => e.stopPropagation()} style={{ display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
                <LsAge min={l.ageMin} done={answered}/>
                <LsStatusSelect map={LS_MGRQ_STATUSES} value={l.status} onChange={s => onStatus && onStatus(l.id, s)}/>
                <button onClick={() => onEdit && onEdit(l)} title="Редагувати" style={{ width: 26, height: 26, border: "1px solid var(--border-default)", background: "var(--bg-raised)", color: "var(--fg-muted)", borderRadius: 6, cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center" }}>
                  <LsIcon name="pencil" size={13}/>
                </button>
              </div>
            </div>
            {open && !answered && (
              <div onClick={e => e.stopPropagation()} style={{ marginTop: 12, marginLeft: 40, display: "flex", flexDirection: "column", gap: 8 }}>
                <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                  {canned.map((c, i) => (
                    <button key={i} onClick={() => setDraft(c)} style={{
                      height: 26, padding: "0 10px", borderRadius: 999, border: "1px solid var(--border-default)",
                      background: "var(--bg-raised)", color: "var(--fg-secondary)", fontFamily: "inherit",
                      fontSize: 11.5, cursor: "pointer",
                    }}>{c}</button>
                  ))}
                </div>
                <div style={{ display: "flex", gap: 8 }}>
                  <input value={draft} onChange={e => setDraft(e.target.value)} placeholder="Відповісти менеджеру…" style={{
                    flex: 1, height: 34, padding: "0 12px", borderRadius: 8, border: "1px solid var(--border-default)",
                    background: "var(--bg-raised)", color: "var(--fg-primary)", fontFamily: "inherit", fontSize: 12.5, outline: "none",
                  }}/>
                  <span onClick={() => draft.trim() && onAnswer(l.id, draft.trim())} style={{ display: "inline-flex" }}>
                    <LsButton variant="primary" icon="send" style={{ height: 34, opacity: draft.trim() ? 1 : 0.5 }}>Відповісти</LsButton>
                  </span>
                </div>
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

Object.assign(window, { LsDocsTable, LsAddDocModal, LsMgrInbox, LsChannel, LsField, LsInput, LsDocFields, LsAutocomplete, LsTtnPanel, LsClientContact, LsLeadFiles });
