"use client";

import React, { useEffect, useMemo, useRef, useState } from "react";
import toast from "react-hot-toast";
import { API_BASE_URL, fetchApi } from "@/lib/api/http";
import * as api from "@/lib/api/checklist-templates.api";

interface Props {
  standards: { id: number; name: string }[];
  onChanged?: () => void;
}

type UserOpt = { id: number; name: string; email: string };

const ALLOWED_FILE = /\.(pdf|docx?|xlsx?)$/i;

/* ---------- helpers ---------- */

const stripExt = (n: string) => n.replace(/\.[^.]+$/, "");
const plural = (n: number, one: string) => `${n} ${n === 1 ? one : one + "s"}`;

const initials = (s: string) => {
  const base = s.includes("@") ? s.split("@")[0] : s;
  const parts = base.split(/[\s._-]+/).filter(Boolean);
  return ((parts[0]?.[0] ?? "?") + (parts[1]?.[0] ?? "")).toUpperCase();
};

const fullName = (u: any): string => {
  const fl = [u.first_name ?? u.firstName, u.last_name ?? u.lastName].filter(Boolean).join(" ").trim();
  const raw = (u.name || fl || "").trim();
  if (raw) return raw;
  return u.email ? String(u.email).split("@")[0] : `User ${u.id}`;
};

const TINTS = ["#ede9fe", "#e0f2fe", "#fef3c7", "#dcfce7", "#fce7f3", "#e2e8f0"];
const INKS = ["#5b21b6", "#0369a1", "#92400e", "#166534", "#9d174d", "#334155"];
const tintOf = (id: number) => id % TINTS.length;

const fileKind = (name: string) => {
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
  if (ext === "pdf") return { label: "PDF", bg: "#fee2e2", ink: "#b91c1c" };
  if (ext === "doc" || ext === "docx") return { label: "DOC", bg: "#dbeafe", ink: "#1d4ed8" };
  if (ext === "xls" || ext === "xlsx") return { label: "XLS", bg: "#dcfce7", ink: "#15803d" };
  return { label: ext.toUpperCase().slice(0, 3) || "FILE", bg: "#f1f5f9", ink: "#475569" };
};

/* ---------- icons ---------- */

const svg = (d: React.ReactNode, size = 16) => (
  <svg width={size} height={size} viewBox="0 0 20 20" fill="none" aria-hidden="true">{d}</svg>
);

const I = {
  plus: svg(<path d="M10 4v12M4 10h12" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />),
  trash: svg(<path d="M4 6h12M8 6V4.5A1.5 1.5 0 0 1 9.5 3h1A1.5 1.5 0 0 1 12 4.5V6m2 0-.6 9.2a1.5 1.5 0 0 1-1.5 1.4H8.1a1.5 1.5 0 0 1-1.5-1.4L6 6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />),
  pencil: svg(<path d="M12.5 4.5l3 3L7 16H4v-3l8.5-8.5z" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />),
  download: svg(<path d="M10 3v9m0 0-3.5-3.5M10 12l3.5-3.5M4 16h12" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />),
  upload: svg(<path d="M10 14V5m0 0L6.5 8.5M10 5l3.5 3.5M4 15h12" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" />, 22),
  chevron: svg(<path d="m5 8 5 5 5-5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" />),
  search: svg(<><circle cx="9" cy="9" r="5.5" stroke="currentColor" strokeWidth="1.6" /><path d="m13.5 13.5 3 3" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" /></>),
  check: svg(<path d="m4.5 10.5 3.5 3.5 7.5-8" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />, 12),
  x: svg(<path d="m5 5 10 10M15 5 5 15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />, 12),
  xLg: svg(<path d="m5 5 10 10M15 5 5 15" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />, 16),
  info: svg(<><circle cx="10" cy="10" r="7.5" stroke="currentColor" strokeWidth="1.5" /><path d="M10 9v4.5M10 6.6v.1" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" /></>, 18),
  lock: svg(<><rect x="4.5" y="9" width="11" height="8" rx="2" stroke="currentColor" strokeWidth="1.5" /><path d="M7 9V6.5a3 3 0 0 1 6 0V9" stroke="currentColor" strokeWidth="1.5" /></>, 13),
  link: svg(<path d="M8.5 11.5l3-3M7 13H5.5a3 3 0 0 1 0-6H7M13 7h1.5a3 3 0 0 1 0 6H13" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />),
  list: svg(<path d="M7 5h10M7 10h10M7 15h10M4 5h.01M4 10h.01M4 15h.01" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />),
  file: svg(<path d="M6 3h5l4 4v10H6zM11 3v4h4" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />),
  layers: svg(<path d="M10 3l7 4-7 4-7-4 7-4zM3 11l7 4 7-4" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />),
  users: svg(<path d="M7 9a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5zm-4.5 7c.4-2.4 2.2-4 4.5-4s4.1 1.6 4.5 4M13 8a2 2 0 1 0 0-4M14.5 16c-.2-1.6-1-2.9-2.2-3.6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />),
};

/* ---------- component ---------- */

export default function ChecklistLibrary({ standards, onChanged }: Props) {
  const [data, setData] = useState<api.MineResponse>({ is_admin: false, checklists: [] });
  const [sel, setSel] = useState<number | null>(null);
  const [busy, setBusy] = useState(false);
  const [loaded, setLoaded] = useState(false);

  // create dialog
  const [showNew, setShowNew] = useState(false);
  const [newName, setNewName] = useState("");
  const [newStd, setNewStd] = useState<number[]>([]);
  const [newFirst, setNewFirst] = useState("");
  const [newFile, setNewFile] = useState<File | null>(null);
  const [newManual, setNewManual] = useState(false);
  const [newDrag, setNewDrag] = useState(false);
  const newFileRef = useRef<HTMLInputElement>(null);

  // items
  const [newItem, setNewItem] = useState("");
  const [editingId, setEditingId] = useState<number | null>(null);
  const [editText, setEditText] = useState("");
  const skipBlur = useRef(false);

  // rename checklist
  const [renaming, setRenaming] = useState(false);
  const [renameText, setRenameText] = useState("");

  // standards of an existing checklist
  const [editingStd, setEditingStd] = useState(false);
  const [stdDraft, setStdDraft] = useState<number[]>([]);

  // upload to an existing checklist
  const [dragging, setDragging] = useState(false);
  const fileRef = useRef<HTMLInputElement>(null);

  // access (admins)
  const [users, setUsers] = useState<UserOpt[]>([]);
  const [shareDraft, setShareDraft] = useState<number[]>([]);
  const [shareOpen, setShareOpen] = useState(false);
  const [userQuery, setUserQuery] = useState("");
  const shareRef = useRef<HTMLDivElement>(null);

  const load = async () => {
    try {
      const r = await api.listMine();
      setData(r);
      setSel((s) => (s && r.checklists.some((c) => c.id === s) ? s : r.checklists[0]?.id ?? null));
    } catch (e: any) {
      toast.error(e.message || "Could not load your checklists");
    } finally {
      setLoaded(true);
    }
  };

  useEffect(() => { load(); }, []);

  // ASSUMPTION: GET /users returns { id, name | email }.
  useEffect(() => {
    if (!data.is_admin) return;
    fetchApi<any[]>(`${API_BASE_URL}/users`)
      .then((rows) => setUsers(rows.map((u) => ({ id: u.id, name: fullName(u), email: u.email || "" }))))
      .catch(() => setUsers([]));
  }, [data.is_admin]);

  const cur = data.checklists.find((c) => c.id === sel) ?? null;

  // reset transient UI when switching checklist
  useEffect(() => {
    setEditingId(null);
    setRenaming(false);
    setEditingStd(false);
    setNewItem("");
  }, [sel]);

  useEffect(() => {
    setShareDraft(cur?.shared_user_ids ?? []);
    setShareOpen(false);
    setUserQuery("");
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sel, data]);

  // close the user picker on outside click / Escape
  useEffect(() => {
    if (!shareOpen) return;
    const down = (e: MouseEvent) => {
      if (shareRef.current && !shareRef.current.contains(e.target as Node)) setShareOpen(false);
    };
    const key = (e: KeyboardEvent) => e.key === "Escape" && setShareOpen(false);
    document.addEventListener("mousedown", down);
    document.addEventListener("keydown", key);
    return () => {
      document.removeEventListener("mousedown", down);
      document.removeEventListener("keydown", key);
    };
  }, [shareOpen]);

  const stdName = (id: number) => standards.find((s) => s.id === id)?.name ?? `#${id}`;

  const run = async (fn: () => Promise<unknown>, ok?: string) => {
    setBusy(true);
    try {
      await fn();
      if (ok) toast.success(ok);
      await load();
      onChanged?.();
    } catch (e: any) {
      toast.error(e.message || "Something went wrong");
    } finally {
      setBusy(false);
    }
  };

  /* ---- create dialog ---- */

  const closeNew = () => {
    setShowNew(false);
    setNewName("");
    setNewStd([]);
    setNewFirst("");
    setNewFile(null);
    setNewManual(false);
    setNewDrag(false);
  };

  const pickNewFile = (f?: File) => {
    if (!f) return;
    if (!ALLOWED_FILE.test(f.name)) { toast.error("Use a PDF, Word or Excel file."); return; }
    setNewFile(f);
    setNewManual(false);
    if (!newName.trim()) setNewName(stripExt(f.name)); // pre-fill name from the file
  };

  const toggleNewStd = (id: number) =>
    setNewStd((d) => (d.includes(id) ? d.filter((x) => x !== id) : [...d, id]));

  const createList = () =>
    run(async () => {
      const name = newName.trim();
      const first = newFirst.trim();
      if (!name) throw new Error("Enter a checklist name.");
      if (newStd.length === 0) throw new Error("Choose at least one standard.");
      if (!newFile && !first) throw new Error("Upload a file or add a first item.");

      const t = await api.createTemplate({
        name,
        is_generic: false,
        standard_ids: newStd,
        items: first ? [{ item_text: first, sort_order: 1 }] : [],
        allow_empty_items: !!newFile,
      });

      const file = newFile;
      closeNew();
      setSel(t.id);

      if (file) {
        try {
          const r = await api.uploadTemplateFile(t.id, file);
          toast.success(
            r.supported ? `Added ${r.items_added} item(s) from ${file.name}` : "File saved. Add items by hand.",
          );
        } catch (e: any) {
          toast.error(`Checklist created, but the file could not be uploaded: ${e.message || "upload failed"}`);
        }
      }
    }, "Checklist created");

  /* ---- items ---- */

  const addItem = () => {
    const v = newItem.trim();
    if (!cur || !v) return;
    run(async () => {
      await api.addItem(cur.id, v);
      setNewItem("");
    }, "Item added");
  };

  const startEdit = (it: api.MineItem) => {
    setEditingId(it.id);
    setEditText(it.item_text);
  };

  const cancelEdit = () => {
    skipBlur.current = true;
    setEditingId(null);
  };

  const saveEdit = (it: api.MineItem) => {
    const v = editText.trim();
    setEditingId(null);
    if (!v) { toast.error("Item text cannot be empty."); return; }
    if (v === it.item_text) return;
    run(() => api.updateItem(it.id, { item_text: v }), "Item updated");
  };

  const removeItem = (id: number) => {
    if (!window.confirm("Remove this item from the checklist?")) return;
    run(() => api.deleteItem(id), "Item removed");
  };

  /* ---- checklist actions ---- */

  const removeList = () => {
    if (!cur || !window.confirm(`Delete checklist "${cur.name}"?`)) return;
    setSel(null);
    run(() => api.removeTemplate(cur.id), "Checklist deleted");
  };
  

  const saveRename = () => {
    if (!cur) return;
    const v = renameText.trim();
    setRenaming(false);
    if (!v || v === cur.name) return;
    run(() => api.renameTemplate(cur.id, v), "Name updated");
  };

  const toggleShareable = () => {
    if (!cur) return;
    const next = !cur.is_shareable;
    run(
      () => api.setShareable(cur.id, next),
      next ? "Reusable: this checklist now appears on the Checklist tab of your audits (any client)" : "Reuse turned off: hidden from the Checklist tab",
    );
  };

  const startEditStd = () => {
    if (!cur) return;
    setStdDraft(cur.standard_ids ?? []);
    setEditingStd(true);
  };

  const toggleStdDraft = (id: number) =>
    setStdDraft((d) => (d.includes(id) ? d.filter((x) => x !== id) : [...d, id]));

  const saveStandards = () => {
    if (!cur) return;
    if (stdDraft.length === 0) { toast.error("Choose at least one standard."); return; }
    setEditingStd(false);
    run(() => api.setStandards(cur.id, stdDraft), "Standards updated");
  };

  const uploadFile = async (file?: File) => {
    if (!cur || !file) return;
    if (!ALLOWED_FILE.test(file.name)) { toast.error("Use a PDF, Word or Excel file."); return; }
    setBusy(true);
    try {
      const r = await api.uploadTemplateFile(cur.id, file);
      toast.success(
        r.supported
          ? `Added ${r.items_added} item(s) from ${file.name}${r.items_skipped ? `, ${r.items_skipped} already listed` : ""}`
          : "File saved. Add items by hand.",
      );
      await load();
      onChanged?.();
    } catch (e: any) {
      toast.error(e.message || "Upload failed");
    } finally {
      setBusy(false);
    }
  };

  /* ---- access (admins) ---- */

  const toggleShare = (uid: number) =>
    setShareDraft((d) => (d.includes(uid) ? d.filter((x) => x !== uid) : [...d, uid]));

  const filteredUsers = useMemo(() => {
    const q = userQuery.trim().toLowerCase();
    return q ? users.filter((u) => (u.name + " " + u.email).toLowerCase().includes(q)) : users;
  }, [users, userQuery]);

  const selectedUsers = useMemo(() => users.filter((u) => shareDraft.includes(u.id)), [users, shareDraft]);

  const savedShares = cur?.shared_user_ids ?? [];
  const dirty =
    shareDraft.length !== savedShares.length || shareDraft.some((id) => !savedShares.includes(id));

  const allFilteredSelected =
    filteredUsers.length > 0 && filteredUsers.every((u) => shareDraft.includes(u.id));

  const toggleAllFiltered = () => {
    const ids = filteredUsers.map((u) => u.id);
    setShareDraft((d) =>
      allFilteredSelected ? d.filter((x) => !ids.includes(x)) : Array.from(new Set([...d, ...ids])),
    );
  };

  /* ---- render ---- */

  return (
    <div className="cl">
      <style>{CSS}</style>

      <header className="cl-head">
        <div>
          <h2 className="cl-title">Checklist library</h2>
          <p className="cl-sub">
            Your checklists for audits. Mark one as reusable to select it on other audits.
          </p>
        </div>
        <button className="cl-btn cl-btn-primary" onClick={() => setShowNew(true)} disabled={busy}>
          {I.plus} New checklist
        </button>
      </header>

      <div className="cl-layout">
        {/* ---------- left: list ---------- */}
        <aside className="cl-side" aria-label="Checklists">
          <div className="cl-side-label">{plural(data.checklists.length, "checklist")}</div>

          {!loaded && <div className="cl-skel" />}

          {loaded && data.checklists.length === 0 && (
            <div className="cl-empty-side">
              <p>No checklists yet.</p>
              <button className="cl-link" onClick={() => setShowNew(true)}>Create your first checklist</button>
            </div>
          )}

          <ul className="cl-list">
            {data.checklists.map((c) => (
              <li key={c.id}>
                <button
                  className={"cl-list-item" + (c.id === sel ? " is-active" : "")}
                  onClick={() => setSel(c.id)}
                >
                  <span className="cl-list-top">
                    <span className="cl-list-name">{c.name}</span>
                    {c.is_shareable && <span className="cl-badge cl-badge-reuse">Reusable</span>}
                  </span>
                  <span className="cl-list-meta">
                    {plural(c.items.length, "item")}
                    {" · "}
                    {(c.standard_ids || []).map((id) => stdName(id)).join(", ") || "No standard"}
                    {!c.can_edit && <span className="cl-tag"> {I.lock} Shared with you</span>}
                  </span>
                </button>
              </li>
            ))}
          </ul>
        </aside>

        {/* ---------- right: detail ---------- */}
        <section className="cl-main">
          {!cur ? (
            <div className="cl-empty-main">
              <button className="cl-empty-plus" onClick={() => setShowNew(true)} aria-label="Create a checklist">
                {I.plus}
              </button>
              <h3>Create a checklist</h3>
              <p>Click + to upload a Word or Excel file, then choose the standard.</p>
            </div>
          ) : (
            <>
              {/* hero */}
              <div className="cl-hero">
                <div className="cl-hero-main">
                  {renaming ? (
                    <div className="cl-rename">
                      <input
                        className="cl-input"
                        autoFocus
                        value={renameText}
                        onChange={(e) => setRenameText(e.target.value)}
                        onKeyDown={(e) => {
                          if (e.key === "Enter") saveRename();
                          if (e.key === "Escape") setRenaming(false);
                        }}
                      />
                      <button className="cl-icon-btn" onClick={saveRename} aria-label="Save name">{I.check}</button>
                      <button className="cl-icon-btn" onClick={() => setRenaming(false)} aria-label="Cancel">{I.xLg}</button>
                    </div>
                  ) : (
                    <h3 className="cl-hero-title">
                      {cur.name}
                      {cur.can_edit && (
                        <button
                          className="cl-icon-btn"
                          onClick={() => { setRenameText(cur.name); setRenaming(true); }}
                          aria-label="Rename checklist"
                          title="Rename"
                        >
                          {I.pencil}
                        </button>
                      )}
                    </h3>
                  )}

                  {/* standards */}
                  {editingStd ? (
                    <div className="cl-std-edit">
                      <div className="cl-std">
                        {standards.map((s) => {
                          const on = stdDraft.includes(s.id);
                          return (
                            <button
                              type="button"
                              key={s.id}
                              className={"cl-std-chip" + (on ? " is-on" : "")}
                              onClick={() => toggleStdDraft(s.id)}
                            >
                              {on && I.check} {s.name}
                            </button>
                          );
                        })}
                      </div>
                      <div className="cl-std-actions">
                        <button className="cl-btn cl-btn-ghost cl-btn-sm" onClick={() => setEditingStd(false)}>Cancel</button>
                        <button className="cl-btn cl-btn-primary cl-btn-sm" onClick={saveStandards} disabled={busy}>Save standards</button>
                      </div>
                    </div>
                  ) : (
                    <div className="cl-chips">
                      {(cur.standard_ids || []).length === 0 && <span className="cl-chip">No standard</span>}
                      {(cur.standard_ids || []).map((id) => (
                        <span className="cl-chip cl-chip-std" key={id}>{stdName(id)}</span>
                      ))}
                      {!cur.can_edit && <span className="cl-chip cl-chip-warn">View only</span>}
                      {cur.can_edit && (
                        <button className="cl-chip-edit" onClick={startEditStd} disabled={busy}>
                          {I.pencil} Change standard
                        </button>
                      )}
                    </div>
                  )}
                </div>

                {cur.can_edit && (
                  <div className="cl-hero-actions">
                    <div className="cl-toggle">
                      <button
                        type="button"
                        role="switch"
                        aria-checked={!!cur.is_shareable}
                        aria-label="Reusable on other audits"
                        className={"cl-switch" + (cur.is_shareable ? " is-on" : "")}
                        onClick={toggleShareable}
                        disabled={busy}
                      >
                        <span className="cl-switch-knob" />
                      </button>
                      <div className="cl-toggle-text">
                        <strong>Reusable</strong>
                        <span>{cur.is_shareable ? "Shown on the Checklist tab — you can use it for any client" : "Turn on to use it on the Checklist tab for another client"}</span>
                      </div>
                    </div>
                    <button className="cl-btn cl-btn-danger" onClick={removeList} disabled={busy}>
                      {I.trash} Delete
                    </button>
                  </div>
                )}
              </div>

              {/* stats */}
              <div className="cl-stats">
                <div className="cl-stat">
                  <span className="cl-stat-icon">{I.list}</span>
                  <div><strong>{cur.items.length}</strong><span>Items</span></div>
                </div>
                <div className="cl-stat">
                  <span className="cl-stat-icon">{I.file}</span>
                  <div><strong>{cur.files.length}</strong><span>Files</span></div>
                </div>
                <div className="cl-stat">
                  <span className="cl-stat-icon">{I.layers}</span>
                  <div><strong>{(cur.standard_ids || []).length}</strong><span>Standards</span></div>
                </div>
              </div>

              {/* items */}
              <div className="cl-card">
                <div className="cl-card-head">
                  <h4>Checklist items</h4>
                  <span className="cl-count">{cur.items.length}</span>
                </div>

                {cur.items.length === 0 ? (
                  <div className="cl-placeholder">No items yet. Upload a file below or add an item.</div>
                ) : (
                  <ol className="cl-grid">
                    {cur.items.map((it, i) => {
                      const editing = editingId === it.id;
                      return (
                        <li className={"cl-tile" + (editing ? " is-editing" : "")} key={it.id}>
                          <span className="cl-tile-n">{i + 1}</span>

                          {editing ? (
                            <input
                              className="cl-tile-input"
                              autoFocus
                              value={editText}
                              onChange={(e) => setEditText(e.target.value)}
                              onKeyDown={(e) => {
                                if (e.key === "Enter") (e.target as HTMLInputElement).blur();
                                if (e.key === "Escape") { (e.target as HTMLInputElement).blur(); cancelEdit(); }
                              }}
                              onBlur={() => {
                                if (skipBlur.current) { skipBlur.current = false; return; }
                                saveEdit(it);
                              }}
                            />
                          ) : (
                            <span className="cl-tile-text" title={it.item_text}>{it.item_text}</span>
                          )}

                          {cur.can_edit && !editing && (
                            <div className="cl-tile-actions">
                              <button
                                className="cl-icon-btn"
                                title="Edit"
                                aria-label={`Edit item ${i + 1}`}
                                onClick={() => startEdit(it)}
                                disabled={busy}
                              >
                                {I.pencil}
                              </button>
                              <button
                                className="cl-icon-btn cl-icon-danger"
                                title="Delete"
                                aria-label={`Delete item ${i + 1}`}
                                onClick={() => removeItem(it.id)}
                                disabled={busy}
                              >
                                {I.trash}
                              </button>
                            </div>
                          )}
                        </li>
                      );
                    })}
                  </ol>
                )}

                {cur.can_edit && (
                  <div className="cl-add">
                    <input
                      className="cl-input"
                      placeholder="Add an item and press Enter"
                      value={newItem}
                      onChange={(e) => setNewItem(e.target.value)}
                      onKeyDown={(e) => e.key === "Enter" && addItem()}
                      disabled={busy}
                    />
                    <button className="cl-btn cl-btn-primary" onClick={addItem} disabled={busy || !newItem.trim()}>
                      {I.plus} Add
                    </button>
                  </div>
                )}
              </div>

              {/* files */}
              <div className="cl-card">
                <div className="cl-card-head">
                  <h4>Files</h4>
                  <span className="cl-count">{cur.files.length}</span>
                </div>

                {cur.can_edit && (
                  <div
                    className={"cl-drop" + (dragging ? " is-drag" : "") + (busy ? " is-busy" : "")}
                    onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
                    onDragLeave={() => setDragging(false)}
                    onDrop={(e) => {
                      e.preventDefault();
                      setDragging(false);
                      uploadFile(e.dataTransfer.files?.[0]);
                    }}
                    onClick={() => !busy && fileRef.current?.click()}
                    role="button"
                    tabIndex={0}
                    onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && fileRef.current?.click()}
                  >
                    <div className="cl-drop-icon">{I.upload}</div>
                    <div className="cl-drop-text">
                      <strong>{busy ? "Uploading…" : "Add items from a file"}</strong>
                      <span>Word and Excel items are added automatically. PDFs are kept as reference.</span>
                    </div>
                    <span className="cl-btn cl-btn-ghost cl-btn-sm">Choose file</span>
                    <input
                      ref={fileRef}
                      type="file"
                      hidden
                      accept=".pdf,.doc,.docx,.xls,.xlsx"
                      disabled={busy}
                      onChange={(e) => {
                        const f = e.target.files?.[0];
                        e.target.value = "";
                        uploadFile(f);
                      }}
                    />
                  </div>
                )}

                {cur.files.length > 0 && (
                  <ul className="cl-files">
                    {cur.files.map((f) => {
                      const k = fileKind(f.original_name);
                      return (
                        <li className="cl-file" key={f.id}>
                          <span className="cl-file-badge" style={{ background: k.bg, color: k.ink }}>{k.label}</span>
                          <span className="cl-file-name" title={f.original_name}>{f.original_name}</span>
                          <button
                            className="cl-icon-btn"
                            title="Download"
                            aria-label={`Download ${f.original_name}`}
                            onClick={() => api.downloadTemplateFile(f.id, f.original_name).catch((e) => toast.error(e.message))}
                          >
                            {I.download}
                          </button>
                          {cur.can_edit && (
                            <button
                              className="cl-icon-btn cl-icon-danger"
                              title="Remove file"
                              aria-label={`Remove ${f.original_name}`}
                              disabled={busy}
                              onClick={() => run(() => api.deleteTemplateFile(f.id), "File removed")}
                            >
                              {I.trash}
                            </button>
                          )}
                        </li>
                      );
                    })}
                  </ul>
                )}
              </div>

              {/* access (admins only) */}
              {data.is_admin && (
                <div className="cl-card">
                  <div className="cl-card-head">
                    <h4>{I.users} Auditor access</h4>
                    <span className="cl-count">{shareDraft.length}</span>
                  </div>
                  <p className="cl-hint">Auditors selected here can view this checklist.</p>

                  <div className="cl-select" ref={shareRef}>
                    <button
                      type="button"
                      className={"cl-select-trigger" + (shareOpen ? " is-open" : "")}
                      onClick={() => setShareOpen((v) => !v)}
                      aria-haspopup="listbox"
                      aria-expanded={shareOpen}
                    >
                      <span className="cl-select-value">
                        {selectedUsers.length === 0 ? (
                          <span className="cl-select-ph">Select auditors…</span>
                        ) : (
                          <>
                            {selectedUsers.slice(0, 3).map((u) => (
                              <span className="cl-pill" key={u.id} title={u.email}>
                                {u.name}
                                <span
                                  role="button"
                                  aria-label={`Remove ${u.name}`}
                                  className="cl-pill-x"
                                  onClick={(e) => { e.stopPropagation(); toggleShare(u.id); }}
                                >
                                  {I.x}
                                </span>
                              </span>
                            ))}
                            {selectedUsers.length > 3 && (
                              <span className="cl-more">+{selectedUsers.length - 3} more</span>
                            )}
                          </>
                        )}
                      </span>
                      <span className={"cl-caret" + (shareOpen ? " is-open" : "")}>{I.chevron}</span>
                    </button>

                    {shareOpen && (
                      <div className="cl-pop" role="listbox" aria-multiselectable="true">
                        <div className="cl-pop-search">
                          {I.search}
                          <input
                            autoFocus
                            placeholder="Search by name or email"
                            value={userQuery}
                            onChange={(e) => setUserQuery(e.target.value)}
                          />
                        </div>
                        <div className="cl-pop-bar">
                          <button className="cl-link" onClick={toggleAllFiltered} disabled={filteredUsers.length === 0}>
                            {allFilteredSelected ? "Clear shown" : "Select all shown"}
                          </button>
                          <span>{shareDraft.length} selected</span>
                        </div>
                        <ul className="cl-pop-list">
                          {filteredUsers.length === 0 && (
                            <li className="cl-pop-empty">No users match &quot;{userQuery}&quot;.</li>
                          )}
                          {filteredUsers.map((u) => {
                            const on = shareDraft.includes(u.id);
                            return (
                              <li key={u.id}>
                                <button
                                  type="button"
                                  role="option"
                                  aria-selected={on}
                                  className={"cl-opt" + (on ? " is-on" : "")}
                                  onClick={() => toggleShare(u.id)}
                                >
                                  <span className={"cl-check" + (on ? " is-on" : "")}>{on && I.check}</span>
                                  <span
                                    className="cl-avatar"
                                    style={{ background: TINTS[tintOf(u.id)], color: INKS[tintOf(u.id)] }}
                                  >
                                    {initials(u.name)}
                                  </span>
                                  <span className="cl-opt-text">
                                    <span className="cl-opt-name">{u.name}</span>
                                    {u.email && <span className="cl-opt-email">{u.email}</span>}
                                  </span>
                                </button>
                              </li>
                            );
                          })}
                        </ul>
                      </div>
                    )}
                  </div>

                  <div className="cl-save-row">
                    <span className="cl-dirty">{dirty ? "You have unsaved changes" : ""}</span>
                    <button
                      className="cl-btn cl-btn-primary"
                      disabled={busy || !dirty}
                      onClick={() => run(() => api.setShares(cur.id, shareDraft), "Access updated")}
                    >
                      Save access
                    </button>
                  </div>
                </div>
              )}
            </>
          )}
        </section>
      </div>

      {/* ---------- create dialog ---------- */}
      {showNew && (
        <div className="cl-overlay" onMouseDown={(e) => e.target === e.currentTarget && closeNew()}>
          <div className="cl-dialog" role="dialog" aria-modal="true" aria-label="New checklist">
            <div className="cl-dialog-head">
              <h3>New checklist</h3>
              <button className="cl-icon-btn" onClick={closeNew} aria-label="Close">{I.xLg}</button>
            </div>

            {/* step 1: source */}
            <div className="cl-field">
              <span>Upload a file</span>
              {newFile ? (
                <div className="cl-picked">
                  {(() => {
                    const k = fileKind(newFile.name);
                    return <span className="cl-file-badge" style={{ background: k.bg, color: k.ink }}>{k.label}</span>;
                  })()}
                  <span className="cl-file-name" title={newFile.name}>{newFile.name}</span>
                  <button
                    className="cl-icon-btn"
                    aria-label="Remove file"
                    onClick={() => setNewFile(null)}
                  >
                    {I.x}
                  </button>
                </div>
              ) : (
                <div
                  className={"cl-drop cl-drop-sm" + (newDrag ? " is-drag" : "")}
                  role="button"
                  tabIndex={0}
                  onClick={() => newFileRef.current?.click()}
                  onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && newFileRef.current?.click()}
                  onDragOver={(e) => { e.preventDefault(); setNewDrag(true); }}
                  onDragLeave={() => setNewDrag(false)}
                  onDrop={(e) => { e.preventDefault(); setNewDrag(false); pickNewFile(e.dataTransfer.files?.[0]); }}
                >
                  <div className="cl-drop-icon">{I.plus}</div>
                  <div className="cl-drop-text">
                    <strong>Drop a file, or browse</strong>
                    <span>Word or Excel items are added automatically. PDFs are kept as reference.</span>
                  </div>
                </div>
              )}
              <input
                ref={newFileRef}
                type="file"
                hidden
                accept=".pdf,.doc,.docx,.xls,.xlsx"
                onChange={(e) => {
                  const f = e.target.files?.[0];
                  e.target.value = "";
                  pickNewFile(f);
                }}
              />
              {!newFile && !newManual && (
                <button type="button" className="cl-link cl-link-left" onClick={() => setNewManual(true)}>
                  Or add items by hand instead
                </button>
              )}
            </div>

            {/* step 2: details, shown once a source is chosen */}
            {(newFile || newManual) && (
              <>
                <label className="cl-field">
                  <span>Name</span>
                  <input
                    className="cl-input"
                    autoFocus={!newFile}
                    placeholder="e.g. Production records"
                    value={newName}
                    onChange={(e) => setNewName(e.target.value)}
                  />
                </label>

                <div className="cl-field">
                  <span>Standard</span>
                  <div className="cl-std">
                    {standards.map((s) => {
                      const on = newStd.includes(s.id);
                      return (
                        <button
                          type="button"
                          key={s.id}
                          className={"cl-std-chip" + (on ? " is-on" : "")}
                          onClick={() => toggleNewStd(s.id)}
                        >
                          {on && I.check} {s.name}
                        </button>
                      );
                    })}
                  </div>
                </div>

                {newManual && (
                  <label className="cl-field">
                    <span>First item</span>
                    <input
                      className="cl-input"
                      placeholder="e.g. Quality manual is available"
                      value={newFirst}
                      onChange={(e) => setNewFirst(e.target.value)}
                      onKeyDown={(e) => e.key === "Enter" && createList()}
                    />
                  </label>
                )}
              </>
            )}

            <div className="cl-dialog-foot">
              <button className="cl-btn cl-btn-ghost" onClick={closeNew}>Cancel</button>
              {(newFile || newManual) && (
                <button
                  className="cl-btn cl-btn-primary"
                  onClick={createList}
                  disabled={
                    busy ||
                    !newName.trim() ||
                    newStd.length === 0 ||
                    (!newFile && !newFirst.trim())
                  }
                >
                  Create checklist
                </button>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ---------- styles (scoped by .cl) ---------- */

const CSS = `
.cl{
  --ink:#111827; --ink-2:#374151; --ink-3:#6b7280;
  --line:#e5e7eb; --line-2:#f1f2f4; --bg:#fff; --bg-soft:#f9fafb;
  --brand:#5b21b6; --brand-2:#4c1d95; --brand-soft:#f5f3ff; --brand-line:#ddd6fe;
  --ok:#047857; --ok-soft:#ecfdf5; --ok-line:#a7f3d0;
  --danger:#b42318; --danger-soft:#fef3f2; --danger-line:#fecdca;
  --warn-soft:#fffbeb; --warn-line:#fde68a; --warn-ink:#92400e;
  color:var(--ink); font-size:14px; line-height:1.45;
  background:var(--bg); border:1px solid var(--line); border-radius:16px;
  padding:24px; margin-bottom:18px;
  box-shadow:0 1px 2px rgba(16,24,40,.04);
}
.cl *{box-sizing:border-box}
.cl button{font-family:inherit}
.cl :focus-visible{outline:2px solid var(--brand); outline-offset:2px}

/* header */
.cl-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:20px}
.cl-title{margin:0;font-size:20px;font-weight:700;letter-spacing:-.01em}
.cl-sub{margin:4px 0 0;color:var(--ink-3);font-size:13px;max-width:560px}

/* buttons */
.cl-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:38px;padding:0 14px;border-radius:10px;border:1px solid transparent;font-size:13px;font-weight:600;cursor:pointer;transition:background .15s,border-color .15s,color .15s,opacity .15s;white-space:nowrap}
.cl-btn:disabled{opacity:.45;cursor:not-allowed}
.cl-btn-sm{height:32px;padding:0 12px;font-size:12.5px}
.cl-btn-primary{background:var(--brand);color:#fff}
.cl-btn-primary:hover:not(:disabled){background:var(--brand-2)}
.cl-btn-ghost{background:#fff;color:var(--ink);border-color:var(--line)}
.cl-btn-ghost:hover:not(:disabled){background:var(--bg-soft)}
.cl-btn-danger{background:#fff;color:var(--danger);border-color:var(--danger-line)}
.cl-btn-danger:hover:not(:disabled){background:var(--danger-soft)}
.cl-link{background:none;border:0;padding:0;color:var(--brand);font-weight:600;font-size:12.5px;cursor:pointer}
.cl-link:hover{text-decoration:underline}
.cl-link-left{text-align:left}

/* layout */
.cl-layout{display:grid;grid-template-columns:272px minmax(0,1fr);gap:24px;align-items:start}

/* sidebar */
.cl-side{border-right:1px solid var(--line-2);padding-right:20px;min-height:320px}
.cl-side-label{font-size:12px;font-weight:600;color:var(--ink-3);text-transform:uppercase;letter-spacing:.04em;margin-bottom:10px}
.cl-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.cl-list-item{width:100%;text-align:left;background:transparent;border:1px solid transparent;border-radius:12px;padding:10px 12px;cursor:pointer;display:flex;flex-direction:column;gap:4px;transition:background .15s,border-color .15s}
.cl-list-item:hover{background:var(--bg-soft)}
.cl-list-item.is-active{background:var(--brand-soft);border-color:var(--brand-line)}
.cl-list-top{display:flex;align-items:center;justify-content:space-between;gap:8px}
.cl-list-name{font-weight:600;font-size:13.5px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-list-item.is-active .cl-list-name{color:var(--brand-2)}
.cl-list-meta{font-size:12px;color:var(--ink-3);display:flex;align-items:center;flex-wrap:wrap;gap:2px}
.cl-tag{display:inline-flex;align-items:center;gap:3px;margin-left:6px}
.cl-badge{font-size:10.5px;font-weight:700;padding:2px 7px;border-radius:99px;white-space:nowrap}
.cl-badge-reuse{background:var(--ok-soft);color:var(--ok);border:1px solid var(--ok-line)}
.cl-empty-side{padding:16px 4px;color:var(--ink-3);font-size:13px}
.cl-empty-side p{margin:0 0 6px}
.cl-skel{height:56px;border-radius:12px;background:linear-gradient(90deg,#f3f4f6,#fafafa,#f3f4f6);background-size:200% 100%;animation:cl-sh 1.2s linear infinite}
@keyframes cl-sh{to{background-position:-200% 0}}

/* main */
.cl-main{min-width:0;padding-bottom:48px}

/* hero */
.cl-hero{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;padding-bottom:18px;border-bottom:1px solid var(--line-2)}
.cl-hero-main{min-width:0;flex:1}
.cl-hero-title{margin:0 0 10px;font-size:18px;font-weight:700;letter-spacing:-.01em;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.cl-rename{display:flex;align-items:center;gap:6px;margin-bottom:10px;max-width:420px}
.cl-rename .cl-input{flex:1}
.cl-hero-actions{display:flex;align-items:center;gap:14px;flex:none}

.cl-chips{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.cl-chip{font-size:12px;font-weight:500;padding:3px 10px;border-radius:99px;background:var(--bg-soft);border:1px solid var(--line);color:var(--ink-2)}
.cl-chip-std{background:var(--brand-soft);border-color:var(--brand-line);color:var(--brand-2)}
.cl-chip-warn{background:var(--warn-soft);border-color:var(--warn-line);color:var(--warn-ink)}
.cl-chip-edit{display:inline-flex;align-items:center;gap:5px;background:none;border:0;padding:3px 6px;color:var(--brand);font-size:12px;font-weight:600;cursor:pointer;border-radius:8px}
.cl-chip-edit:hover{background:var(--brand-soft)}
.cl-std-edit{display:flex;flex-direction:column;gap:10px;max-width:560px}
.cl-std-actions{display:flex;justify-content:flex-end;gap:8px}

/* reusable toggle */
.cl-toggle{display:flex;align-items:center;gap:10px}
.cl-toggle-text{display:flex;flex-direction:column;line-height:1.2}
.cl-toggle-text strong{font-size:13px;font-weight:600}
.cl-toggle-text span{font-size:11.5px;color:var(--ink-3)}
.cl-switch{position:relative;width:40px;height:22px;border-radius:99px;border:0;background:#d1d5db;cursor:pointer;padding:0;transition:background .18s;flex:none}
.cl-switch.is-on{background:var(--ok)}
.cl-switch:disabled{opacity:.5;cursor:not-allowed}
.cl-switch-knob{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.2);transition:transform .18s}
.cl-switch.is-on .cl-switch-knob{transform:translateX(18px)}

/* stats */
.cl-stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:18px 0}
.cl-stat{display:flex;align-items:center;gap:12px;padding:12px 14px;border:1px solid var(--line);border-radius:12px;background:var(--bg-soft)}
.cl-stat-icon{width:34px;height:34px;border-radius:10px;background:#fff;border:1px solid var(--line);color:var(--brand);display:flex;align-items:center;justify-content:center;flex:none}
.cl-stat > div{display:flex;flex-direction:column;line-height:1.15}
.cl-stat strong{font-size:17px;font-weight:700}
.cl-stat span{font-size:12px;color:var(--ink-3)}

/* cards */
.cl-card{border:1px solid var(--line);border-radius:14px;padding:18px;margin-bottom:16px;background:#fff}
.cl-card-head{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.cl-card-head h4{margin:0;font-size:14px;font-weight:700;display:flex;align-items:center;gap:6px}
.cl-count{min-width:22px;height:20px;padding:0 7px;border-radius:99px;background:var(--bg-soft);border:1px solid var(--line);font-size:11.5px;font-weight:600;color:var(--ink-2);display:inline-flex;align-items:center;justify-content:center}
.cl-hint{margin:-6px 0 12px;color:var(--ink-3);font-size:12.5px}
.cl-placeholder{padding:16px;border:1px dashed var(--line);border-radius:12px;color:var(--ink-3);font-size:13px;text-align:center;margin-bottom:12px}

/* items grid: two columns side by side */
.cl-grid{list-style:none;margin:0 0 12px;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.cl-tile{display:flex;align-items:center;gap:10px;padding:8px 8px 8px 12px;border:1px solid var(--line);border-radius:10px;background:#fff;min-width:0;transition:border-color .15s,box-shadow .15s}
.cl-tile:hover{border-color:var(--brand-line);box-shadow:0 1px 4px rgba(91,33,182,.08)}
.cl-tile.is-editing{border-color:var(--brand);box-shadow:0 0 0 3px rgba(91,33,182,.12)}
.cl-tile-n{width:22px;height:22px;border-radius:7px;background:var(--bg-soft);border:1px solid var(--line);font-size:11px;font-weight:600;color:var(--ink-3);display:flex;align-items:center;justify-content:center;flex:none;font-variant-numeric:tabular-nums}
.cl-tile-text{flex:1;min-width:0;font-size:13.5px;color:var(--ink);word-break:break-word;line-height:1.35}
.cl-tile-input{flex:1;min-width:0;height:32px;border:0;outline:0;background:transparent;font-size:13.5px;color:var(--ink);font-family:inherit;padding:0}
.cl-tile-actions{display:flex;gap:2px;flex:none;opacity:.55;transition:opacity .15s}
.cl-tile:hover .cl-tile-actions,.cl-tile:focus-within .cl-tile-actions{opacity:1}

/* inputs */
.cl-input{width:100%;height:38px;padding:0 12px;border:1px solid var(--line);border-radius:10px;font-size:13.5px;color:var(--ink);background:#fff;font-family:inherit;transition:border-color .15s,box-shadow .15s}
.cl-input::placeholder{color:#9ca3af}
.cl-input:focus{outline:0;border-color:var(--brand);box-shadow:0 0 0 3px rgba(91,33,182,.12)}
.cl-add{display:flex;gap:8px}

/* icon buttons */
.cl-icon-btn{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border-radius:8px;border:0;background:transparent;color:var(--ink-3);cursor:pointer;transition:background .15s,color .15s;flex:none}
.cl-icon-btn:hover:not(:disabled){background:var(--line-2);color:var(--ink)}
.cl-icon-btn:disabled{opacity:.4;cursor:not-allowed}
.cl-icon-danger:hover:not(:disabled){background:var(--danger-soft);color:var(--danger)}

/* upload */
.cl-drop{display:flex;align-items:center;gap:14px;padding:18px 18px;border:1.5px dashed var(--brand-line);border-radius:12px;background:var(--bg-soft);cursor:pointer;transition:background .15s,border-color .15s;margin-bottom:12px}
.cl-drop:hover,.cl-drop.is-drag{background:var(--brand-soft);border-color:var(--brand)}
.cl-drop.is-busy{opacity:.6;cursor:progress}
.cl-drop-sm{padding:14px 16px;gap:12px;margin-bottom:0}
.cl-drop-icon{width:44px;height:44px;border-radius:12px;background:#fff;border:1px solid var(--brand-line);color:var(--brand);display:flex;align-items:center;justify-content:center;flex:none}
.cl-drop-sm .cl-drop-icon{width:40px;height:40px}
.cl-drop-text{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.cl-drop-text strong{font-size:13.5px;font-weight:600}
.cl-drop-text span{font-size:12.5px;color:var(--ink-3)}

.cl-files{list-style:none;margin:0;padding:0;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.cl-file{display:flex;align-items:center;gap:12px;padding:10px 10px 10px 14px}
.cl-file + .cl-file{border-top:1px solid var(--line-2)}
.cl-file-badge{width:38px;height:38px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:10.5px;font-weight:800;letter-spacing:.03em;flex:none}
.cl-file-name{flex:1;min-width:0;font-size:13.5px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* access picker */
.cl-select{position:relative}
.cl-select-trigger{width:100%;min-height:44px;display:flex;align-items:center;gap:8px;padding:6px 10px 6px 12px;background:#fff;border:1px solid var(--line);border-radius:10px;cursor:pointer;text-align:left;transition:border-color .15s,box-shadow .15s}
.cl-select-trigger:hover{border-color:var(--brand-line)}
.cl-select-trigger.is-open{border-color:var(--brand);box-shadow:0 0 0 3px rgba(91,33,182,.12)}
.cl-select-value{flex:1;min-width:0;display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.cl-select-ph{color:#9ca3af;font-size:13.5px}
.cl-pill{display:inline-flex;align-items:center;gap:4px;max-width:220px;padding:3px 4px 3px 9px;border-radius:7px;background:var(--brand-soft);border:1px solid var(--brand-line);color:var(--brand-2);font-size:12.5px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-pill-x{display:inline-flex;width:18px;height:18px;align-items:center;justify-content:center;border-radius:5px;cursor:pointer;flex:none}
.cl-pill-x:hover{background:var(--brand-line)}
.cl-more{font-size:12.5px;color:var(--ink-2);font-weight:600;padding:0 4px}
.cl-caret{display:flex;color:var(--ink-3);transition:transform .15s;flex:none}
.cl-caret.is-open{transform:rotate(180deg)}
.cl-pop{position:absolute;z-index:30;left:0;right:0;top:calc(100% + 6px);background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:0 12px 32px -8px rgba(17,24,39,.22);overflow:hidden}
.cl-pop-search{display:flex;align-items:center;gap:8px;padding:0 12px;height:44px;border-bottom:1px solid var(--line-2);color:var(--ink-3)}
.cl-pop-search input{flex:1;border:0;outline:0;background:transparent;font-size:13.5px;color:var(--ink);font-family:inherit;height:100%}
.cl-pop-bar{display:flex;justify-content:space-between;align-items:center;padding:8px 14px;font-size:12px;color:var(--ink-3);background:var(--bg-soft);border-bottom:1px solid var(--line-2)}
.cl-pop-list{list-style:none;margin:0;padding:4px;max-height:300px;overflow-y:auto}
.cl-pop-empty{padding:18px;text-align:center;color:var(--ink-3);font-size:13px}
.cl-opt{width:100%;display:flex;align-items:center;gap:12px;padding:8px 10px;border:0;background:transparent;border-radius:8px;cursor:pointer;text-align:left;font-size:13.5px;color:var(--ink)}
.cl-opt:hover{background:var(--bg-soft)}
.cl-opt.is-on{background:var(--brand-soft)}
.cl-opt-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.cl-opt-name{font-size:13.5px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-opt-email{font-size:12px;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cl-check{width:18px;height:18px;border-radius:5px;border:1.5px solid #c4c7d0;background:#fff;display:flex;align-items:center;justify-content:center;color:#fff;flex:none;transition:background .12s,border-color .12s}
.cl-check.is-on{background:var(--brand);border-color:var(--brand)}
.cl-avatar{width:34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex:none}
.cl-save-row{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:14px}
.cl-dirty{font-size:12.5px;color:var(--warn-ink)}

/* empty main */
.cl-empty-main{display:flex;flex-direction:column;align-items:center;text-align:center;padding:72px 20px;color:var(--ink-3)}
.cl-empty-main h3{margin:14px 0 4px;color:var(--ink);font-size:15px}
.cl-empty-main p{margin:0;font-size:13px}
.cl-empty-plus{width:60px;height:60px;border-radius:16px;border:1.5px dashed var(--brand);background:var(--brand-soft);color:var(--brand);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .15s}
.cl-empty-plus:hover{background:var(--brand-line)}

/* create dialog */
.cl-overlay{position:fixed;inset:0;z-index:100;background:rgba(17,24,39,.45);display:flex;align-items:center;justify-content:center;padding:20px}
.cl-dialog{width:100%;max-width:520px;max-height:calc(100vh - 40px);overflow-y:auto;background:#fff;border-radius:16px;padding:22px;box-shadow:0 24px 60px -12px rgba(17,24,39,.4)}
.cl-dialog-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}
.cl-dialog-head h3{margin:0;font-size:17px}
.cl-field{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
.cl-field > span{font-size:12.5px;font-weight:600;color:var(--ink-2)}
.cl-std{display:flex;flex-wrap:wrap;gap:6px}
.cl-std-chip{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:99px;border:1px solid var(--line);background:#fff;color:var(--ink-2);font-size:12.5px;font-weight:500;cursor:pointer;transition:all .12s}
.cl-std-chip:hover{border-color:var(--brand-line)}
.cl-std-chip.is-on{background:var(--brand-soft);border-color:var(--brand);color:var(--brand-2);font-weight:600}
.cl-picked{display:flex;align-items:center;gap:12px;padding:10px 8px 10px 12px;border:1px solid var(--brand-line);background:var(--brand-soft);border-radius:12px}
.cl-dialog-foot{display:flex;justify-content:flex-end;gap:8px;margin-top:20px}

/* responsive */
@media (max-width:1024px){
  .cl-layout{grid-template-columns:1fr}
  .cl-side{border-right:0;border-bottom:1px solid var(--line-2);padding:0 0 16px;min-height:0}
  .cl-list{flex-direction:row;overflow-x:auto;padding-bottom:4px}
  .cl-list-item{min-width:220px}
}
@media (max-width:720px){
  .cl{padding:16px}
  .cl-grid{grid-template-columns:1fr}
  .cl-stats{grid-template-columns:1fr}
  .cl-hero{flex-direction:column}
  .cl-hero-actions{width:100%;justify-content:space-between}
  .cl-head{flex-direction:column}
}
@media (prefers-reduced-motion:reduce){
  .cl *{transition:none!important;animation:none!important}
}
`;